diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/Configure.help linux.18p8/Documentation/Configure.help
--- linux.vanilla/Documentation/Configure.help	Sat Sep  9 18:42:32 2000
+++ linux.18p8/Documentation/Configure.help	Mon Sep 11 18:06:33 2000
@@ -624,6 +624,11 @@
   say M here and read Documentation/modules.txt. The module will be
   called ps2esdi.o.
 
+ALI M15X3 chipset support (EXPERIMENTAL)
+CONFIG_BLK_DEV_ALI15X3
+  This driver ensures (U)DMA support for ALI 1543 and 1543C,
+  1535, 1535D onboard chipsets.
+
 Tekram TRM290 chipset support (EXPERIMENTAL)
 CONFIG_BLK_DEV_TRM290
   This driver adds support for bus master DMA transfers
@@ -1818,6 +1823,21 @@
 CONFIG_FB_ATY
   This driver supports graphics boards with the ATI Mach64 chips.
 
+  This driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want).
+  The module will be called atyfb.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
+ATI Rage128 display support (EXPERIMENTAL)
+CONFIG_FB_ATY128
+  This driver supports graphics boards with the ATI Rage128 chips.
+  Say Y if you have such a graphics board.
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called aty128fb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 PowerMac "control" frame buffer device support
 CONFIG_FB_CONTROL
   This driver supports a frame buffer for the graphics adapter in the
@@ -4081,9 +4101,11 @@
   tagged command queuing and fast synchronous data transfers up to 80
   MB/s with wide FAST-40 LVD devices and controllers.
 
+  This driver does not support SYM53C1010 Ultra-160 PCI-SCSI chips.
+  Support for SYM53C1010 chips requires the "SYM53C8XX SCSI option" to
+  be configured. This option will configure a different driver.
   Recent versions of the 53C8XX chips are better supported by the
-  option "SYM53C8XX SCSI support", below. This option will configure 
-  a different driver.
+  option "SYM53C8XX SCSI support", below.
 
   If you want the kernel to select the recommended driver for each of 
   of your NCR/SYM53C8XX controllers you may just configure both the 
@@ -4102,7 +4124,8 @@
 CONFIG_SCSI_SYM53C8XX
   This driver supports all the features of recent 53C8XX chips (used
   in PCI SCSI controllers), notably the hardware phase mismatch
-  feature of the SYM53C896.
+  feature of the SYM53C896, SYM53C895A and SYM53C1010.
+  It also supports Ultra-160 SCSI data transfers for the SYM53C1010.
 
   Older versions of the 53C8XX chips are not supported by this
   driver. If your system uses either a 810 rev. < 16, a 815, or a 825
@@ -4124,8 +4147,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
@@ -4133,9 +4156,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,
@@ -4146,7 +4169,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.
 
@@ -4197,7 +4220,9 @@
 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.
   
@@ -5191,6 +5216,14 @@
   If you want to do that, say M here. The module will be called
   sealevel.o.
 
+SyncLink HDLC/SYNCPPP support
+CONFIG_SYNCLINK_SYNCPPP
+  Enables HDLC/SYNCPPP support for the SyncLink WAN driver.
+  Normally the SyncLink WAN driver works with the main PPP
+  driver (ppp.c) and pppd program. HDLC/SYNCPPP support allows use
+  of the Cisco HDLC/PPP driver (syncppp.c).
+  The SyncLink WAN driver (in character devices) must also be enabled.
+
 Frame Relay (DLCI) support
 CONFIG_DLCI
   This is support for the frame relay protocol; frame relay is a fast
@@ -6929,6 +6962,35 @@
   This is support for the DIGITAL series of EISA (DEFEA) and PCI
   (DEFPA) controllers which can connect you to a local FDDI network.
 
+SysKonnect FDDI PCI support
+CONFIG_SKFP
+  Say Y here if you have a SysKonnect FDDI PCI adapter.
+  The following adapters are supported by this driver:
+  - SK-5521 (SK-NET FDDI-UP)
+  - SK-5522 (SK-NET FDDI-UP DAS)
+  - SK-5541 (SK-NET FDDI-FP)
+  - SK-5543 (SK-NET FDDI-LP)
+  - SK-5544 (SK-NET FDDI-LP DAS)
+  - SK-5821 (SK-NET FDDI-UP64)
+  - SK-5822 (SK-NET FDDI-UP64 DAS)
+  - SK-5841 (SK-NET FDDI-FP64)
+  - SK-5843 (SK-NET FDDI-LP64)
+  - SK-5844 (SK-NET FDDI-LP64 DAS)
+  - Netelligent 100 FDDI DAS Fibre SC
+  - Netelligent 100 FDDI SAS Fibre SC
+  - Netelligent 100 FDDI DAS UTP
+  - Netelligent 100 FDDI SAS UTP
+  - Netelligent 100 FDDI SAS Fibre MIC
+  Read Documentation/networking/skfp.txt for information about
+  the driver.
+  Questions concerning this driver can be addressed to:
+    linux@syskonnect.de
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called skfp.o.
+
 HIgh Performance Parallel Interface support (EXPERIMENTAL)
 CONFIG_HIPPI
   HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
@@ -7891,6 +7953,20 @@
   want), say M here and read Documentation/modules.txt. The module
   will be called smbfs.o. Most people say N, however.
 
+use nls by default
+CONFIG_SMB_NLS_DEFAULT
+  Enabling this will make smbfs use nls translations by default. You
+  need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls
+  settings and you need to give the default nls for the SMB server as
+  CONFIG_SMB_NLS_REMOTE.
+
+nls support setting
+CONFIG_SMB_NLS_REMOTE
+  This setting allows you to specify a default value for which
+  codepage the server uses. If this field is left blank no
+  translations will be done. The local codepage/charset default to
+  CONFIG_NLS_DEFAULT, you need to set that value in the NLS menu.
+
 Coda filesystem support
 CONFIG_CODA_FS
   Coda is an advanced network filesystem, similar to NFS in that it
@@ -9501,6 +9577,23 @@
  You can compile this driver directly into the kernel, or use
  it as a module.  The module will be called sbc60xxwdt.o.
 
+CONFIG_MICROCODE
+  /dev/cpu/microcode - Intel P6 CPU microcode support
+
+  If you say Y here you will be able to update the microcode on
+  Intel processors in the P6 family, e.g. Pentium Pro, Pentium II,
+  Pentium III, Xeon etc. You will obviously need the actual microcode
+  binary data itself which is not shipped with the Linux kernel.
+ 
+  For latest news and information on obtaining all the required
+  ingredients for this driver, check:
+  http://www.urbanmyth.org/microcode/
+ 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called microcode.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
 Enhanced Real Time Clock Support
 CONFIG_RTC
   If you say Y here and create a character special file /dev/rtc with
@@ -9519,6 +9612,20 @@
   sampling), then say Y here, and read Documentation/rtc.txt for
   details.
 
+AGP/GART support
+CONFIG_AGP
+  This provides a kernel interface (/dev/agpgart) for programming AGP
+  transfers on motherboards that support them. Primarily, this is used
+  for hardware-accelerated 3d graphics, though any other AGP device
+  could take advantage of it.
+
+  If you have a 3d-capable AGP video card say 'M' or 'Y' here.
+  Otherwise, say 'N'.
+
+  You will also have to indicate support for your specific chipset.
+  Consult the output of lspci, your motherboard manual, or the inside
+  of your computer if unsure what to choose. Multiple selections are ok.
+
 Tadpole ANA H8 Support
 CONFIG_H8
   The Hitachi H8/337 is a microcontroller used to deal with the power
@@ -10275,7 +10382,7 @@
 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.
+  chipset, such as the Creative SBLive!,  SB PCI512 or Emu-APS.
 
 Ensoniq ES1370 based PCI sound cards
 CONFIG_SOUND_ES1370
@@ -12332,6 +12439,14 @@
    boards supported by this driver, and for further information 
    on the use of this driver. 
 
+Compaq Smart Array support
+CONFIG_BLK_CPQ_CISS_DA
+   This is the driver for Compaq Smart Array controllers.
+   Everyone using these boards should say Y here.
+   See "linux/Documentation/cciss.txt" for the current list of
+   boards supported by this driver, and for further information
+   on the use of this driver.
+
 QuickNet Internet LineJack/PhoneJack support
 CONFIG_PHONE_IXJ
   Say M if you have a telephony card manufactured by Quicknet
@@ -12350,6 +12465,17 @@
   If you do not have any Quicknet telephony cards, you can safely
   ignore this option.
 
+Kawasaki USB ethernet controller support
+CONFIG_USB_KAWETH
+  Say Y here if you want support for devices based on the Kawasaki
+  LSI KL5KUSB100 USB to Ethernet 1-Chip Controller, such as the
+  NetGear EA101 USB to Ethernet Adapter.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kaweth.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+ 
 Toshiba Laptop support
 CONFIG_TOSHIBA	
   If you intend to run this the kernel on a Toshiba portable say yes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/README.DAC960 linux.18p8/Documentation/README.DAC960
--- linux.vanilla/Documentation/README.DAC960	Sat Sep  9 18:42:32 2000
+++ linux.18p8/Documentation/README.DAC960	Sun Sep 10 14:46:08 2000
@@ -1,11 +1,11 @@
    Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-			Version 2.2.8 for Linux 2.2.16
-			Version 2.4.8 for Linux 2.4.0
+			Version 2.2.9 for Linux 2.2.17
+			Version 2.4.9 for Linux 2.4.0
 
 			      PRODUCTION RELEASE
 
-				19 August 2000
+			       7 September 2000
 
 			       Leonard N. Zubkoff
 			       Dandelion Digital
@@ -203,13 +203,13 @@
 
 			      DRIVER INSTALLATION
 
-This distribution was prepared for Linux kernel version 2.2.16 or 2.4.0.
+This distribution was prepared for Linux kernel version 2.2.17 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.8.tar.gz (or DAC960-2.4.8.tar.gz)
+  tar -xvzf DAC960-2.2.9.tar.gz (or DAC960-2.4.9.tar.gz)
   mv README.DAC960 linux/Documentation
   mv DAC960.[ch] linux/drivers/block
   patch -p0 < DAC960.patch (if DAC960.patch is included)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/SubmittingDrivers linux.18p8/Documentation/SubmittingDrivers
--- linux.vanilla/Documentation/SubmittingDrivers	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/SubmittingDrivers	Thu Aug 31 22:18:27 2000
@@ -0,0 +1,112 @@
+Submitting Drivers For The Linux Kernel
+---------------------------------------
+
+This document is intended to explain how to submit device drivers to the
+Linux 2.2 and 2.4test kernel trees. Note that if you are interested in video
+card drivers you should probably talk to XFree86 (http://wwww.xfree86.org) 
+instead.
+
+Allocating Device Numbers
+-------------------------
+
+Major and minor numbers for devices are allocated by the Linux assigned name
+and number authority (currently better known as H Peter Anvin). The
+site is http://www.lanana.org/. This also deals with allocating numbers for
+devices that are not going to be submitted to the mainstream kernel.
+
+If you don't use assigned numbers then when you device is submitted it will
+get given an assigned number even if that is different from values you may
+have shipped to customers before.
+
+Who To Submit Drivers To
+------------------------
+
+Linux 2.0:
+	No new drivers are accepted for this kernel tree
+
+Linux 2.2:
+	If the code area has a general maintainer then please submit it to
+	the maintainer listed in MAINTAINERS in the kernel file. If the
+	maintainer does not respond or you cannot find the appropriate
+	maintainer then please contact Alan Cox <alan@lxorguk.ukuu.org.uk>
+
+Linux 2.4test:
+	This kernel tree is under active development. The same rules apply
+	as 2.2 but you may wish to submit your driver via linux-kernel (see
+	resources) and follow that list to track changes in API's. These
+	should no longer be occuring as we are now in a code freeze.
+	The final contact point for Linux 2.4 submissions is 	
+	<torvalds@transmeta.com>.
+
+What Criteria Determine Acceptance
+----------------------------------
+
+Licensing:	The code must be released to us under the GNU public license. 
+		We don't insist on any kind of exclusively GPL licensing,
+		and if you wish the driver to be useful to other communities
+		such as BSD you may well wish to release under multiple
+		licenses.
+
+Interfaces:	If your driver uses existing interfaces and behaves like
+		other drivers in the same class it will be much more likely
+		to be accepted than if it invents gratuitous new ones. 
+		If you need to implement a common API over Linux and NT
+		drivers do it in userspace.
+
+Code:		Please use the Linux style of code formatting as documented
+		in Documentation/CodingStyle. If you have sections of code
+		that need to be in other formats, for example because they
+		are shared with a windows driver kit and you want to
+		maintain them just once seperate them out nicely and note
+		this fact.
+
+Portability:	Pointers are not always 32bits, people do not all have
+		floating point and you shouldn't use inline x86 assembler in 
+		your driver without careful thought. Pure x86 drivers
+		generally are not popular. If you only have x86 hardware it 
+		is hard to test portability but it is easy to make sure the
+		code can easily be made portable.
+
+Clarity:	It helps if anyone can see how to fix the driver. It helps
+		you because you get patches not bug reports. If you submit a
+		driver that intentionally obfuscates how the hardware works
+		it will go in the bitbucket.
+
+Control:	In general if there is active maintainance of a driver by
+		the author then patches will be redirected to them unless 
+		they are totally obvious and without need of checking.
+		If you want to be the contact and update point for the
+		driver it is a good idea to state this in the comments.
+
+What Criteria Do Not Determine Acceptance
+-----------------------------------------
+
+Vendor:		Being the hardware vendor and maintaining the driver is
+		often a good thing. If there is a stable working driver from
+		other people already in the tree don't expect 'we are the
+		vendor' to get your driver chosen. Ideally work with the 
+		existing driver author to build a single perfect driver.
+
+Author:		It doesn't matter if a large Linux company wrote the driver,
+		or you did. Nobody has any special access to the kernel
+		tree. Anyone who tells you otherwise isn't telling the
+		whole story.
+
+
+Resources
+---------
+
+Linux kernel master tree:
+	ftp.kernel.org:/pub/linux/kernel/...
+
+Linux kernel mailing list:		
+	linux-kernel@vger.kernel.org
+	[mail majordomo@vger.kernel.org to subscribe]
+
+Kernel traffic:
+	Weekly summary of kernel list activity (much easier to read)
+	[http://kt.linuxcare.com/kernel-traffic]
+
+Linux USB project:
+	http://sourceforge.net/projects/linux-usb/
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/cciss.txt linux.18p8/Documentation/cciss.txt
--- linux.vanilla/Documentation/cciss.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/cciss.txt	Fri Sep  1 13:32:52 2000
@@ -0,0 +1,47 @@
+This driver is for Compaq's SMART Array Controllers.
+
+Supported Cards:
+----------------
+
+This driver is known to work with the following cards:
+
+	* SA 5300
+
+If notes are not already created in the /dev/cciss directory
+
+# mkdev.cciss [ctlrs]
+
+Where ctlrs is the number of controllers you have (defaults to 1 if not
+specified).
+
+Device Naming:
+--------------
+
+You need some entries in /dev for the cciss device.  The mkdev.cciss script
+can make device nodes for you automatically.  Currently the device setup
+is as follows:
+
+Major numbers:
+	104	cciss0	
+	105	cciss1	
+	106	cciss2 
+	etc...
+
+Minor numbers:
+        b7 b6 b5 b4 b3 b2 b1 b0
+        |----+----| |----+----|
+             |           |
+             |           +-------- Partition ID (0=wholedev, 1-15 partition)
+             |
+             +-------------------- Logical Volume number
+
+The suggested device naming scheme is:
+/dev/cciss/c0d0			Controller 0, disk 0, whole device
+/dev/cciss/c0d0p1		Controller 0, disk 0, partition 1
+/dev/cciss/c0d0p2		Controller 0, disk 0, partition 2
+/dev/cciss/c0d0p3		Controller 0, disk 0, partition 3
+
+/dev/cciss/c1d1			Controller 1, disk 1, whole device
+/dev/cciss/c1d1p1		Controller 1, disk 1, partition 1
+/dev/cciss/c1d1p2		Controller 1, disk 1, partition 2
+/dev/cciss/c1d1p3		Controller 1, disk 1, partition 3
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/mkdev.cciss linux.18p8/Documentation/mkdev.cciss
--- linux.vanilla/Documentation/mkdev.cciss	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/mkdev.cciss	Fri Sep  1 13:32:52 2000
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Script to create device nodes for SMART array controllers
+# Usage:
+#	mkdev.cciss [num controllers] [num log volumes] [num partitions]
+#
+# With no arguments, the script assumes 1 controller, 16 logical volumes,
+# and 16 partitions/volume, which is adequate for most configurations.
+#
+# If you had 5 controllers and were planning on no more than 4 logical volumes
+# each, using a maximum of 8 partitions per volume, you could say:
+#
+# mkdev.cciss 5 4 8
+#
+# Of course, this has no real benefit over "mkdev.cciss 5" except that it
+# doesn't create so many device nodes in /dev/cciss.
+
+NR_CTLR=${1-1}
+NR_VOL=${2-16}
+NR_PART=${3-16}
+
+if [ ! -d /dev/cciss ]; then
+	mkdir -p /dev/cciss
+fi
+
+C=0; while [ $C -lt $NR_CTLR ]; do
+	MAJ=`expr $C + 104`
+	D=0; while [ $D -lt $NR_VOL ]; do
+		P=0; while [ $P -lt $NR_PART ]; do
+			MIN=`expr $D \* 16 + $P`
+			if [ $P -eq 0 ]; then
+				mknod /dev/cciss/c${C}d${D} b $MAJ $MIN
+			else
+				mknod /dev/cciss/c${C}d${D}p${P} b $MAJ $MIN
+			fi
+			P=`expr $P + 1`
+		done
+		D=`expr $D + 1`
+	done
+	C=`expr $C + 1`
+done
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/modules.txt linux.18p8/Documentation/modules.txt
--- linux.vanilla/Documentation/modules.txt	Fri Apr 21 12:45:49 2000
+++ linux.18p8/Documentation/modules.txt	Thu Aug 31 15:02:02 2000
@@ -124,7 +124,7 @@
 
 To use modprobe successfully, you generally place the following
 command in your /etc/rc.d/rc.S script.  (Read more about this in the
-"rc.hints" file in the module utilities package, "modules-x.y.z.tar.gz".)
+"rc.hints" file in the module utilities package, "modutils-x.y.z.tar.gz".)
 
 	/sbin/depmod -a
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/skfp.txt linux.18p8/Documentation/networking/skfp.txt
--- linux.vanilla/Documentation/networking/skfp.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/networking/skfp.txt	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,224 @@
+(C)Copyright 1998-2000 SysKonnect,
+===========================================================================
+
+skfp.txt created 17-Jul-2000
+
+Readme File for skfp.o v2.07
+
+
+This file contains
+(1) OVERVIEW
+(2) SUPPORTED ADAPTERS
+(3) GENERAL INFORMATION
+(4) INSTALLATION
+(5) INCLUSION OF THE ADAPTER IN SYSTEM START
+(6) TROUBLESHOOTING
+(7) FUNCTION OF THE ADAPTER LEDS
+(8) HISTORY
+
+===========================================================================
+
+
+
+(1) OVERVIEW
+============
+
+This README explains how to use the driver 'skfp' for Linux with your
+network adapter.
+
+Chapter 2: Contains a list of all network adapters that are supported by
+	   this driver.
+
+Chapter 3: Gives some general information.
+
+Chapter 4: Describes common problems and solutions.
+
+Chapter 5: Shows the changed functionality of the adapter LEDs.
+
+Chapter 6: History of development.
+
+***
+
+
+(2) SUPPORTED ADAPTERS
+======================
+
+The network driver 'skfp' supports the following network adapters:
+SysKonnect adapters:
+  - SK-5521 (SK-NET FDDI-UP)
+  - SK-5522 (SK-NET FDDI-UP DAS)
+  - SK-5541 (SK-NET FDDI-FP)
+  - SK-5543 (SK-NET FDDI-LP)
+  - SK-5544 (SK-NET FDDI-LP DAS)
+  - SK-5821 (SK-NET FDDI-UP64)
+  - SK-5822 (SK-NET FDDI-UP64 DAS)
+  - SK-5841 (SK-NET FDDI-FP64)
+  - SK-5843 (SK-NET FDDI-LP64)
+  - SK-5844 (SK-NET FDDI-LP64 DAS)
+Compaq adapters (not tested):
+  - Netelligent 100 FDDI DAS Fibre SC
+  - Netelligent 100 FDDI SAS Fibre SC
+  - Netelligent 100 FDDI DAS UTP
+  - Netelligent 100 FDDI SAS UTP
+  - Netelligent 100 FDDI SAS Fibre MIC
+***
+
+
+(3) GENERAL INFORMATION
+=======================
+
+From v2.01 on, the driver is integrated in the linux kernel sources.
+Therefor, the installation is the same as for any other adapter
+supported by the kernel.
+Refer to the manual of your distribution about the installation
+of network adapters.
+Makes my life much easier :-)
+***
+
+
+(4) TROUBLESHOOTING
+===================
+
+If you run into problems during installation, check those items:
+
+Problem:  The FDDI adapter can not be found by the driver.
+Reason:   Look in /proc/pci for the following entry:
+             'FDDI network controller: SysKonnect SK-FDDI-PCI ...'
+	  If this entry exists, then the FDDI adapter has been
+	  found by the system and should be able to be used.
+	  If this entry does not exist or if the file '/proc/pci'
+	  is not there, then you may have a hardware problem or PCI
+	  support may not be enabled in your kernel.
+	  The adapter can be checked using the diagnostic program
+	  which is available from the SysKonnect web site:
+	      www.syskonnect.de
+	  Some COMPAQ machines have a problem with PCI under
+	  Linux. This is described in the 'PCI howto' document
+	  (included in some distributions or available from the
+	  www, e.g. at 'www.linux.org') and no workaround is available.
+
+Problem:  You want to use your computer as a router between
+          multiple IP subnetworks (using multiple adapters), but
+	  you can not reach computers in other subnetworks.
+Reason:   Either the router's kernel is not configured for IP
+	  forwarding or there is a problem with the routing table
+	  and gateway configuration in at least one of the
+	  computers.
+
+If your problem is not listed here, please contact our
+technical support for help. 
+You can send email to:
+  linux@syskonnect.de
+When contacting our technical support,
+please ensure that the following information is available:
+- System Manufacturer and Model
+- Boards in your system
+- Distribution
+- Kernel version
+
+***
+
+
+(5) FUNCTION OF THE ADAPTER LEDS
+================================
+
+        The functionality of the LED's on the FDDI network adapters was
+        changed in SMT version v2.82. With this new SMT version, the yellow
+        LED works as a ring operational indicator. An active yellow LED
+        indicates that the ring is down. The green LED on the adapter now
+        works as a link indicator where an active GREEN LED indicates that
+        the respective port has a physical connection.
+
+        With versions of SMT prior to v2.82 a ring up was indicated if the
+        yellow LED was off while the green LED(s) showed the connection
+        status of the adapter. During a ring down the green LED was off and
+        the yellow LED was on.
+
+        All implementations indicate that a driver is not loaded if
+        all LEDs are off.
+
+***
+
+
+(6) HISTORY
+===========
+
+v2.07 (20000717) (In-Kernel version)
+    New features:
+	- in kernel 2.2.17 (hopefully !)
+
+v2.06 (20000511) (In-Kernel version)
+    New features:
+	- 64 bit support
+	- new pci dma interface
+	- in kernel 2.3.99
+
+v2.05 (20000217) (In-Kernel version)
+    New features:
+	- Changes for 2.3.45 kernel
+
+v2.04 (20000207) (Standalone version)
+    New features:
+	- Added rx/tx byte counter
+
+v2.03 (20000111) (Standalone version)
+    Problems fixed:
+	- Fixed printk statements from v2.02
+
+v2.02 (991215) (Standalone version)
+    Problems fixed:
+	- Removed unnecessary output
+	- Fixed path for "printver.sh" in makefile
+
+v2.01 (991122)
+    New features:
+	- Integration in Linux kernel sources
+	- Support for memory mapped I/O
+
+v2.00 (991112)
+    New features:
+	- Full source released under GPL
+
+v1.05 (991023)
+    Problems fixed:
+	- Compilation with kernel version 2.2.13 failed
+
+v1.04 (990427)
+    Changes:
+	- New SMT module included, changing LED functionality
+    Problems fixed:
+	- Synchronization on SMP machines was buggy
+
+v1.03 (990325)
+    Problems fixed:
+	- Interrupt routing on SMP machines could be incorrect
+
+v1.02 (990310)
+    New features:
+	- Support for kernel versions 2.2.x added
+	- Kernel patch instead of private duplicate of kernel functions
+
+v1.01 (980812)
+    Problems fixed:
+	Connection hangup with telnet
+	Slow telnet connection
+
+v1.00 beta 01 (980507)
+    New features:
+	None.
+    Problems fixed:
+	None.
+    Known limitations:
+        - tar archive instead of standard package format (rpm).
+	- FDDI statistic is empty.
+	- not tested with 2.1.xx kernels
+	- integration in kernel not tested
+	- not tested simultaneously with FDDI adapters from other vendors.
+	- only X86 processors supported.
+	- SBA (Synchronous Bandwidth Allocator) parameters can
+	  not be configured.
+	- does not work on some COMPAQ machines. See the PCI howto
+	  document for details about this problem.
+	- data corruption with kernel versions below 2.0.33.
+
+*** End of information file ***
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/nmi_watchdog.txt linux.18p8/Documentation/nmi_watchdog.txt
--- linux.vanilla/Documentation/nmi_watchdog.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/nmi_watchdog.txt	Tue Sep 12 11:51:04 2000
@@ -0,0 +1,34 @@
+
+Is your SMP system locking up unpredictably? No keyboard activity, just
+a frustrating complete hard lockup? Do you want to help us debugging
+such lockups? If all yes then this document is definitely for you.
+
+on Intel SMP hardware there is a feature that enables us to generate
+'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt - these get
+executed even if the system is otherwise locked up hard) This can be
+used to debug hard kernel lockups. By executing periodic NMI interrupts,
+the kernel can monitor wether any CPU has locked up, and print out
+debugging messages if so.  You can enable/disable the NMI watchdog at boot
+time with the 'nmi_watchdog=1' boot parameter. Eg. the relevant
+lilo.conf entry:
+
+        append="nmi_watchdog=1"
+
+A 'lockup' is the following scenario: if any CPU in the system does not
+execute the period local timer interrupt for more than 5 seconds, then
+the NMI handler generates an oops and kills the process. This
+'controlled crash' (and the resulting kernel messages) can be used to
+debug the lockup. Thus whenever the lockup happens, wait 5 seconds and
+the oops will show up automatically. If the kernel produces no messages
+then the system has crashed so hard (eg. hardware-wise) that either it
+cannot even accept NMI interrupts, or the crash has made the kernel
+unable to print messages.
+
+You can find NMI watchdog patch against Linux 2.2.x at 
+http://people.redhat.com/mingo/NMI-watchdog-patches/
+
+
+[ feel free to send bug reports, suggestions and patches to
+  Ingo Molnar <mingo@redhat.com> or the Linux SMP mailing
+  list at <linux-smp@vger.kernel.org> ]
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/CREDITS linux.18p8/Documentation/usb/CREDITS
--- linux.vanilla/Documentation/usb/CREDITS	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/CREDITS	Thu Sep 14 15:35:24 2000
@@ -0,0 +1,169 @@
+Credits for the Simple Linux USB Driver:
+
+The following people have contributed to this code (in alphabetical
+order by last name).  I'm sure this list should be longer, its
+difficult to maintain, add yourself with a patch if desired.
+
+  Georg Acher <acher@informatik.tu-muenchen.de>
+  Alan Cox <alan@lxorguk.ukuu.org.uk>
+  Randy Dunlap <randy.dunlap@intel.com>
+  Johannes Erdfelt <jerdfelt@sventech.com>
+  Deti Fliegl <deti@fliegl.de>
+  ham <ham@unsuave.com>
+  Bradley M Keryan <keryan@andrew.cmu.edu>
+  Greg Kroah-Hartman <greg@kroah.com>
+  Pavel Machek <pavel@suse.cz>
+  Paul Mackerras <paulus@cs.anu.edu.au>
+  David E. Nelson <dnelson@jump.net>
+  Vojtech Pavlik <vojtech@suse.cz>
+  Bill Ryder <bryder@sgi.com>
+  Thomas Sailer <sailer@ife.ee.ethz.ch>
+  Gregory P. Smith <greg@electricrain.com>
+  Linus Torvalds <torvalds@transmeta.com>
+  Roman Weissgaerber <weissg@vienna.at>
+  <Kazuki.Yasumatsu@fujixerox.co.jp>
+
+Special thanks to:
+
+  Inaky Perez Gonzalez <inaky@peloncho.fis.ucm.es> for starting the
+  Linux USB driver effort and writing much of the larger uusbd driver.
+  Much has been learned from that effort.
+
+  The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
+  and offering suggestions and sharing implementation experiences.
+
+Additional thanks to the following companies and people for donations
+of hardware, support, time and development (this is from the original
+THANKS file in Inaky's driver):
+
+        The following corporations have helped us in the development
+        of Linux USB / UUSBD:
+
+	- 3Com GmbH for donating a ISDN Pro TA and supporting me
+	  in technical questions and with test equipment. I'd never 
+	  expect such a great help.
+
+        - USAR Systems provided us with one of their excellent USB
+          Evaluation Kits. It allows us to test the Linux-USB driver
+          for compliance with the latest USB specification. USAR
+          Systems recognized the importance of an up-to-date open
+          Operating System and supports this project with
+          Hardware. Thanks!.
+
+        - Thanks to Intel Corporation for their precious help.
+
+        - We teamed up with Cherry to make Linux the first OS with
+          built-in USB support. Cherry is one of the biggest keyboard
+          makers in the world.
+
+        - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
+          PCI-to-USB Controller Board to test the OHCI implementation.
+
+        - Due to their support to us, Keytronic can be sure that they
+          will sell keyboards to some of the 3 million (at least)
+          Linux users.
+
+        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
+          It was almost impossible to get a PC backplate USB connector
+          for the motherboard here at Europe (mine, home-made, was
+          quite lousy :). Now I know where to acquire nice USB stuff!
+
+        - Genius Germany donated a USB mouse to test the mouse boot
+          protocol. They've also donated a F-23 digital joystick and a
+          NetMouse Pro. Thanks! 
+
+        - AVM GmbH Berlin is supporting the development of the Linux
+          USB driver for the AVM ISDN Controller B1 USB. AVM is a
+          leading manufacturer for active and passive ISDN Controllers
+          and CAPI 2.0-based software. The active design of the AVM B1
+          is open for all OS platforms, including Linux.
+
+        - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
+          USB Floppy Disk Drive, so we could test the bulk transfer
+          code.
+
+        - Many thanks to Logitech for contributing a three axis USB
+          mouse. 
+
+          Logitech designs, manufactures and markets
+          Human Interface Devices, having a long history and
+          experience in making devices such as keyboards, mice,
+          trackballs, cameras, loudspeakers and control devices for
+          gaming and professional use.
+
+          Being a recognized vendor and seller for all these devices,
+          they have donated USB mice, a joystick and a scanner, as a
+          way to acknowledge the importance of Linux and to allow
+          Logitech customers to enjoy support in their favorite
+          operating systems and all Linux users to use Logitech and
+          other USB hardware.
+
+          Logitech is official sponsor of the Linux Conference on
+          Feb. 11th 1999 in Vienna, where we'll will present the
+          current state of the Linux USB effort.
+
+        - CATC has provided means to uncover dark corners of the UHCI
+          inner workings with a USB Inspector.
+
+        - Thanks to Entrega for providing PCI to USB cards, hubs and
+          converter products for development. 
+
+	- Thanks to ConnectTech for providing a WhiteHEAT usb to
+	  serial converter, and the documentation for the device to
+	  allow a driver to be written.
+
+        And thanks go to (hey! in no particular order :)
+
+        - Oren Tirosh <orenti@hishome.net>, for standing so patiently
+          all my doubts'bout USB and giving lots of cool ideas.
+
+        - Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
+          pointing out mortal bugs and giving advice.
+
+        - Edmund Humemberger <ed@atnet.at>, for it's great work on
+          public relationships and general management stuff for the
+          Linux-USB effort.
+
+        - Alberto Menegazzi <flash@flash.iol.it> is starting the
+          documentation for the UUSBD. Go for it!
+
+        - Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
+          introductory documents (competing with Alberto's :).
+
+        - Christian Groessler <cpg@aladdin.de>, for it's help on those
+          itchy bits ... :)
+
+        - Paul MacKerras for polishing OHCI and pushing me harder for
+          the iMac support, giving improvements and enhancements.
+
+        - Fernando Herrera <fherrera@eurielec.etsit.upm.es> has taken
+          charge of composing, maintaining and feeding the
+          long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!
+
+        - Rasca Gmelch <thron@gmx.de> has revived the raw driver and
+          pointed bugs, as well as started the uusbd-utils package.
+
+        - Peter Dettori <dettori@ozy.dec.com> is uncovering bugs like
+          crazy, as well as making cool suggestions, great :)
+
+        - All the Free Software and Linux community, the FSF & the GNU
+          project, the MIT X consortium, the TeX people ... everyone!
+          You know who you are!
+
+        - Big thanks to Richard Stallman for creating Emacs!
+
+        - The people at the linux-usb mailing list, for reading so
+          many messages :) Ok, no more kidding; for all your advises!
+
+        - All the people at the USB Implementors Forum for their
+          help and assistance.
+
+        - Nathan Myers <ncm@cantrip.org>, for his advice! (hope you
+          liked Cibeles' party).
+
+        - Linus Torvalds, for starting, developing and managing Linux.
+
+        - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
+          for convincing me USB Standard hubs are not that standard
+          and that's good to allow for vendor specific quirks on the
+          standard hub driver.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/URB.txt linux.18p8/Documentation/usb/URB.txt
--- linux.vanilla/Documentation/usb/URB.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/URB.txt	Thu Sep 14 15:35:24 2000
@@ -0,0 +1,196 @@
+1. Specification of the API
+
+1.1. Basic concept or 'What is an URB?'
+
+The basic idea of the new driver is message passing, the message itself is 
+called USB Request Block, or URB for short. 
+
+- An URB consists of all relevant information to execute any USB transaction 
+and deliver the data and status back. 
+
+- Execution of an URB is an inherently asynchronous operation, i.e. the 
+submit_urb(urb) call returns immediately after it has successfully queued 
+the requested action. 
+
+- Ongoing transfers for one URB (e.g. ISO) can simply be canceled with
+unlink_urb(urb) at any time. 
+
+- Each URB has a completion handler, which is called after the action
+has been successfully completed or canceled (INT transfers behave a bit
+different, see below). The URB also contains a context-pointer for free 
+usage and information passing to the completion handler.
+
+- URBs can be linked. After completing one URB, the next one can be
+automatically submitted. This is especially useful for ISO transfers:
+You only have read/write the data from/to the buffers in the completion 
+handler, the continuous streaming itself is transparently done by the 
+URB-machinery.
+
+1.2. The URB structure
+
+typedef struct urb
+{
+// ignore, for host controller/URB machine internal use
+	void *hcpriv;                   // private data for host controller
+	struct list_head urb_list;      // list pointer to all active urbs 
+
+// This is used for urb linking
+	struct urb* next;               // pointer to next URB  
+	struct usb_device *dev;         // pointer to associated USB device
+
+// pipe is assembled by the various well known pipe-macros in usb.h
+	unsigned int pipe;              // pipe information
+
+// status after each completion
+	int status;                     // returned status
+	unsigned int transfer_flags;    // ASAP, SP_OK, EARLY_COMPLETE
+
+// for data stage (CTRL), BULK, INT and ISO
+	void *transfer_buffer;          // associated data buffer
+
+// expected length
+	int transfer_buffer_length;     // data buffer length
+	int actual_length;              // actual data buffer length    
+
+// setup stage for CTRL (always 8 bytes!)
+	unsigned char* setup_packet;    // setup packet (control only)
+	
+// with ASAP, start_frame is set to the determined frame
+	int start_frame;                // start frame (iso/irq)
+	int number_of_packets;          // # of packets (iso/int)
+	int interval;                   // polling interval (irq only)
+	int error_count;                // number of errors (iso only)
+	//
+	void *context;                  // context for completion routine
+	usb_complete_t complete;        // pointer to completion routine
+	//
+// specification of the requested data offsets and length for ISO
+	iso_packet_descriptor_t  iso_frame_desc[0];
+} urb_t, *purb_t;
+
+1.3. How to get an URB?
+
+URBs are allocated with the following call
+
+	purb_t alloc_urb(int isoframes)
+
+Return value is a pointer to the allocated URB, 0 if allocation failed.
+The parameter isoframes specifies the number of isochronous transfer frames
+you want to schedule. For CTRL/BULK/INT, use 0.
+
+To free an URB, use
+
+	void free_urb(purb_t purb)
+
+This call also may free internal (host controller specific) memory in the
+future.
+
+1.4. What has to be filled in?
+
+Depending on the type of transaction, there are some macros 
+(FILL_CONTROL_URB, FILL_BULK_URB, and FILL_INT_URB, defined in uhci.h)
+that simplify the URB creation. In general, all macros need the usb
+device pointer, the pipe (usual format), the transfer buffer, the 
+desired transfer length, the completion  handler, and its context. 
+Take a look at the uhci_control_msg-function that convert the old API 
+into an URB.
+
+Flags:
+For ISO there are two startup behaviors: Specified start_frame or ASAP.
+For ASAP set USB_ISO_ASAP in transfer_flags.
+
+If short packets should NOT be tolerated, set USB_DISABLE_SPD in 
+transfer_flags.
+
+Usually, (to reduce restart time) the completion handler is called
+AFTER the URB re-submission. You can get the other way by setting
+USB_URB_EARLY_COMPLETE in transfer_flags. This is implicit for
+INT transfers.
+
+1.5. How to submit an URB?
+
+Just call
+
+	int submit_urb(purb_t purb)
+
+It immediately returns, either with status 0 (request queued) or some
+error code, usually caused by the following:
+
+- Out of memory (-ENOMEM)
+- Wrong pipe handle (-ENXIO)
+- Unplugged device (-ENODEV)
+- Stalled endpoint (-EPIPE)
+- Too many queued ISO transfers (-EAGAIN)
+- Too many requested ISO frames (-EFBIG)
+- Invalid INT interval (-EINVAL)
+- More than one packet for INT (-EINVAL)
+
+After submission, urb->status is USB_ST_URB_PENDING.
+
+For isochronous endpoints, subsequent submitting of URBs to the same endpoint
+with the ASAP flag result in a seamless ISO streaming. Exception: The 
+execution cannot be scheduled later than 900 frames from the 'now'-time. 
+The same applies to INT transfers, but here the seamless continuation is 
+independent of the transfer flags (implicitly ASAP).
+
+1.6. How to cancel an already running URB?
+
+Call
+	int unlink_urb(purb_t purb)
+
+It removes the urb from the internal list and frees all allocated
+HW descriptors. The status is changed to USB_ST_URB_KILLED. After 
+unlink_urb() returns, you can safely free the URB with free_urb(urb)
+and all other possibly associated data (urb->context etc.)
+
+1.7. What about the completion handler?
+
+The completion handler is optional, but useful for fast data processing
+or wakeup of a sleeping process (as shown in the compatibility wrapper's 
+completion handler).
+
+The handler is of the following type:
+
+	typedef void (*usb_complete_t)(struct urb *);
+
+i.e. it gets just the URB that caused the completion call.
+In the completion handler, you should have a look at urb->status to
+detect any USB errors. Since the context parameter is included in the URB,
+you can pass information to the completion handler. 
+
+
+1.8. How to do isochronous (ISO) transfers?
+
+For ISO transfers you have to append the iso_packet_descriptor_t structure 
+to the URB for each frame you want to schedule. When using alloc_urb(n)
+(recommended), the isoframe-parameter n can be used to allocate the
+structures for n frames.
+
+For each entry you have to specify the data offset for this frame (base is
+transfer_buffer), and the length you want to write/expect to read.
+After completion, actual_length contains the actual transfered length and 
+status contains the resulting USB-status for the ISO transfer for this frame.
+It is allowed to specify a varying length from frame to frame (e.g. for
+audio synchronisation/adaptive transfer rates). You can also use the length 
+0 to omit one or more frames (striping).
+
+As can be concluded from above, the UHCI-driver does not care for continuous
+data in case of short packet ISO reads! There's no fixup_isoc() like in the 
+old driver. There may be a common routine to do this in the future, but this 
+has nothing to do with the UHCI-driver!
+
+For scheduling you can choose your own start frame or ASAP. As written above,
+queuing more than one ISO frame with ASAP to the same device&endpoint result 
+in seamless ISO streaming. For continuous streaming you have to use URB
+linking. 
+
+1.9. How to start interrupt (INT) transfers?
+
+INT transfers are currently implemented with 8 different queues for intervals 
+for 1, 2, 4,... 128ms. Only one TD is allocated for each interrupt. After
+calling the completion handler, the TD is recycled.
+With the submission of one URB, the interrupt is scheduled until it is
+canceled by unlink_urb.
+
+The submit_urb()-call modifies urb->interval to the rounded value.
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/acm.txt linux.18p8/Documentation/usb/acm.txt
--- linux.vanilla/Documentation/usb/acm.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/acm.txt	Fri Sep  1 13:51:28 2000
@@ -0,0 +1,138 @@
+			  Linux ACM driver v0.16
+		 (c) 1999 Vojtech Pavlik <vojtech@suse.cz>
+			     Sponsored by SuSE
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+  This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option)
+any later version.
+
+  This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+more details.
+
+  You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc., 59
+Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+  Should you need to contact me, the author, you can do so either by e-mail
+- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, Prague 8, 182 00 Czech Republic
+
+  For your convenience, the GNU General Public License version 2 is included
+in the package: See the file COPYING.
+
+1. Usage
+~~~~~~~~
+  The drivers/usb/acm.c drivers works with USB modems and USB ISDN terminal
+adapters that conform to the Universal Serial Bus Communication Device Class
+Abstract Control Model (USB CDC ACM) specification.
+
+  Many modems do, here is a list of those I know of:
+
+	3Com OfficeConnect 56k
+	3Com Voice FaxModem Pro
+	3Com Sportster
+	MultiTech MultiModem 56k
+	Zoom 2986L FaxModem
+	Compaq 56k FaxModem
+	ELSA Microlink 56k
+
+  I know of one ISDN TA that does work with the acm driver:
+
+	3Com USR ISDN Pro TA
+
+  Unfortunately many modems and most ISDN TAs use proprietary interfaces and
+thus won't work with this drivers. Check for ACM compliance before buying.
+
+  The driver (with devfs) creates these devices in /dev/usb/acm:
+
+	crw-r--r--   1 root     root     166,   0 Apr  1 10:49 0
+	crw-r--r--   1 root     root     166,   1 Apr  1 10:49 1
+	crw-r--r--   1 root     root     166,   2 Apr  1 10:49 2
+
+  And so on, up to 31, with the limit being possible to change in acm.c to up
+to 256, so you can use up to 256 USB modems with one computer (you'll need
+three USB cards for that, though).
+
+  If you don't use devfs, then you can create device nodes with the same
+minor/major numbers anywhere you want, but either the above location or
+/dev/usb/ttyACM0 is preferred.
+
+  To use the modems you need these modules loaded:
+
+	usbcore.o
+	usb-[uo]hci.o or uhci.o
+	acm.o
+
+  After that, the modem[s] should be accessible. You should be able to use
+minicom, ppp and mgetty with them.
+
+2. Verifying that it works
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The first step would be to check /proc/bus/usb/devices, it should look
+like this:
+
+T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
+B:  Alloc=  0/900 us ( 0%), #Int=  0, #Iso=  0
+D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0000 ProdID=0000 Rev= 0.00
+S:  Product=USB UHCI Root Hub
+S:  SerialNumber=6800
+C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
+E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
+T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
+D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
+P:  Vendor=04c1 ProdID=008f Rev= 2.07
+S:  Manufacturer=3Com Inc.
+S:  Product=3Com U.S. Robotics Pro ISDN TA
+S:  SerialNumber=UFT53A49BVT7
+C:  #Ifs= 1 Cfg#= 1 Atr=60 MxPwr=  0mA
+I:  If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=acm
+E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
+C:* #Ifs= 2 Cfg#= 2 Atr=60 MxPwr=  0mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=128ms
+I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+E:  Ad=85(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+E:  Ad=04(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+
+The presence of these three lines (and the Cls= 'comm' and 'data' classes)
+is important, it means it's an ACM device. The Driver=acm means the acm
+driver is used for the device. If you see only Cls=ff(vend.) then you're out
+of luck, you have a device with vendor specific-interface.
+
+D:  Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs=  2
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm
+I:  If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm
+
+In the system log you should see:
+
+usb.c: USB new device connect, assigned device number 2
+usb.c: kmalloc IF c7691fa0, numif 1
+usb.c: kmalloc IF c7b5f3e0, numif 2
+usb.c: skipped 4 class/vendor specific interface descriptors
+usb.c: new device strings: Mfr=1, Product=2, SerialNumber=3
+usb.c: USB device number 2 default language ID 0x409
+Manufacturer: 3Com Inc.
+Product: 3Com U.S. Robotics Pro ISDN TA
+SerialNumber: UFT53A49BVT7
+acm.c: probing config 1
+acm.c: probing config 2
+ttyACM0: USB ACM device
+acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0
+acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7
+usb.c: acm driver claimed interface c7b5f3e0
+usb.c: acm driver claimed interface c7b5f3f8
+usb.c: acm driver claimed interface c7691fa0
+
+If all this seems to be OK, fire up minicom and set it to talk to the ttyACM
+device and try typing 'at'. If it responds with 'OK', then everything is
+working.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/dc2xx.txt linux.18p8/Documentation/usb/dc2xx.txt
--- linux.vanilla/Documentation/usb/dc2xx.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/dc2xx.txt	Fri Sep  1 13:51:28 2000
@@ -0,0 +1,111 @@
+14 April 2000
+david-b@pacbell.net
+
+This is an overview of how to use the "dc2xx" USB driver with certain
+digital still cameras from Kodak and other vendors.
+
+
+CAMERAS
+
+This driver will mostly be used with Kodak DC-2xx series digital still
+cameras, but it should be trivial to tell it about several non-Kodak
+USB-enabled cameras.
+
+You'll most likely want to hook it up to recent versions of "gPhoto"
+(www.gphoto.org), since version 0.4 and later know how to use it to talk
+to Kodak DC-240 and DC-280 cameras over USB.
+
+In addition the DC-220, DC-260, DC-265, and DC-290 are also recognized.
+However, like other cameras using the "Digita OS" (from www.flashpoint.com)
+there is no gPhoto support for this camera.  There is a python script
+for accessing these cameras (see archives of the linux-usb mailing list)
+and a "Digita Services" library that can also use this driver.
+
+The HP PhotoSmart C500 should also work, since it's another Digita camera
+with USB support.
+
+
+USB HARDWARE
+
+Recent kernels have had no particular problems using this driver with
+either OHCI or UHCI chipsets, and have worked on the PowerMac platform.
+
+Note that in some cases changes in BIOS settings may be needed before
+your USB works.  At least one user has reported a need for SMP-related 
+settings as well, and some old hardware may not handle USB correctly.
+
+
+SETUP
+
+Configure in the DC2XX USB driver, and have it in your kernel.  It works
+as a module, or compiled in directly.
+
+Create at least one device, perhaps like this (both read and write):
+
+    # mknod -m 0660 /dev/usb/dc2xx0 c 180 80
+    # mknod -m 0660 /dev/usb/dc2xx1 c 180 81
+    ...
+
+NOTE:  you would normally configure PAM so that the user logged in at
+the console is granted ownership of these devices.  console.perms(5)
+explains how to do this.
+
+The driver supports multiple device nodes.  The USB framework supports
+a maximum of sixteen device nodes (up to minor device number 96).
+
+When you plug in one camera, it will use the first device node (dc2xx0
+in the example above).  A second camera will use the second device node,
+and so on.
+
+
+SANITY TESTING
+
+First:  if you've got /proc support, make sure that the driver has hooked
+itself up correctly.
+
+    - You should see an entry in /proc/bus/usb/drivers for "dc2xx",
+      if you enabled USB /proc support and correctly mounted the
+      usbdevfs on /proc/bus/usb.
+
+Second:  when you connect your camera to the computer, does it get recognized
+by the driver?  (Make sure the camera is powered on!)
+
+    - if you've got /proc/bus/usb/devices, you should see an entry
+      something like this.  The "ProdID" may be different if you didn't
+      plug in a DC-240, as may the strings presented, but "Driver=dc2xx"
+      had better be there.
+
+	T:  Lev=01 Prnt=00 Port=00 Cnt=01 Dev#=  1 Spd=12  MxCh= 0
+	D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+	P:  Vendor=040a ProdID=0120 Rev= 1.08
+	S:  Manufacturer=Eastman Kodak Company
+	S:  Product=KODAK DC240 Zoom Digital Camera
+	C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=100mA
+	I:  If#= 0 Alt= 0 #EPs= 2 Cls=00(>ifc ) Sub=00 Prot=00 Driver=dc2xx
+	E:  Ad=01(O) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+	E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=  0ms
+
+    - see if "dmesg" output tells you that you plugged in your camera.
+
+	Manufacturer: Eastman Kodak Company
+	Product: KODAK DC240 Zoom Digital Camera
+	dc2xx.c: USB Camera #0 connected
+
+Third:  (optional) can you use gPhoto to talk to the camera?
+
+    - When you configure your camera, tell it to use "/dev/usb/dc2xx0"
+      (or whatever name you used).  Right now, gPhoto emits a diagnostic
+      message (non-GUI) saying that it since it didn't act like a TTY,
+      it's assuming it's got a USB connection.
+
+    - With the camera turned on, get the "camera summary".  It'll
+      talk to the camera -- and tell you you're using USB.
+
+If you got that far, you should be able to use everything fine.
+
+
+ADDITIONAL INFORMATION
+
+You may find that you need more driver-specific information, which is
+currently accessible through a link from http://www.linux-usb.org/
+along with other Linux USB resources.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/error-codes.txt linux.18p8/Documentation/usb/error-codes.txt
--- linux.vanilla/Documentation/usb/error-codes.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/error-codes.txt	Fri Sep  1 13:51:28 2000
@@ -0,0 +1,108 @@
+$Id: README.error-codes,v 1.1 1999/12/14 14:03:02 fliegl Exp $
+
+This is the documentation of (hopefully) all possible error codes (and
+their interpretation) that can be returned from the hostcontroller driver 
+and from usbcore.
+
+NOTE:
+The USB_ST_* codes are deferred and are only listed for compatibility, new
+software should use only -E* instead!
+
+
+
+**************************************************************************
+*                   Error codes returned by usb_submit_urb               *
+**************************************************************************
+
+Non-USB-specific:
+
+USB_ST_NOERROR
+0		URB submission went fine
+
+-ENOMEM		no memory for allocation of internal structures	
+
+USB-specific:
+
+-ENODEV		specified USB-device or bus doesn't exist
+
+-ENXIO		specified endpoint doesn't exist on the device
+
+USB_ST_URB_INVALID_ERROR
+-EINVAL		a) Invalid transfer type specified (or not supported)
+		b) Invalid interrupt interval (0<=n<256)
+		c) more than one interrupt packet requested
+
+-EAGAIN		a) specified ISO start frame too early
+		b) (using ISO-ASAP) too much scheduled for the future
+		   wait some time and try again.
+
+-EFBIG		too much ISO frames requested (currently uhci>900)
+
+-EPIPE		specified pipe-handle is already stalled
+
+-EMSGSIZE	endpoint message size is zero, do interface/alternate setting
+
+
+**************************************************************************
+*                   Error codes returned by in urb->status               *
+*                   or in iso_frame_desc[n].status (for ISO)             *
+**************************************************************************
+
+USB_ST_NOERROR
+0			Transfer completed successfully
+
+USB_ST_URB_KILLED
+-ENOENT			URB was canceled by unlink_urb
+
+USB_ST_URB_PENDING
+-EINPROGRESS		URB still pending, no results yet
+			(actually no error until now;-)
+
+USB_ST_BITSTUFF
+USB_ST_INTERNALERROR
+-EPROTO			a) bitstuff error
+			b) unknown USB error 
+
+USB_ST_CRC
+-EILSEQ			CRC mismatch
+
+-EPIPE			a) babble detect
+			b) endpoint stalled
+
+USB_ST_BUFFERUNDERRUN
+-ENOST			buffer error
+
+USB_ST_NORESPONSE
+USB_ST_TIMEOUT
+-ETIMEDOUT		transfer timed out, NAK
+
+USB_ST_REMOVED	
+-ENODEV			device was removed
+
+USB_ST_SHORT_PACKET
+-EREMOTEIO		short packet detected
+
+USB_ST_PARTIAL_ERROR
+-EXDEV			ISO transfer only partially completed
+			look at individual frame status for details
+
+USB_ST_URB_INVALID_ERROR
+-EINVAL			ISO madness, if this happens: Log off and go home
+
+**************************************************************************
+*              Error codes returned by usbcore-functions                 *
+*           (expect also other submit and transfer status codes)         *
+**************************************************************************
+
+usb_register():
+USB_ST_NOTSUPPORTED
+-EINVAL			error during registering new driver
+
+usb_terminate_bulk():
+USB_ST_REMOVED
+-ENODEV			urb already removed
+
+usb_get_*/usb_set_*():
+			All USB errors (submit/status) can occur
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/ibmcam.txt linux.18p8/Documentation/usb/ibmcam.txt
--- linux.vanilla/Documentation/usb/ibmcam.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/ibmcam.txt	Fri Sep  1 13:51:28 2000
@@ -0,0 +1,288 @@
+README for Linux device driver for the IBM "C-It" USB video camera
+
+INTRODUCTION:
+
+This driver does not use all features known to exist in
+the IBM camera. However most of needed features work well.
+
+This driver was developed using logs of observed USB traffic
+which was produced by standard Windows driver (c-it98.sys).
+I did not have data sheets from Xirlink.
+
+Video formats:
+      128x96  [model 1]
+      176x144
+      320x240 [model 2]
+      352x240 [model 2]
+      352x288
+Frame rate: 3 - 30 frames per second (FPS)
+External interface: USB
+Internal interface: Video For Linux (V4L)
+Supported controls:
+- by V4L: Contrast,  Brightness, Color, Hue
+- by driver options: frame rate, lighting conditions, video format,
+                     default picture settings, sharpness.
+
+SUPPORTED CAMERAS:
+
+IBM "C-It" camera, also known as "Xirlink PC Camera"
+The device uses proprietary ASIC (and compression method);
+it is manufactured by Xirlink. See http://www.xirlink.com/
+http://www.ibmpccamera.com or http://www.c-itnow.com/ for
+details and pictures.
+
+The Linux driver was developed with camera with following
+model number (or FCC ID): KSX-XVP510. This camera has three
+interfaces, each with one endpoint (control, iso, iso). This
+type of cameras is referred to as "model 1". These cameras are
+no longer manufactured.
+
+Xirlink now manufactures new cameras which are somewhat different.
+In particular, following models [FCC ID] belong to that category:
+
+XVP300 [KSX-X9903]
+XVP600 [KSX-X9902]
+XVP610 [KSX-X9902]
+
+(see http://www.xirlink.com/ibmpccamera/ for updates, they refer
+to these new cameras by Windows driver dated 12-27-99, v3005 BETA)
+These cameras have two interfaces, one endpoint in each (iso, bulk).
+Such type of cameras is referred to as "model 2". They are supported
+(with exception of 352x288 native mode).
+
+Quirks of Model 2 cameras:
+-------------------------
+
+Model 2 does not have hardware contrast control. Corresponding V4L
+control is not used at the moment. It may be possible to implement
+contrast control in software, at cost of extra processor cycles.
+
+This driver provides 352x288 mode by switching the camera into
+quasi-352x288 RGB mode (800 Kbits per frame) essentially limiting
+this mode to 10 frames per second or less, in ideal conditions on
+the bus (USB is shared, after all). The frame rate
+has to be programmed very conservatively. Additional concern is that
+frame rate depends on brightness setting; therefore the picture can
+be good at one brightness and broken at another! I did not want to fix
+the frame rate at slowest setting, but I had to move it pretty much down
+the scale (so that framerate option barely matters). I also noticed that
+camera after first powering up produces frames slightly faster than during
+consecutive uses. All this means that if you use videosize=2 (which is
+default), be warned - you may encounter broken picture on first connect;
+try to adjust brightness - brighter image is slower, so USB will be able
+to send all data. However if you regularly use Model 2 cameras you may
+prefer videosize=1 which makes perfectly good I420, with no scaling and
+lesser demands on USB (300 Kbits per second, or 26 frames per second).
+
+The camera that I had also has a hardware quirk: if disconnected,
+it needs few minutes to "relax" before it can be plugged in again
+(poorly designed USB processor reset circuit?)
+
+Model 2 camera can be programmed for very high sensitivity (even starlight
+may be enough), this makes it convenient for tinkering with. The driver
+code has enough comments to help a programmer to tweak the camera
+as s/he feels necessary.
+
+WHAT YOU NEED:
+
+- A supported IBM PC (C-it) camera (model 1 or 2)
+
+- A Linux box with USB support (2.3/2.4; 2.2 w/backport may work)
+
+- A Video4Linux compatible frame grabber program such as xawtv.
+  
+HOW TO COMPILE THE DRIVER:
+
+You need to compile the driver only if you are a developer
+or if you want to make changes to the code. Most distributions
+precompile all modules, so you can go directly to the next
+section "HOW TO USE THE DRIVER".
+
+The driver consists of two files in usb/ directory:
+ibmcam.c and ibmcam.h These files are included into the
+Linux kernel build process if you configure the kernel
+for CONFIG_USB_IBMCAM. Run "make xconfig" and in USB section
+you will find the IBM camera driver. Select it, save the
+configuration and recompile.
+
+HOW TO USE THE DRIVER:
+
+I recommend to compile driver as a module. This gives you an
+easier access to its configuration. The camera has many more
+settings than V4L can operate, so some settings are done using
+module options.
+
+Typically module is installed with command 'modprobe', like this:
+
+# modprobe ibmcam framerate=1
+
+Alternatively you can use 'insmod' in similar fashion:
+
+# insmod /lib/modules/2.x.y/usb/ibmcam.o framerate=1
+
+Module can be inserted with camera connected or disconnected.
+
+The driver can have options, though some defaults are provided.
+
+Driver options: (* indicates that option is model-dependent)
+
+Name            Type            Range [default] Example
+--------------  --------------  --------------  ------------------
+debug           Integer         0-9 [0]         debug=1
+flags           Integer         0-0xFF [0]      flags=0x0d
+framerate       Integer         0-6 [2]         framerate=1
+hue_correction  Integer         0-255 [128]     hue_correction=115
+init_brightness Integer         0-255 [128]     init_brightness=100
+init_contrast   Integer         0-255 [192]     init_contrast=200
+init_color      Integer         0-255 [128]     init_color=130
+init_hue        Integer         0-255 [128]     init_hue=115
+lighting        Integer         0-2* [1]        lighting=2
+sharpness       Integer         0-6* [4]        sharpness=3
+videosize       Integer         0-2* [2]        videosize=1
+
+Options for Model 2 only:
+
+Name            Type            Range [default] Example
+--------------  --------------  --------------  ------------------
+init_model2_rg  Integer         0..255 [0x70]   init_model2_rg=128
+init_model2_rg2 Integer         0..255 [0x2f]   init_model2_rg2=50
+init_model2_sat Integer         0..255 [0x34]   init_model2_sat=65
+init_model2_yb  Integer         0..255 [0xa0]   init_model2_yb=200
+
+debug           You don't need this option unless you are a developer.
+                If you are a developer then you will see in the code
+                what values do what. 0=off.
+
+flags           This is a bit mask, and you can combine any number of
+                bits to produce what you want. Usually you don't want
+                any of extra features this option provides:
+
+                FLAGS_RETRY_VIDIOCSYNC  1  This bit allows to retry failed
+                                           VIDIOCSYNC ioctls without failing.
+                                           Will work with xawtv, will not
+                                           with xrealproducer. Default is
+                                           not set.
+                FLAGS_MONOCHROME        2  Activates monochrome (b/w) mode.
+                FLAGS_DISPLAY_HINTS     4  Shows colored pixels which have
+                                           magic meaning to developers.
+                FLAGS_OVERLAY_STATS     8  Shows tiny numbers on screen,
+                                           useful only for debugging.
+                FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
+                FLAGS_SEPARATE_FRAMES   32 Shows each frame separately, as
+                                           it was received from the camera.
+                                           Default (not set) is to mix the
+                                           preceding frame in to compensate
+                                           for occasional loss of Isoc data
+                                           on high frame rates.
+                FLAGS_CLEAN_FRAMES      64 Forces "cleanup" of each frame
+                                           prior to use; relevant only if
+                                           FLAGS_SEPARATE_FRAMES is set.
+                                           Default is not to clean frames,
+                                           this is a little faster but may
+                                           produce flicker if frame rate is
+                                           too high and Isoc data gets lost.
+
+framerate       This setting controls frame rate of the camera. This is
+                an approximate setting (in terms of "worst" ... "best")
+                because camera changes frame rate depending on amount
+                of light available. Setting 0 is slowest, 6 is fastest.
+                Beware - fast settings are very demanding and may not
+                work well with all video sizes. Be conservative.
+
+hue_correction  This highly optional setting allows to adjust the
+                hue of the image in a way slightly different from
+                what usual "hue" control does. Both controls affect
+                YUV colorspace: regular "hue" control adjusts only
+                U component, and this "hue_correction" option similarly
+                adjusts only V component. However usually it is enough
+                to tweak only U or V to compensate for colored light or
+                color temperature; this option simply allows more
+                complicated correction when and if it is necessary.
+
+init_brightness These settings specify _initial_ values which will be
+init_contrast   used to set up the camera. If your V4L application has
+init_color      its own controls to adjust the picture then these
+init_hue        controls will be used too. These options allow you to
+                preconfigure the camera when it gets connected, before
+                any V4L application connects to it. Good for webcams.
+
+init_model2_rg  These initial settings alter color balance of the
+init_model2_rg2 camera on hardware level. All four settings may be used
+init_model2_sat to tune the camera to specific lighting conditions. These
+init_model2_yb  settings only apply to Model 2 cameras.
+
+lighting        This option selects one of three hardware-defined
+                photosensitivity settings of the camera. 0=bright light,
+                1=Medium (default), 2=Low light. This setting affects
+                frame rate: the dimmer the lighting the lower the frame
+                rate (because longer exposition time is needed). The
+                Model 2 cameras allow values more than 2 for this option,
+                thus enabling extremely high sensitivity at cost of frame
+                rate, color saturation and imaging sensor noise.
+
+sharpness       This option controls smoothing (noise reduction)
+                made by camera. Setting 0 is most smooth, setting 6
+                is most sharp. Be aware that CMOS sensor used in the
+                camera is pretty noisy, so if you choose 6 you will
+                be greeted with "snowy" image. Default is 4. Model 2
+                cameras do not support this feature.
+
+videosize       This setting chooses one if three image sizes that are
+                supported by this driver. Camera supports more, but
+                it's difficult to reverse-engineer all formats.
+                Following video sizes are supported:
+
+                videosize=0     128x96  (Model 1 only)
+                videosize=1     176x144
+                videosize=2     352x288
+                videosize=3     320x240 (Model 2 only)
+                videosize=4     352x240 (Model 2 only)
+
+                The last one (352x288) is the native size of the sensor
+                array, so it's the best resolution camera (Model 1) can
+                yield. The best resolution of Model 2 is 176x144, and
+                larger images are produced by stretching the bitmap.
+                Choose the image size you need. The smaller image can
+                support faster frame rate. Default is 352x288.
+
+WHAT NEEDS TO BE DONE:
+
+- The box freezes if camera is unplugged after being used (OHCI).
+  Workaround: remove usb-ohci module first.
+- On occasion camera (model 1) does not start properly (xawtv reports
+  errors), or camera produces negative image (funny colors.)
+  Workaround: reload the driver module. Reason: [1].
+- The button on the camera is not used. I don't know how to get to it.
+  I know now how to read button on Model 2, but what to do with it?
+
+[1]
+- Camera reports its status back to the driver; however I don't know
+  what returned data means. If camera fails at some initialization
+  stage then something should be done, and I don't do that because
+  I don't even know that some command failed. This is mostly Model 1
+  concern because Model 2 uses different commands which do not return
+  status (and seem to complete successfully every time).
+
+VIDEO SIZE AND IMAGE SIZE
+
+Camera produces picture X by Y pixels. This is camera-specific and can be
+altered by programming the camera accordingly. This image is placed onto
+larger (or equal) area W by H, this is V4L image. At this time the driver
+uses V4L image size (W by H) 352x288 pixels because many programs (such
+as xawtv) expect quite specific sizes and don't want to deal with arbitrary,
+camera-specific sizes. However this approach "hides" real image size, and
+application always sees the camera as producing only 352x288 image. It is
+possible to change the V4L image size to 128x96, and then if camera is
+switched to 128x96 mode then xawtv will correctly accept this image size. But
+many other popular sizes (such as 176x144) will not be welcomed. This is the
+reason why all camera images are at this time placed onto 352x288 "canvas",
+and size of that canvas (V4L) is reported to applications. It will be easy
+to add options to control the canvas size, but it will be application-
+specific because not all applications are ready to work with variety of
+camera-specific sizes.
+
+CREDITS:
+
+The code is based in no small part on the CPiA driver by Johannes Erdfelt,
+Randy Dunlap, and others. Big thanks to them for their pioneering work on that
+and the USB stack.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/input.txt linux.18p8/Documentation/usb/input.txt
--- linux.vanilla/Documentation/usb/input.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/input.txt	Thu Sep 14 15:35:24 2000
@@ -0,0 +1,306 @@
+			  Linux Input drivers v1.0
+	       (c) 1999-2000 Vojtech Pavlik <vojtech@suse.cz>
+			     Sponsored by SuSE
+	    $Id: input.txt,v 1.4 2000/05/28 17:57:22 vojtech Exp $
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+  This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your option)
+any later version.
+
+  This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+more details.
+
+  You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc., 59
+Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+  Should you need to contact me, the author, you can do so either by e-mail
+- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, Prague 8, 182 00 Czech Republic
+
+  For your convenience, the GNU General Public License version 2 is included
+in the package: See the file COPYING.
+
+1. Introduction
+~~~~~~~~~~~~~~~
+  This is a collection of drivers that is designed to support all input
+devices under Linux. However, in the current kernels, although it's
+possibilities are much bigger, it's limited to USB devices only. This is
+also why it resides in the drivers/usb subdirectory.
+
+  The center of the input drivers is the input.o module, which must be
+loaded before any other of the input modules - it serves as a way of
+communication between two groups of modules:
+
+1.1 Device drivers
+~~~~~~~~~~~~~~~~~~
+  These modules talk to the hardware (for example via USB), and provide
+events (keystrokes, mouse movements) to the input.o module.
+
+1.2 Event handlers
+~~~~~~~~~~~~~~~~~~
+  These modules get events from input.o and pass them where needed via
+various interfaces - keystrokes to the kernel, mouse movements via a
+simulated PS/2 interface to GPM and X and so on.
+
+2. Simple Usage
+~~~~~~~~~~~~~~~
+  For the most usual configuration, with one USB mouse and one USB keyboard,
+you'll have to load the following modules (or have them built in to the
+kernel):
+
+	input.o
+	mousedev.o
+	keybdev.o
+	usbcore.o
+	usb-[uo]hci.o
+	hid.o
+
+  After this, the USB keyboard will work straight away, and the USB mouse
+will be available as a character device on major 13, minor 63:
+
+	crw-r--r--   1 root     root      13,  63 Mar 28 22:45 mice
+
+  This device, has to be created, unless you use devfs, in which case it's
+created automatically. The commands to do that are:
+
+	cd /dev
+	mkdir input
+	mknod input/mice c 13 63
+
+  After that you have to point GPM (the textmode mouse cut&paste tool) and
+XFree to this device to use it - GPM should be called like:
+
+	gpm -t ps2 -m /dev/input/mice
+
+  And in X:
+
+	Section "Pointer"
+	    Protocol    "ImPS/2"
+	    Device      "/dev/input/mice"
+	    ZAxisMapping 4 5
+	EndSection
+
+  When you do all of the above, you can use your USB mouse and keyboard.
+
+3. Detailed Description
+~~~~~~~~~~~~~~~~~~~~~~~
+3.1 Device drivers
+~~~~~~~~~~~~~~~~~~
+  Device drivers are the modules that generate events. The events are
+however not useful without being handled, so you also will need to use some
+of the modules from section 3.2.
+
+3.1.1 hid.c
+~~~~~~~~~~~
+  Hid.c is the largest and most complex driver of the whole suite. It
+handles all HID devices, and because there is a very wide variety of them,
+and because the USB HID specification isn't simple, it needs to be this big.
+
+  Currently, it handles USB mice, joysticks, gamepads, steering wheels
+keyboards, trackballs and digitizers.
+
+ However, USB uses HID also for monitor controls, speaker controls, UPSs,
+LCDs and many other purposes.
+
+ The monitor and speaker controls should be easy to add to the hid/input
+interface, but for the UPSs and LCDs it doesn't make much sense. The driver
+doesn't support these yet, and a new, non-event interface should be designed
+for them. If you have any of these devices (I don't), feel free to design
+something and if it's good, it'll get into the driver.
+
+  The usage of the hid.o module is very simple, it takes no parameters,
+detects everything automatically and when a HID device is inserted, it
+detects it appropriately.
+
+  However, because the devices vary wildly, you might happen to have a
+device that doesn't work well. In that case #define DEBUG at the beginning
+of hid.c and send me the syslog traces.
+
+3.1.2 usbmouse.c
+~~~~~~~~~~~~~~~~
+  For embedded systems, for mice with broken HID descriptors and just any
+other use when the big hid.c wouldn't be a good choice, there is the
+usbmouse.c driver. It handles USB mice only. It uses a simpler HIDBP
+protocol. This also means the mice must support this simpler protocol. Not
+all do. If you don't have any strong reason to use this module, use hid.c
+instead.
+
+3.1.3 usbkbd.c
+~~~~~~~~~~~~~~
+  Much like usbmouse.c, this module talks to keyboards with a simplified
+HIDBP protocol. It's smaller, but doesn't support any extra special keys.
+Use hid.c instead if there isn't any special reason to use this.
+
+3.1.4 wacom.c
+~~~~~~~~~~~~~
+  This is a driver for Wacom Graphire and Intuos tablets. Not for Wacom
+PenPartner, that one is handled by the HID driver. Although the Intuos and
+Graphire tablets claim that they are HID tablets as well, they are not and
+thus need this specific driver.
+
+3.1.5 wmforce.c
+~~~~~~~~~~~~~~~
+  A driver for the Logitech WingMan Force joysticks, when connected via the
+USB port. It works quite well, but there is no force feedback support yet,
+because the interface to do that is a trade secret of Immersion Corp, and
+even Logitech can't disclose it.
+
+  Support for Logitech WingMan Force Wheel isn't present in this driver, but
+if someone has the device, and is willing to cooperate, it should be a
+matter of a couple days to add it.
+
+3.2 Event handlers
+~~~~~~~~~~~~~~~~~~
+  Event handlers distribute the events from the devices to userland and
+kernel, as needed.
+
+3.2.1 keybdev.c
+~~~~~~~~~~~~~~~
+  Keybdev is currently a rather ugly hack that translates the input events
+into architecture-specific keyboard raw mode (Xlated AT Set2 on x86), and
+passes them into the handle_scancode function of the keyboard.c module. This
+works well enough on all architectures that keybdev can generate rawmode on,
+other architectures can be added to it.
+
+  The right way would be to pass the events to keyboard.c directly, best if
+keyboard.c would itself be an event handler. This is done in the input
+patch, available on the webpage mentioned below.
+
+3.2.2 mousedev.c
+~~~~~~~~~~~~~~~~
+  Mousedev is also a hack to make programs that use mouse input work. It
+takes events from either mice or digitizers/tablets and makes a PS/2-style
+(a la /dev/psaux) mouse device available to the userland. Ideally, the
+programs could use a more reasonable interface, for example evdev.c
+
+  Mousedev devices in /dev/input (as shown above) are:
+
+	crw-r--r--   1 root     root      13,  32 Mar 28 22:45 mouse0
+	crw-r--r--   1 root     root      13,  33 Mar 29 00:41 mouse1
+	crw-r--r--   1 root     root      13,  34 Mar 29 00:41 mouse2
+	crw-r--r--   1 root     root      13,  35 Apr  1 10:50 mouse3
+	...
+	...
+	crw-r--r--   1 root     root      13,  62 Apr  1 10:50 mouse30
+	crw-r--r--   1 root     root      13,  63 Apr  1 10:50 mice
+
+Each 'mouse' device is assigned to a single mouse or digitizer, except the last
+one - 'mice'. This single character device is shared by all mice and
+digitizers, and even if none are connected, the device is present.  This is
+useful for hotplugging USB mice, so that programs can open the device even when
+no mice are present.
+
+  CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size
+of your screen (in pixels) in XFree86. This is needed if you want to use
+your digitizer in X, because it's movement is sent to X via a virtual PS/2
+mouse and thus needs to be scaled accordingly. These values won't be used if
+you use a mouse only.
+
+  Mousedev will generate either PS/2, ImPS/2 (Microsoft IntelliMouse) or
+GenPS/2 (Genius NetMouse/NetScroll) protocols, depending on what the program
+reading the data wishes. You can set GPM and X to any of these. You'll need
+ImPS/2 if you want to make use of a wheel on a USB mouse and GenPS/2 if you
+want to use extra (up to 5) buttons. I'm not sure how much is GenPS/2 supported
+in X, though.
+
+3.2.3 joydev.c
+~~~~~~~~~~~~~~
+  Joydev implements v0.x and v1.x Linux joystick api, much like
+drivers/char/joystick/joystick.c. See joystick-api.txt in the Documentation
+subdirectory for details. Joydev does it on top of the input subsystem,
+though. As soon as any USB joystick is connected, it can be accessed in
+/dev/input on:
+
+	crw-r--r--   1 root     root      13,   0 Apr  1 10:50 js0
+	crw-r--r--   1 root     root      13,   1 Apr  1 10:50 js1
+	crw-r--r--   1 root     root      13,   2 Apr  1 10:50 js2
+	crw-r--r--   1 root     root      13,   3 Apr  1 10:50 js3
+	...
+
+And so on up to js31.
+
+3.2.4 evdev.c
+~~~~~~~~~~~~~
+  Evdev is the generic input event interface. It passes the events generated
+in the kernel straight to the program, with timestamps. The API is still
+evolving, but should be usable now. It's described in section 5.
+
+  This should be the way for GPM and X to get keyboard and mouse mouse
+events. It allows for multihead in X without any specific multihead kernel
+support. The event codes are the same on all architectures and are hardware
+independent.
+
+  The devices are in /dev/input:
+
+	crw-r--r--   1 root     root      13,  64 Apr  1 10:49 event0
+	crw-r--r--   1 root     root      13,  65 Apr  1 10:50 event1
+	crw-r--r--   1 root     root      13,  66 Apr  1 10:50 event2
+	crw-r--r--   1 root     root      13,  67 Apr  1 10:50 event3
+	...
+
+3. Contacts
+~~~~~~~~~~~
+  This effort has it's home page at:
+
+	http://www.suse.cz/development/input/
+
+You'll find both the latest HID driver and the complete Input driver there
+as well as information how to access the CVS repository for latest revisions
+of the drivers.
+
+
+  There is also a mailing list for this:
+
+	majordomo@atrey.karlin.mff.cuni.cz
+
+Send "subscribe linux-input" to subscribe to it.
+
+4. Verifying if it works
+~~~~~~~~~~~~~~~~~~~~~~~~
+  Typing a couple keys on the keyboard should be enough to check that a USB
+keyboard works and is correctly connected to the kernel keyboard driver.
+
+  Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse is also
+emulated, characters should appear if you move it.
+
+  You can test the joystick emulation with the 'jstest' utility, available
+in the joystick package (see Documentation/joystick.txt).
+
+  You can test the event devics with the 'evtest' utility available on the
+input driver homepage (see the URL above).
+
+5. Event interface
+~~~~~~~~~~~~~~~~~~
+  Should you want to add event device support into any application (X, gpm,
+svgalib ...) I <vojtech@suse.cz> will be happy to provide you any help I
+can. Here goes a description of the current state of things, which is going
+to be extended, but not changed incompatibly as time goes:
+
+  You can use blocking and nonblocking reads, also select() on the
+/dev/input/eventX devices, and you'll always get a whole number of input
+events on a read. Their layout is:
+
+struct input_event {
+	struct timeval time;
+	unsigned short type;
+	unsigned short code;
+	unsigned int value;
+};
+
+  'time' is the timestamp, it returns the time at which the event happened.
+Type is for example EV_REL for relative movement, REL_KEY for a keypress or
+release. More types are defined in include/linux/input.h.
+
+  'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
+list is in include/linux/input.h.
+
+  'value' is the value the event carries. Either a relative change for
+EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
+release, 1 for keypress and 2 for autorepeat.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/ohci.txt linux.18p8/Documentation/usb/ohci.txt
--- linux.vanilla/Documentation/usb/ohci.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/ohci.txt	Thu Sep 14 15:35:24 2000
@@ -0,0 +1,98 @@
+
+The OHCI HCD layer is a simple but nearly complete implementation of what the
+USB people would call a HCD  for the OHCI. 
+ (ISO coming soon, Bulk, INT u. CTRL transfers enabled)
+It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
+The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. 
+
+- Roman Weissgaerber <weissg@vienna.at>
+
+ * v4.0 1999/08/18 removed all dummy eds, unlink unused eds, code cleanup, bulk transfers 
+ * v2.1 1999/05/09 ep_addr correction, code cleanup
+ * v0.2.0 1999/05/04 
+ * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
+ * virtual root hub is now an option, 
+ * memory allocation based on kmalloc and kfree now, simple Bus error handling, 
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * 
+ * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
+ * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
+ * 
+ * v0.1.0 1999/04/27 initial release
+ 
+to remove the module try:
+rmmod usb-ohci
+
+Features:
+- virtual root hub, all basic hub descriptors and commands (state: complete) 
+  this is an option now (v0.2.0)
+  #define  CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
+  default is with. 
+  (at the moment: the Virtual Root Hub is included automatically)
+  
+  files: ohci-root-hub.c, ohci-root-hub.h 
+ 
+
+- Endpoint Descriptor (ED) handling more static approach 
+ (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
+ as long as the function (device) is alive or another configuration is chosen.
+ In the HCD layer the EDs has to be allocated manually either by calling a subroutine
+ or by sending a USB root hub vendor specific command to the virtual root hub.
+ At the alternate linux usb stack EDs will be added (allocated) at their first use.
+ ED will be unlinked from the HC chains if they are not busy.
+ 
+ files: ohci-hcd.c ohci-hcd.h
+ routines:   (do not use for drivers, use the top layer alternate usb commands instead)
+ 
+ int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, 
+            int interval, int load, f_handler handler, int ep_size, int speed)
+       adds an endpoint, (if the endpoint already exists some parameters will be updated)
+       
+ int usb_ohci_rm_ep( ) 
+       removes an endpoint and all pending TDs of that EP
+       
+  usb_ohci_rm_function( )
+       removes all Endpoints of a function (device)
+
+- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
+  The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
+  to take care of buffer allocation.
+  files: ohci-hcd.c ohci-hcd.h 
+
+  There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
+  
+  int ohci_trans_req(struct ohci * ohci, hcd_ed, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
+  
+  CTRL: ctrl, ctrl_len ... cmd buffer 
+        data, data_len ... data buffer (in or out)
+  INT, BULK:  ctrl = NULL, ctrl_len=0,
+  		data, data_len ... data buffer (in or out)
+  ISO: tbd
+
+  There is no buffer reinsertion done by the internal HCD function. 
+  (The interface layer does this for a INT-pipe on request.)
+  If you want a transfer then you have to 
+  provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
+  you can send as many as you like. They should come back by the callback f_handler in
+  the same order (for each endpoint, not globally) If an error occurs all
+  queued transfers of an endpoint will return unsent. They will be marked with an error status.
+  
+  e.g double-buffering for int transfers:
+
+   	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  and when a data0 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  and when a data1 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
+  The alternate usb uses them for dev_id and usb_device_irq handler.
+
+
+- Done list handling: returns the requests (callback f_handler in ED) and does 
+  some error handling, root-hub request dequeuing
+  (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
+
+  
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/ov511.txt linux.18p8/Documentation/usb/ov511.txt
--- linux.vanilla/Documentation/usb/ov511.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/ov511.txt	Fri Sep 15 12:49:09 2000
@@ -0,0 +1,254 @@
+-------------------------------------------------------------------------------
+Readme for Linux device driver for the OmniVision OV511 USB to camera bridge IC
+-------------------------------------------------------------------------------
+
+Author: Mark McClelland
+Homepage: http://alpha.dyndns.org/ov511
+
+NEW IN THIS VERSION:
+ o Stability improvements
+ o Support for hue control
+ o 160x120 mostly working
+ o OV6620 color problems fixed
+ o MoreWebCam 3 detection improvements
+
+INTRODUCTION:
+
+This is a driver for the OV511, a USB-only chip used in many "webcam" devices.
+Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. It 
+supports streaming and capture of color or monochrome video via the Video4Linux
+API. Most V4L apps are compatible with it, but a few videoconferencing programs
+do not work yet. The following resolutions are supported: 640x480, 448x336,
+384x288, 352x288, and 320x240.
+
+WHAT YOU NEED:
+
+- If you want to help with the development, get the chip's specification docs at
+  http://www.ovt.com/omniusbp.html
+
+- A Video4Linux compatible frame grabber program (I recommend vidcat and xawtv)
+    vidcat is part of the w3cam package:  http://www.hdk-berlin.de/~rasca/w3cam/
+    xawtv is available at:  http://www.in-berlin.de/User/kraxel/xawtv.html
+
+HOW TO USE IT:
+
+You must have first compiled USB support, support for your specific USB host
+controller (UHCI or OHCI), and Video4Linux support for your kernel (I recommend
+making them modules.)
+
+Next, (as root) from your appropriate modules directory (lib/modules/2.3.XX):
+
+	insmod usb/usbcore.o
+	insmod usb/usb-uhci.o  <OR>  insmod usb/ohci-hcd.o
+	insmod misc/videodev.o
+	insmod usb/ov511.o
+
+If it is not already there (it usually is), create the video device:
+
+	mknod /dev/video c 81 0
+
+Sometimes /dev/video is a symlink to /dev/video0
+
+You will have to set permissions on this device to allow you to read/write
+from it:
+
+	chmod 666 /dev/video
+	chmod 666 /dev/video0 (if necessary)
+	
+Now you are ready to run a video app! Both vidcat and xawtv work well for me
+at 640x480.
+	
+[Using vidcat:]
+
+	vidcat -s 640x480 > test.jpg
+	xview test.jpg
+	
+[Using xawtv:]
+
+You must make some modifications to the source and compile it before you use it.
+(Note: this may not be applicable to versions other than 3.06)
+
+In src/Xawtv.ad, change xawtv.tv.width to 640 and xawtv.tv.height to 480. Next,
+in src/grab-v4l.c, change SYNC_TIMEOUT from 1 to 2. Then, from the main xawtv
+directory:
+
+	make clean
+	./configure
+	make
+	make install
+
+Now you should be able to run xawtv. Right click for the options dialog. If
+you get a scrambled image it is likely that you made a mistake in Xawtv.ad.
+Try setting the size to 320x240 if all else fails.
+
+FAQ:
+Q: "Why does the picture have noise and look grainy"
+A: This is a problem at low light levels, and may be also due to subtle bugs in
+   the code. The cause is most likely the OV7610 settings we are currently
+   using. I am looking into this problem.
+
+Q: "The driver sometimes says `Failed to read OV7610 ID.' What is the deal?"
+A: The I2C code that allows the OV511 to communicate with the camera chip is a
+   bit flaky right now. This message means that the I2C bus never got
+   initialized properly, and the camera will most likely not work even if you
+   disable this warning. Try unloading/reloading the driver or unplugging/re-
+   plugging the camera if this happens. Also try increasing the i2c_detect_tries
+   parameter (see below).
+
+Q: "Why do you bother with this phony camera detection crap? It doesn't do
+    anything useful!"
+A: The main purpose of only supporting known camera models is to force people
+   with new camera models to tell me about them, so I can assemble the list
+   above, and so the code can know what CCD chip you have. Right now, nearly all
+   of the cameras use the OV7610 and consequently I have not put support for
+   other ones in, so the value of the detection code is questionable. Eventually
+   though, new CCDs might appear and we will be fortunate to have the detection.
+
+MODULE PARAMETERS:
+
+  You can set these with:  insmod ov511 NAME=VALUE
+  There is currently no way to set these on a per-camera basis.
+
+  NAME: autoadjust
+  TYPE: integer (boolean)
+  DEFAULT: 1
+  DESC: The camera normally adjusts exposure, gain, and hue automatically. This
+        can be set to 0 to disable this automatic adjustment. Note that there is
+        currently no way to set these parameters manually once autoadjust is
+        disabled.
+
+  NAME: debug
+  TYPE: integer (0-6)
+  DEFAULT: 3
+  DESC: Sets the threshold for printing debug messages. The higher the value,
+        the more is printed. The levels are cumulative, and are as follows:
+          0=no debug messages
+          1=init/detection/unload and other significant messages
+          2=some warning messages
+          3=config/control function calls
+          4=most function calls and data parsing messages
+          5=highly repetitive mesgs
+
+  NAME: fix_rgb_offset
+  TYPE: integer (boolean)
+  DEFAULT: 0
+  DESC: Some people have reported that the blue component of the image is one
+        or so lines higher than the red component. This is only apparent in 
+        images with white objects on black backgrounds at 640x480. Setting this
+        to 1 will realign the color planes correctly. NOTE: This is still
+        experimental and very buggy. You will likely need a fast (500 Mhz) CPU.
+
+  NAME: snapshot
+  TYPE: integer (boolean)
+  DEFAULT: 0
+  DESC: Set to 1 to enable snapshot mode. read() will block until the snapshot
+        button is pressed. Note that this does not yet work with most apps,
+        including xawtv and vidcat. NOTE: See the section "TODO" for more info.
+
+  NAME: sensor
+  TYPE: integer ([0, 1, 3])
+  DEFAULT: [varies]
+  DESC: If you know that your camera sensor is not detected correctly, set this
+        parameter. This is a global option for all attached OV511 cameras. You
+        will probably never need to set this, but if you do, valid values are:
+        	0 for OV7620
+        	1 for OV7620AE
+        	3 for OV7610
+
+  NAME: i2c_detect_tries
+  TYPE: integer (don't set it insanely high!)
+  DEFAULT: 5
+  DESC: This is the number of times the driver will try to sync and detect the
+        internal i2c bus (which connects the OV511 and sensor). If you are
+        getting intermittent detection failures ("Failed to read sensor ID...")
+        you should increase this by a modest amount. If setting it to 20 or so
+        doesn't fix things, look elsewhere for the cause of the problem.
+
+  NAME: aperture
+  TYPE: integer (0 - 15)
+  DEFAULT: [varies by sensor]
+  DESC: For legal values, see the OV7610/7620 specs under register Common F.
+        This setting affects the upper nybble of that reg (bits 4-7). This is
+        for if you want to play with the camera's pixel saturation.
+
+  NAME: force_rgb
+  TYPE: integer (boolean)
+  DEFAULT: 0
+  DESC: Force image to be read in RGB instead of BGR. This option allow
+        programs that expect RGB data (e.g. gqcam) to work with this driver. If
+        your colors look VERY wrong, you may want to change this.
+
+  NAME: buf_timeout
+  TYPE: integer
+  DEFAULT: 5 (seconds)
+  DESC: Number of seconds before unused frame buffers are deallocated.
+        Previously, memory was allocated upon open() and deallocated upon
+        close(). Deallocation now occurs only if the driver is closed and this
+        timeout is reached. If you are capturing frames less frequently than
+        the default timeout, increase this. This will not make any difference
+        with programs that capture multiple frames during an open/close cycle.
+
+  NAME: cams
+  TYPE: integer (1-4 for OV511, 1-31 for OV511+)
+  DEFAULT: 1
+  DESC: Number of cameras allowed to stream simultaneously on a single bus.
+        Values higher than 1 reduce the data rate of each camera, allowing two
+        or more to be used at once. If you have a complicated setup involving
+        both OV511 and OV511+ cameras, trial-and-error may be necessary for
+        finding the optimum setting.
+
+  NAME: retry_sync
+  TYPE: boolean
+  DEFAULT: 0
+  DESC: Prevent apps from timing out if frame is not done in time. This is
+        useful if you are having problems with Xawtv getting "stuck" on a frame
+        when your system is under heavy load.
+ 
+WORKING FEATURES:
+ o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, 320x240, and
+   160x120
+ o RGB24, YUV420, YUV422, YUYV, and YUV422P color
+ o Monochrome
+ o Setting/getting of saturation, contrast, brightness, and hue (only some of
+   them work the OV7620 and OV7620AE)
+ o proc status reporting
+
+EXPERIMENTAL FEATURES:
+ o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and
+   corrupted frames. If you have a very fast CPU, you can try it.
+ o Snapshot mode (only works with some read() based apps; see below for more)
+ o OV6620 sensor support
+ o GBR422 parsing
+
+TODO:
+ o Fix the noise / grainy image problem.
+ o Get compression working. It would be a nice addition as it improves
+   frame rate quite a bit. OmniVision wouldn't tell me how the algorithm works,
+   so we can't really work on that yet. Please kindly inform OmniVision that you
+   would like them to release their specifications to the Linux community.
+ o YUV422
+ o Get snapshot mode working with mmap().
+ o Fix fixFrameRGBoffset(). It is not stable yet with streaming video.
+ o Get autoadjust disable working
+ o V4L2 support (Probably not until it goes into the kernel)
+ o Creative WebCam III has problems initializing its sensor. This should be
+   fixed now, but if you still have problems let me know.
+ o Get rid of the memory management functions (put them in videodev.c??)
+ o Setting of contrast and brightness not working with 7620/7620AE
+ o Driver/camera state save/restore for when USB supports suspend/resume
+ o Unstable on SMP systems
+ o OV7620/OV6620 experience frame corruption with moving objects
+ o OV6620 is too dark
+
+HOW TO CONTACT ME:
+
+You can email me at mwm@i.am . Please prefix the subject line
+with "OV511: " so that I am certain to notice your message.
+
+CREDITS:
+
+The code is based in no small part on the CPiA driver by Johannes Erdfelt,
+Randy Dunlap, and others. Big thanks to them for their pioneering work on that
+and the USB stack. Thanks to Bret Wallach for getting camera reg IO, ISOC, and
+image capture working. Thanks to Orion Sky Lawlor, Kevin Moore, and Claudio
+Matsuoka for their work as well.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/proc_usb_info.txt linux.18p8/Documentation/usb/proc_usb_info.txt
--- linux.vanilla/Documentation/usb/proc_usb_info.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/proc_usb_info.txt	Thu Sep 14 15:35:24 2000
@@ -0,0 +1,273 @@
+/proc/bus/usb filesystem output
+===============================
+(version 2000.08.15)
+
+
+The /proc filesystem for USB devices generates
+/proc/bus/usb/drivers and /proc/bus/usb/devices.
+
+/proc/bus/usb/drivers lists the registered drivers,
+one per line, with each driver's USB minor dev node
+number range if applicable.
+
+**NOTE**: If /proc/bus/usb appears empty, you need
+          to mount the filesystem, issue the command (as root):
+
+      mount -t usbdevfs none /proc/bus/usb
+
+	  An alternative and more permanent method would be to add
+
+      none  /proc/bus/usb  usbdevfs  defaults  0  0
+
+	  to /etc/fstab.  This will mount usbdevfs at each reboot.
+	  You can then issue `cat /proc/bus/usb/devices` to extract
+	  USB device information.
+
+For more information on mounting the usbdevfs file system, see the
+"USB Device Filesystem" section of the USB Guide. The latest copy 
+of the USB Guide can be found at http://www.linux-usb.org/
+
+In /proc/bus/usb/devices, each device's output has multiple
+lines of ASCII output.
+I made it ASCII instead of binary on purpose, so that someone
+can obtain some useful data from it without the use of an
+auxiliary program.  However, with an auxiliary program, the numbers
+in the first 4 columns of each "T:" line (topology info:
+Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
+(I think.  I haven't proved this, but I have tested it with 3
+different topo/connections and it looked possible.)
+
+Each line is tagged with a one-character ID for that line:
+
+T = Topology (etc.)
+B = Bandwidth (applies only to USB host controllers, which are
+    virtualized as root hubs)
+D = Device descriptor info.
+P = Product ID info. (from Device descriptor, but they won't fit
+    together on one line)
+S = String descriptors.
+C = Configuration descriptor info. (* = active configuration)
+I = Interface descriptor info.
+E = Endpoint descriptor info.
+
+=======================================================================
+
+/proc/bus/usb/devices output format:
+
+Legend:
+  d = decimal number (may have leading spaces or 0's)
+  x = hexadecimal number (may have leading spaces or 0's)
+  s = string
+
+
+Topology info:
+
+T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
+|   |      |      |       |       |      |        |       |__MaxChildren
+|   |      |      |       |       |      |        |__Device Speed in Mbps
+|   |      |      |       |       |      |__DeviceNumber
+|   |      |      |       |       |__Count of devices at this level
+|   |      |      |       |__Connector/Port on Parent for this device
+|   |      |      |__Parent DeviceNumber
+|   |      |__Level in topology for this bus
+|   |__Bus number
+|__Topology info tag
+
+
+Bandwidth info:
+B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
+|   |                       |         |__Number if isochronous requests
+|   |                       |__Number of interrupt requests
+|   |__Total Bandwidth allocated to this bus
+|__Bandwidth info tag
+
+
+Device descriptor info & Product ID info:
+
+D:  Ver=x.xx Cls=xx(s) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
+P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
+
+where
+D:  Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
+|   |        |             |      |       |       |__NumberConfigurations
+|   |        |             |      |       |__MaxPacketSize of Default Endpoint
+|   |        |             |      |__DeviceProtocol
+|   |        |             |__DeviceSubClass
+|   |        |__DeviceClass
+|   |__Device USB version
+|__Device info tag #1
+
+where
+P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
+|   |           |           |__Product revision number
+|   |           |__Product ID code
+|   |__Vendor ID code
+|__Device info tag #2
+
+
+String descriptor info:
+
+S:  Manufacturer=ssss
+|   |__Manufacturer of this device as read from the device.
+|__String info tag
+
+S:  Product=ssss
+|   |__Product description of this device as read from the device,
+|      except that it is a generated string for USB host controllers
+|      (virtual root hubs), in the form "USB *HCI Root Hub".
+|__String info tag
+
+S:  SerialNumber=ssss
+|   |__Serial Number of this device as read from the device,
+|      except that it is a generated string for USB host controllers
+|      (virtual root hubs), and represents the host controller's
+|      unique identification in the system (currently I/O or
+|      memory-mapped base address).
+|__String info tag
+
+
+Configuration descriptor info:
+
+C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
+|   |       |       |      |__MaxPower in mA
+|   |       |       |__Attributes
+|   |       |__ConfiguratioNumber
+|   |__NumberOfInterfaces
+|__Config info tag
+
+
+Interface descriptor info (can be multiple per Config):
+
+I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
+|   |      |      |       |             |      |       |__Driver name
+|   |      |      |       |             |      |__InterfaceProtocol
+|   |      |      |       |             |__InterfaceSubClass
+|   |      |      |       |__InterfaceClass
+|   |      |      |__NumberOfEndpoints
+|   |      |__AlternateSettingNumber
+|   |__InterfaceNumber
+|__Interface info tag
+
+
+Endpoint descriptor info (can be multiple per Interface):
+
+E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
+E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
+|   |        |            |         |__Interval
+|   |        |            |__EndpointMaxPacketSize
+|   |        |__Attributes(EndpointType)
+|   |__EndpointAddress(I=In,O=Out)
+|__Endpoint info tag
+
+=======================================================================
+
+
+If a user or script is interested only in Topology info, for
+example, use something like "grep ^T: /proc/bus/usb/devices"
+for only the Topology lines.  A command like
+"grep -i ^[tdp]: /proc/bus/usb/devices" can be used to list
+only the lines that begin with the characters in square brackets,
+where the valid characters are TDPCIE.  With a slightly more able
+script, it can display any selected lines (for example, only T, D,
+and P lines) and change their output format.  (The "procusb"
+Perl script is the beginning of this idea.  It will list only
+selected lines [selected from TBDPSCIE] or "All" lines from
+/proc/bus/usb/devices.)
+
+The Topology lines can be used to generate a graphic/pictorial
+of the USB devices on a system's root hub.  (See more below
+on how to do this.)
+
+The Interface lines can be used to determine what driver is
+being used for each device.
+
+The Configuration lines could be used to list maximum power
+(in milliamps) that a system's USB devices are using.
+For example, "grep ^C: /proc/bus/usb/devices".
+
+
+Here's an example, from a system which has a UHCI root hub,
+an external hub connected to the root hub, and a mouse and
+a serial converter connected to the external hub.
+
+T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
+B:  Alloc= 28/900 us ( 3%), #Int=  2, #Iso=  0
+D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0000 ProdID=0000 Rev= 0.00
+S:  Product=USB UHCI Root Hub
+S:  SerialNumber=dce0
+C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr=  0mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
+E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl=255ms
+T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
+D:  Ver= 1.00 Cls=09(hub  ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0451 ProdID=1446 Rev= 1.00
+C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr=100mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
+E:  Ad=81(I) Atr=03(Int.) MxPS=   1 Ivl=255ms
+T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
+D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=04b4 ProdID=0001 Rev= 0.00
+C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=mouse
+E:  Ad=81(I) Atr=03(Int.) MxPS=   3 Ivl= 10ms
+T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
+D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
+P:  Vendor=0565 ProdID=0001 Rev= 1.08
+S:  Manufacturer=Peracom Networks, Inc.
+S:  Product=Peracom USB to Serial Converter
+C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
+I:  If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
+E:  Ad=81(I) Atr=02(Bulk) MxPS=  64 Ivl= 16ms
+E:  Ad=01(O) Atr=02(Bulk) MxPS=  16 Ivl= 16ms
+E:  Ad=82(I) Atr=03(Int.) MxPS=   8 Ivl=  8ms
+
+
+Selecting only the "T:" and "I:" lines from this (for example, by using
+"procusb ti"), we have:
+
+T:  Bus=00 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=12  MxCh= 2
+T:  Bus=00 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 4
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=09(hub  ) Sub=00 Prot=00 Driver=hub
+T:  Bus=00 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
+I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=01 Prot=02 Driver=mouse
+T:  Bus=00 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#=  4 Spd=12  MxCh= 0
+I:  If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=serial
+
+
+Physically this looks like (or could be converted to):
+
+                      +------------------+
+                      |  PC/root_hub (12)|   Dev# = 1
+                      +------------------+   (nn) is Mbps.
+    Level 0           |  CN.0   |  CN.1  |   [CN = connector/port #]
+                      +------------------+
+                          /
+                         /
+            +-----------------------+
+  Level 1   | Dev#2: 4-port hub (12)|
+            +-----------------------+
+            |CN.0 |CN.1 |CN.2 |CN.3 |
+            +-----------------------+
+                \           \____________________
+                 \_____                          \
+                       \                          \
+               +--------------------+      +--------------------+
+  Level 2      | Dev# 3: mouse (1.5)|      | Dev# 4: serial (12)|
+               +--------------------+      +--------------------+
+
+
+
+Or, in a more tree-like structure (ports [Connectors] without
+connections could be omitted):
+
+PC:  Dev# 1, root hub, 2 ports, 12 Mbps
+|_ CN.0:  Dev# 2, hub, 4 ports, 12 Mbps
+     |_ CN.0:  Dev #3, mouse, 1.5 Mbps
+     |_ CN.1:
+     |_ CN.2:  Dev #4, serial, 12 Mbps
+     |_ CN.3:
+|_ CN.1:
+
+
+                         ### END ###
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/rio.txt linux.18p8/Documentation/usb/rio.txt
--- linux.vanilla/Documentation/usb/rio.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/rio.txt	Fri Sep  1 13:51:28 2000
@@ -0,0 +1,138 @@
+Copyright (C) 1999, 2000 Bruce Tenison
+Portions Copyright (C) 1999, 2000 David Nelson
+Thanks to David Nelson for guidance and the usage of the scanner.txt
+and scanner.c files to model our driver and this informative file.
+
+Mar. 2, 2000
+
+CHANGES
+
+- Initial Revision
+
+
+OVERVIEW
+
+This README will address issues regarding how to configure the kernel
+to access a RIO 500 mp3 player.  
+Before I explain how to use this to access the Rio500 please be warned:
+
+W A R N I N G:
+--------------
+
+Please note that this software is still under development.  The authors
+are in no way responsible for any damage that may occur, no matter how
+inconsequential.
+
+It seems that the Rio has a problem when sending .mp3 with low batteries.
+I suggest when the batteries are low and want to transfer stuff that you
+replace it with a fresh one. In my case, what happened is I lost two 16kb
+blocks (they are no longer usable to store information to it). But I don't
+know if thats normal or not. It could simply be a problem with the flash 
+memory.
+
+In an extreme case, I left my Rio playing overnight and the batteries wore 
+down to nothing and appear to have corrupted the flash memory. My RIO 
+needed to be replaced as a result.  Diamond tech support is aware of the 
+problem.  Do NOT allow your batteries to wear down to nothing before 
+changing them.  It appears RIO 500 firmware does not handle low battery 
+power well at all. 
+
+On systems with OHCI controllers, the kernel OHCI code appears to have 
+power on problems with some chipsets.  If you are having problems 
+connecting to your RIO 500, try turning it on first and then plugging it 
+into the USB cable.  
+
+Contact information:
+--------------------
+
+   The main page for the project is hosted at sourceforge.net in the following
+   address: http://rio500.sourceforge.net You can also go to the sourceforge
+   project page at: http://sourceforge.net/project/?group_id=1944 There is 
+   also a mailing list: rio500-users@lists.sourceforge.net
+
+Authors:
+-------
+
+Most of the code was written by Cesar Miquel <miquel@df.uba.ar>. Keith 
+Clayton <kclayton@jps.net> is incharge of the PPC port and making sure
+things work there. Bruce Tenison <btenison@dibbs.net> is adding support
+for .fon files and also does testing. The program will mostly sure be
+re-written and Pete Ikusz along with the rest will re-design it. I would
+also like to thank Tri Nguyen <tmn_3022000@hotmail.com> who provided use 
+with some important information regarding the communication with the Rio.
+
+ADDITIONAL INFORMATION and Userspace tools
+
+http://rio500.sourceforge.net/
+
+
+REQUIREMENTS
+
+A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
+(Compaq and others) hardware port should work.
+
+A Linux development kernel (2.3.x) with USB support enabled or a
+backported version to linux-2.2.x.  See http://www.linux-usb.org for
+more information on accomplishing this.
+
+A Linux kernel with RIO 500 support enabled.
+
+'lspci' which is only needed to determine the type of USB hardware
+available in your machine.
+
+CONFIGURATION
+
+Using `lspci -v`, determine the type of USB hardware available.
+
+  If you see something like:
+
+    USB Controller: ......
+    Flags: .....
+    I/O ports at ....
+
+  Then you have a UHCI based controller.
+
+  If you see something like:
+
+     USB Controller: .....
+     Flags: ....
+     Memory at .....
+
+  Then you have a OHCI based controller.
+
+Using `make menuconfig` or your preferred method for configuring the
+kernel, select 'Support for USB', 'OHCI/UHCI' depending on your
+hardware (determined from the steps above), 'USB Diamond Rio500 support', and
+'Preliminary USB device filesystem'.  Compile and install the modules
+(you may need to execute `depmod -a` to update the module
+dependencies).
+
+Add a device for the USB rio500:
+  `mknod /dev/usb/rio500 c 180 64`
+
+Set appropriate permissions for /dev/usb/rio500 (don't forget about
+group and world permissions).  Both read and write permissions are
+required for proper operation.
+
+Load the appropriate modules (if compiled as modules):
+
+  OHCI:
+    modprobe usbcore
+    modprobe usb-ohci
+    modprobe rio500
+
+  UHCI:
+    modprobe usbcore
+    modprobe usb-uhci  (or uhci)
+    modprobe rio500
+
+That's it.  The Rio500 Utils at: http://rio500.sourceforge.net should
+be able to access the rio500.
+
+BUGS
+
+If you encounter any problems feel free to drop me an email.
+
+Bruce Tenison
+btenison@dibbs.net
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/scanner-hp-sane.txt linux.18p8/Documentation/usb/scanner-hp-sane.txt
--- linux.vanilla/Documentation/usb/scanner-hp-sane.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/scanner-hp-sane.txt	Fri Sep  1 13:51:28 2000
@@ -0,0 +1,81 @@
+Copyright (C) 1999, 2000 David E. Nelson
+
+April 26, 2000
+
+CHANGES
+
+- Amended for Linux-2.3.99-pre6-3
+- Updated for multiple scanner support
+
+INTRODUCTION
+
+This document will hopefully provide enough info on how to get SANE
+working with a Hewlett Packard USB capable scanner using the USB
+interface.  The majority of HP Scanners support the Scanner Control
+Language (SCL) which is both published by HP and supported by SANE.
+The only HP Scanners that I'm aware of that do not support SCL are the
+4200C ,3300C, and the PhotoSmart S20.  All other HP scanners with USB
+interfaces should work (4100C, 5200C, 6200C, and 6300C) as do models
+that are derived from the models above. ie the 6350C which is a 6300C
+with a transparency adaptor included with the scanner at time of
+purchase.  Of course as HP releases new scanners this information may
+change.
+
+
+REQUIREMENTS
+
+In order to get this running you'll need USB support in your kernel in
+addition to USB Scanner support.  Please refer to scanner.txt for
+issues pertaining to Linux USB and USB Scanner support.
+
+An installed version of SANE which is available from
+http://www.mostang.com/sane/.  Testing has been performed using
+version SANE-1.0.1.  For instructions on building and installing SANE,
+refer to the various README files within the SANE distribution.
+
+The latest SANE HP backend is available from http://www.kirchgessner.net.
+At the time of this writing, version 0.83 was available.
+
+
+OK, I'VE INSTALLED SANE. SO WHAT DO I DO NOW?
+
+NOTE: $INSTALL_DIR is the location where SANE is installed.  It may be
+/usr/local, /usr, /opt or somewhere else.  If you don't know, ask your
+system administrator.
+
+1) Make sure that you have the libsane-hp.* libraries under the
+$INSTALL_DIR/lib/sane/ directory.  If you don't, then the HP backend
+was either not compiled or installed properly.
+
+2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
+files: dll.conf, hp.conf.
+
+  dll.conf:  Make sure that the 'hp' entry is present and uncommented.
+
+  hp.conf: This should contain two lines:
+
+    /dev/usbscanner
+    option connect-device
+
+NOTE: If you are using multiple scanners, make sure to have the correct
+device, ie /dev/usbscanner0.  See scanner.txt for more info.
+
+3) You should now be able to use SANE (xscanimage or scanimage).
+
+Don't forget to read any relevant man pages regarding the usage of
+SANE.  If you have other entries uncommented in 'dll.conf', you may
+have to specify the device to (x)scanimage.  Again, `man` is your
+friend.  The xscanimage (1) man page has info on how to get 'The Gimp'
+to work with xscanimage.  Note that Gimp support must be compiled into
+SANE for it to work.  If you are dealing with a RedHat system, this
+means that you'll also need to install the gimp-devel rpm package
+prior to compiling SANE.
+
+NOTE: The issues regarding core dumping by (x)scanimage have (or seem
+to be thus far) been resolved with version 0.2+ of the USB scanner
+driver which should be available in linux-2.3.23.  If you notice
+otherwise, please contact me.
+
+David /\/elson
+dnelson@jump.net
+http://www.jump.net/~dnelson
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/scanner.txt linux.18p8/Documentation/usb/scanner.txt
--- linux.vanilla/Documentation/usb/scanner.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/scanner.txt	Thu Sep 14 15:35:24 2000
@@ -0,0 +1,362 @@
+Copyright (C) 1999, 2000 David E. Nelson
+
+April 26, 2000
+
+CHANGES
+
+- Amended for linux-2.3.99-pre6-3
+- Appended hp_scan.c to end of this README
+- Removed most references to HP
+- Updated uhci/ohci host controller info
+- Updated support for multiple scanner support
+- Updated supported scanners list
+- Updated usbdevfs info
+- Spellcheck
+
+OVERVIEW
+
+This README addresses issues regarding how to configure the kernel
+to access a USB scanner.  Although the driver was originally conceived
+for USB HP scanners, it's general enough so that it can be used with
+other scanners.  Also, one can now pass the USB Vendor and Product
+ID's using module parameters for unknown scanners.  Refer to the
+document scanner-hp-sane.txt for guidance on how to configure SANE to
+use a USB HP Scanner.
+
+
+ADDITIONAL INFORMATION
+
+http://www.linux-usb.org/
+
+
+REQUIREMENTS
+
+A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
+(Compaq and others) hardware port should work.  At the time of this
+writing, there are two UHCI drivers and one OHCI.
+
+A Linux development kernel (2.3.x) with USB support enabled or a
+backported version to linux-2.2.x.  See http://www.linux-usb.org for
+more information on accomplishing this.
+
+A Linux kernel with USB Scanner support enabled.
+
+'lspci' which is only needed to determine the type of USB hardware
+available/installed in your machine.
+
+CONFIGURATION
+
+Using `lspci -v`, determine the type of USB hardware available/installed.
+
+  If you see something like:
+
+    USB Controller: ......
+    Flags: .....
+    I/O ports at ....
+
+  Then you have a UHCI based controller.
+
+  If you see something like:
+
+     USB Controller: .....
+     Flags: ....
+     Memory at .....
+
+  Then you have a OHCI based controller.
+
+Using `make menuconfig` or your preferred method for configuring the
+kernel, select 'Support for USB', 'OHCI/UHCI' depending on your
+hardware (determined from the steps above), 'USB Scanner support', and
+'Preliminary USB device filesystem'.  Compile and install the modules
+(you may need to execute `depmod -a` to update the module
+dependencies). If any of the USB sections were compiled into the
+kernel, a reboot is necessary. NOTE: Updating the boot disk with
+'lilo' may also be required. Testing was performed only as modules,
+YMMV.
+
+Beginning with version 0.4 of the driver, up to 16 scanners can be
+connected/used simultaneously.  If you intend to use more than
+one scanner at a time:
+
+   Add a device for the USB scanner:
+	`mknod /dev/usbscanner0 c 180 48`
+	`mknod /dev/usbscanner1 c 180 49`
+                      . 
+                      .
+	`mknod /dev/usb/scanner15 180 63`
+
+
+If you foresee using only one scanner it is best to:
+	`mknod /dev/usbscanner0 c 180 48`
+	`ln -s /dev/usbscanner0 /dev/usbscanner`
+
+
+Set appropriate permissions for /dev/usbscanner[0-15] (don't forget
+about group and world permissions).  Both read and write permissions
+are required for proper operation. For example:
+	`chmod 666 /dev/usbscanner0`
+
+Load the appropriate modules (if compiled as modules):
+
+  OHCI:
+    modprobe usb-ohci
+    modprobe scanner
+
+  UHCI:
+    modprobe usb-uhci
+    modprobe scanner
+
+That's it.  SANE should now be able to access the device.  
+
+There is a small test program (hp_scan.c -- appended below) that can
+be used to test the scanner device if it's an HP scanner that supports
+SCL (Scanner Control Language).  Known HP scanner that support SCL are
+the 4100, 5200, 6200, the 6300 -- note that the 4200 is *not*
+supported since it does not understand SCL; it's also strongly
+suspected that the 3300 and the PhotoSmart S20 are not SCL compliant.
+Hp_scan.c's purpose is to test the driver without having to
+retrieve/configure SANE.  Hp_scan.c will scan the entire bed and put
+the output into a file called 'out.dat' in the current directory.  The
+data in the file is raw data so it's not very useful for imaging.
+
+MESSAGES
+
+On occasions the message 'usb_control/bulk_msg: timeout' or something
+similar will appear in '/var/adm/messages' or on the console or both,
+depending on how your system is configured.  This is a side effect
+that scanners are sometimes very slow at warming up and/or
+initializing.  In most cases, however, only several of these messages
+should appear and is generally considered to be normal.  If you see
+a message of the type 'excessive NAK's received' then this should
+be considered abnormal and generally indicates that the USB system is
+unable to communicate with the scanner for some particular reason.
+
+SUPPORTED SCANNERS
+
+NOTE: Just because a product is listed here does not mean that
+applications exist that support the product.  It's in the hopes that
+this will allow developers a means to produce applications that will
+support the listed USB products.
+
+At the time of this writing, the following scanners were supported by
+scanner.c:
+
+ Acer
+	 Prisa Acerscan 620U & 640U (!)
+	 Prisa AcerScan 620U (!)
+ Agfa
+	 SnapScan 1212U
+	 Another SnapScan 1212U (?)
+	 SnapScan Touch
+ Colorado -- See Primax/Colorado below
+ Epson -- See Seiko/Epson below
+ Genius
+         ColorPage-Vivid Pro
+ Hewlett Packard
+	 3300C
+	 4100C
+	 4200C
+	 PhotoSmart S20
+	 5200C
+	 6200C
+	 6300C
+ Microtek
+	 ScanMaker X6 - X6U
+	 Phantom 336CX - C3
+	 Phantom 336CX - C3 #2
+	 Phantom C6
+	 ScanMaker V6USL
+	 ScanMaker V6USL #2
+	 ScanMaker V6UL - SpicyU
+ Mustek
+	 1200 CU
+ Primax/Colorado
+	 G2-300 #1
+	 G2-600 #1
+	 G2E-300 #1
+	 ReadyScan 636i
+	 G2-300 #2
+	 G2-600 #2
+	 G2E-300 #2
+	 G2E-600
+	 Colorado USB 9600
+	 Colorado USB 19200
+	 Colorado 600u
+	 Colorado 1200u
+ Seiko/Epson Corp.
+	 Perfection 636U and 636Photo
+	 Perfection 610
+	 Perfection 1200U and 1200Photo
+ Umax
+	 Astra 1220U
+	 Astra 1236U
+	 Astra 2000U
+	 Astra 2200U
+ Visioneer
+	 OneTouch 5300
+	 OneTouch 7600 duplicate ID (!)
+	 6100
+
+
+MODULE PARAMETERS
+
+If you have a device that you wish to experiment with or try using
+this driver with, but the Vendor and Product ID's are not coded in,
+don't despair.  If the driver was compiled as a module, you can pass
+options to the driver.  Simply add 
+
+  options scanner vendor=0x#### product=0x****
+
+to the /etc/modules.conf file replacing the #'s and the *'s with the
+correct ID's.  The ID's can be retrieved from the messages file or
+using `cat /proc/bus/usb/devices`. Note that USB /proc support must be
+enabled during kernel configuration.  If the 'scanner' module is
+already loaded into memory, it must be reloaded for the module
+parameters to take effect.  In essence, `rmmod scanner; modprobe
+scanner` must be performed.
+
+**NOTE**: In later kernels (2.3.38+), a new filesystem was introduced,
+usbdevfs.  To mount the filesystem, issue the command (as root):
+
+  mount -t usbdevfs /proc/bus/usb /proc/bus/usb
+
+An alternative and more permanent method would be to add
+
+  none  /proc/bus/usb  usbdevfs  defaults  0  0
+
+to /etc/fstab.  This will mount usbdevfs at each reboot.  You can then
+issue `cat /proc/bus/usb/devices` to extract USB device information.
+
+
+BUGS
+
+Just look at the list of fixes in the source files.  So, if you
+encounter any problems feel free to drop me an email.
+
+David /\/elson
+dnelson@jump.net
+http://www.jump.net/~dnelson
+
+--------------- snip -- hp_scan.c -- snip ---------------
+/*
+
+This is a really crude attempt at writing a short test program.  It's
+mostly only to be used to test connectivity with USB HP scanners that
+understand SCL.  Currently, the supported models are 4100C, 5200C,
+6200C, and the 6300C.  Note that the 4200C is *NOT* acceptable.
+
+Copyright (C) David E. Nelson <dnelson@jump.net>, 1999
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <error.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+/*
+   Gray Output produces about a 8945400 byte file.
+   Color Output produces a 26836200 byte file. 
+   
+   To compile: gcc -o hp_scan hp_scan.c
+*/
+
+// #define COLOR /* Undef to scan GrayScale */
+
+int send_cmd(int, const char *, int);
+int read_cmd(int, char *, int);
+
+int
+main(void) {
+
+	ssize_t cnt = 0, total_cnt = 0;
+
+	FILE *fpout;
+
+	int fp;
+	int data_size = 32768;
+
+	char *data;
+
+	static char reset_cmd[] = {'\x1b','E'};
+
+#ifdef COLOR
+	static char data_type_cmd[] = {'\x1b','*','a','5','T'}; /* Color */
+	static char data_width_cmd[] = {'\x1b','*','a','2','4','G'}; /* 24 Bit Color */
+#else
+	static char data_type_cmd[] = {'\x1b','*','a','4','T'}; /* Gray */
+	static char data_width_cmd[] = {'\x1b','*','a','8','G'}; /* 8 Bit Gray */
+#endif
+
+	static char query_cmd[] = {'\x1b', '*', 's', '2', '5', '7', 'E'};
+	static char start_scan_cmd[] = {'\x1b','*','f','0','S'};
+	
+	if(!(data=malloc(data_size))) {
+		perror("malloc failed");
+		exit (1);
+	}
+	
+	if((fp=open("/dev/usbscanner", O_RDWR)) < 0) {
+		perror("Unable to open scanner device");
+		exit (1);
+	}
+
+	if((fpout=fopen("out.dat", "w+")) == NULL) {
+		perror("Unable to open ouput file");
+		exit(1);
+	}
+
+	send_cmd(fp, reset_cmd, sizeof(reset_cmd));
+	send_cmd(fp, data_type_cmd, sizeof(data_type_cmd));
+	send_cmd(fp, data_width_cmd, sizeof(data_width_cmd));
+	send_cmd(fp, start_scan_cmd, sizeof(start_scan_cmd));
+
+	while ((cnt = read(fp, data, data_size)) > 0) {
+		printf("Read: %u\n", cnt); 
+		if(fwrite(data, sizeof(char), cnt, fpout) < 0) {
+			perror("Write to output file failed");
+			exit (1);
+		}
+		total_cnt += cnt;
+	}
+	if (cnt < 0) {
+		perror("Read from scanner failed");
+		exit (1);
+	}
+
+	printf("\nRead %lu bytes.\n", total_cnt);
+
+	send_cmd(fp, reset_cmd, sizeof(reset_cmd));
+
+	close(fp);
+	fclose(fpout);
+	return (0);
+}
+
+int
+send_cmd(int fp, const char * cmd, int length) {
+
+	int result;
+	int x;
+
+	if((result = write(fp, cmd, length)) != length) {
+		printf ("Write warning: %d bytes requested, %d written\n");
+	} else if (result < 0) {
+		perror ("send_cmd failure");
+		exit (1);
+	}
+	return (result);
+}
+	
+int
+read_cmd(int fp, char * response, int length) {
+
+	return read(fp, response, length);
+
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/uhci.txt linux.18p8/Documentation/usb/uhci.txt
--- linux.vanilla/Documentation/usb/uhci.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/uhci.txt	Thu Sep 14 15:35:24 2000
@@ -0,0 +1,165 @@
+Specification and Internals for the New UHCI Driver (Whitepaper...)
+
+	brought to you by
+
+	Georg Acher, acher@in.tum.de (executive slave) (base guitar)
+	Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
+	Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
+ 
+	$Id: README.uhci,v 1.1 1999/12/14 14:03:02 fliegl Exp $
+
+This document and the new uhci sources can be found on
+		http://hotswap.in.tum.de/usb
+
+1. General issues
+
+1.1 Why a new UHCI driver, we already have one?!?
+
+Correct, but its internal structure got more and more mixed up by the (still
+ongoing) efforts to get isochronous transfers (ISO) to work.
+Since there is an increasing need for reliable ISO-transfers (especially 
+for USB-audio needed by TS and for a DAB-USB-Receiver build by GA and DF), 
+this state was a bit unsatisfying in our opinion, so we've decided (based
+on knowledge and experiences with the old UHCI driver) to start 
+from scratch with a new approach, much simpler but at the same time more 
+powerful.
+It is inspired by the way Win98/Win2000 handles USB requests via URBs,
+but it's definitely 100% free of MS-code and doesn't crash while 
+unplugging an used ISO-device like Win98 ;-)
+Some code for HW setup and root hub management was taken from the 
+original UHCI driver, but heavily modified to fit into the new code.
+The invention of the basic concept, and major coding were completed in two 
+days (and nights) on the 16th and 17th of October 1999, now known as the
+great USB-October-Revolution started by GA, DF, and TS ;-)
+
+Since the concept is in no way UHCI dependent, we hope that it will also be 
+transfered to the OHCI-driver, so both drivers share a common API.
+
+1.2. Advantages and disadvantages
+
++ All USB transfer types work now!
++ Asynchronous operation
++ Simple, but powerful interface (only two calls for start and cancel)
++ Easy migration to the new API, simplified by a compatibility API
++ Simple usage of ISO transfers
++ Automatic linking of requests
++ ISO transfers allow variable length for each frame and striping
++ No CPU dependent and non-portable atomic memory access, no asm()-inlines
++ Tested on x86 and Alpha
+
+- Rewriting for ISO transfers needed
+
+1.3. Is there some compatibility to the old API?
+
+Yes, but only for control, bulk and interrupt transfers. We've implemented 
+some wrapper calls for these transfer types. The usbcore works fine with 
+these wrappers. For ISO there's no compatibility, because the old ISO-API 
+and its semantics were unnecessary complicated in our opinion.
+
+1.4. What's really working?
+
+As said above, CTRL and BULK already work fine even with the wrappers,
+so legacy code wouldn't notice the change.
+Regarding to Thomas, ISO transfers now run stable with USB audio.
+INT transfers (e.g. mouse driver) work fine, too.
+
+1.5. Are there any bugs?
+
+No ;-)
+Hm...
+Well, of course this implementation needs extensive testing on all available
+hardware, but we believe that any fixes shouldn't harm the overall concept.
+
+1.6. What should be done next?
+
+A large part of the request handling seems to be identical for UHCI and 
+OHCI, so it would be a good idea to extract the common parts and have only 
+the HW specific stuff in uhci.c. Furthermore, all other USB device drivers
+should need URBification, if they use isochronous or interrupt transfers.
+One thing missing in the current implementation (and the old UHCI driver) 
+is fair queueing for BULK transfers. Since this would need (in principle) 
+the alteration of already constructed TD chains (to switch from depth to 
+breadth execution), another way has to be found. Maybe some simple 
+heuristics work with the same effect.
+
+---------------------------------------------------------------------------
+
+2. Internal structure and mechanisms
+
+To get quickly familiar with the internal structures, here's a short
+description how the new UHCI driver works. However, the ultimate source of
+truth is only uhci.c!
+
+2.1. Descriptor structure (QHs and TDs)
+
+During initialization, the following skeleton is allocated in init_skel:
+
+	 framespecific           |           common chain     
+
+framelist[]
+[  0 ]-----> TD --> TD -------\
+[  1 ]-----> TD --> TD --------> TD ----> QH -------> QH -------> QH ---> NULL
+  ...        TD --> TD -------/
+[1023]-----> TD --> TD ------/
+	     
+	     ^^     ^^           ^^       ^^          ^^          ^^
+   1024 TDs for   7 TDs for    1 TD for   Start of    Start of    End Chain
+	    ISO  INT (2-128ms) 1ms-INT    CTRL Chain  BULK Chain
+
+For each CTRL or BULK transfer a new QH is allocated and the containing data
+transfers are appended as (vertical) TDs. After building the whole QH with its
+dangling TDs, the QH is inserted before the BULK Chain QH (for CTRL) or
+before the End Chain QH (for BULK). Since only the QH->next pointers are
+affected, no atomic memory operation is required. The three QHs in the
+common chain are never equipped with TDs!
+
+For ISO or INT, the TD for each frame is simply inserted into the appropriate
+ISO/INT-TD-chain for the desired frame. The 7 skeleton INT-TDs are scattered
+among the 1024 frames similar to the old UHCI driver.
+
+For CTRL/BULK/ISO, the last TD in the transfer has the IOC-bit set. For INT,
+every TD (there is only one...) has the IOC-bit set.
+
+Besides the data for the UHCI controller (2 or 4 32bit words), the descriptors
+are double-linked through the .vertical and .horizontal elements in the 
+SW data of the descriptor (using the double-linked list structures and 
+operations), but SW-linking occurs only in closed domains, i.e. for each of
+the 1024 ISO-chains and the 8 INT-chains there is a closed cycle. This 
+simplifies all insertions and unlinking operations and avoids costly 
+bus_to_virt()-calls.
+
+2.2. URB structure and linking to QH/TDs
+
+During assembly of the QH and TDs of the requested action, these descriptors
+are stored in urb->urb_list, so the allocated QH/TD descriptors are bound to
+this URB.
+If the assembly was successful and the descriptors were added to the HW chain,
+the corresponding URB is inserted into a global URB list for this controller.
+This list stores all pending URBs.
+
+2.3. Interrupt processing
+
+Since UHCI provides no means to directly detect completed transactions, the
+following is done in each UHCI interrupt (uhci_interrupt()):
+
+For each URB in the pending queue (process_urb()), the ACTIVE-flag of the 
+associated TDs are processed (depending on the transfer type 
+process_{transfer|interrupt|iso}()). If the TDs are not active anymore, 
+they indicate the completion of the transaction and the status is calculated. 
+Inactive QH/TDs are removed from the HW chain (since the host controller
+already removed the TDs from the QH, no atomic access is needed) and 
+eventually the URB is marked as completed (OK or errors) and removed from the 
+pending queue. Then the next linked URB is submitted. After (or immediately 
+before) that, the completion handler is called.
+
+2.4. Unlinking URBs
+
+First, all QH/TDs stored in the URB are unlinked from the HW chain. 
+To ensure that the host controller really left a vertical TD chain, we 
+wait for one frame. After that, the TDs are physically destroyed.
+
+2.5. URB linking and the consequences
+
+Since URBs can be linked and the corresponding submit_urb is called in
+the UHCI-interrupt, all work associated with URB/QH/TD assembly has to be
+interrupt save. This forces kmalloc to use GFP_ATOMIC in the interrupt.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/usb-help.txt linux.18p8/Documentation/usb/usb-help.txt
--- linux.vanilla/Documentation/usb/usb-help.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/usb-help.txt	Thu Sep 14 15:35:24 2000
@@ -0,0 +1,18 @@
+usb-help.txt
+2000-July-12
+
+For USB help other than the readme files that are located in
+linux/Documentation/usb/*, see the following:
+
+Linux-USB project:  http://www.linux-usb.org
+  mirrors at        http://www.suse.cz/development/linux-usb/
+         and        http://usb.in.tum.de/linux-usb/
+Linux USB Guide:    http://linux-usb.sourceforge.net
+Linux-USB device overview (working devices and drivers):
+                    http://www.qbik.ch/usb/devices/
+    
+The Linux-USB mailing lists are:
+  linux-usb-users@lists.sourceforge.net   for general user help
+  linux-usb-devel@lists.sourceforge.net   for developer discussions
+
+###
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/usb-serial.txt linux.18p8/Documentation/usb/usb-serial.txt
--- linux.vanilla/Documentation/usb/usb-serial.txt	Thu Jan  1 01:00:00 1970
+++ linux.18p8/Documentation/usb/usb-serial.txt	Thu Sep 14 15:35:24 2000
@@ -0,0 +1,183 @@
+INTRODUCTION
+
+  The USB serial driver currently supports a number of different USB to
+  serial converter products, as well as some devices that use a serial
+  interface from userspace to talk to the device.
+
+  See the individual product section below for specific information about
+  the different devices.
+
+
+CONFIGURATION
+
+  Currently the driver can handle up to 256 different serial interfaces at
+  one time. 
+
+  If you are not using devfs:
+    The major number that the driver uses is 188 so to use the driver,
+    create the following nodes:
+	mknod /dev/ttyUSB0 c 188 0
+	mknod /dev/ttyUSB1 c 188 1
+	mknod /dev/ttyUSB2 c 188 2
+	mknod /dev/ttyUSB3 c 188 3
+		.
+		.
+		.
+	mknod /dev/ttyUSB254 c 188 254
+	mknod /dev/ttyUSB255 c 188 255
+
+  If you are using devfs:
+    The devices supported by this driver will show up as
+    /dev/usb/tts/{0,1,...}
+
+  When the device is connected and recognized by the driver, the driver
+  will print to the system log, which node(s) the device has been bound
+  to.
+  
+
+SPECIFIC DEVICES SUPPORTED
+
+
+ConnectTech WhiteHEAT 4 port converter
+
+  ConnectTech has been very forthcoming with information about their
+  device, including providing a unit to test with. This driver will end up
+  being fully supported.
+
+Current status:
+  The device's firmware is downloaded on connection, the new firmware 
+  runs properly and all four ports are successfully recognized and connected.
+  Data can be sent and received through the device on all ports.
+  Hardware flow control needs to be implemented.
+
+
+HandSpring Visor USB docking station
+
+Current status:
+  Only when the Visor tries to connect to the host, does the docking
+  station show up as a valid USB device. When this happens, the device is
+  properly enumerated, assigned a port, and then communication _should_ be
+  possible. The driver cleans up properly when the device is removed, or
+  the connection is canceled on the Visor.
+
+  NOTE:
+    This means that in order to talk to the Visor, the sync button must be
+    pressed BEFORE trying to get any program to communicate to the Visor.
+    This goes against the current documentation for pilot-xfer and other
+    packages, but is the only way that it will work due to the hardware
+    in the Visor.
+  
+  When the device is connected, try talking to it on the second port
+  (this is usually /dev/ttyUSB1 if you do not have any other usb-serial
+  devices in the system.) The system log should tell you which port is
+  the port to use for the HotSync transfer. The "Generic" port can be used
+  for other device communication, such as a PPP link.
+
+  There is a webpage and mailing lists for this portion of the driver at: 
+  http://usbvisor.sourceforge.net/
+
+
+Keyspan PDA Serial Adapter
+
+  Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly
+  sold in Macintosh catalogs, comes in a translucent white/green dongle).
+  Fairly simple device. Firmware is homebrew.
+
+Current status:
+ Things that work:
+   basic input/output (tested with 'cu')
+   blocking write when serial line can't keep up
+   changing baud rates (up to 115200)
+   getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC})
+   sending break (although duration looks suspect)
+ Things that don't:
+   device strings (as logged by kernel) have trailing binary garbage
+   device ID isn't right, might collide with other Keyspan products
+   changing baud rates ought to flush tx/rx to avoid mangled half characters
+ Big Things on the todo list:
+   parity, 7 vs 8 bits per char, 1 or 2 stop bits
+   HW flow control
+   not all of the standard USB descriptors are handled: Get_Status, Set_Feature
+   O_NONBLOCK, select()
+
+
+Keyspan USA-series Serial Adapters
+
+  Single and Dual port adapters - driver uses Keyspan supplied 
+  firmware and is being developed with their support.
+  
+  Driver isn't as far advanced as Keyspan PDA driver mentioned above.
+  
+Current status:
+ Things that work:
+   Firmware upload for USA-18X, USA-28, USA-28X, USA-19 and USA-19W 
+   Simple character I/O fixed at 9600 baud on USA-19 only
+   
+ Things that don't:
+   Everything else. (for now...)
+   
+ Big Things on the todo list:
+   Driver is in infancy, much functionality remains to be added
+
+
+FTDI Single Port Serial Driver
+
+  This is a single port DB-25 serial adapter. More information about this
+  device and the Linux driver can be found at:
+	http://reality.sgi.com/bryder_wellington/ftdi_sio/
+
+
+ZyXEL omni.net lcd plus ISDN TA
+
+  This is an ISDN TA. Please report both successes and troubles to the
+  author at omninet@kroah.com
+
+
+Digi AccelePort Driver
+
+  This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port
+  (plus a parallel port) and 4 port USB serial converters.  The driver
+  does NOT yet support the Digi AccelePort USB 8.
+
+  The driver is generally working, though we still have a few more ioctls
+  to implement and final testing and debugging to do.  The paralled port
+  on the USB 2 is supported as a serial to parallel converter; in other
+  words, it appears as another USB serial port on Linux, even though
+  physically it is really a parallel port.  The Digi Acceleport USB 8
+  is not yet supported.
+
+  Please contact Peter Berger (pberger@brimson.com) or Al Borchers
+  (alborchers@steinerpoint.com) for questions or problems with this
+  driver.
+
+
+Generic Serial driver
+
+  If your device is not one of the above listed devices, compatible with
+  the above models, you can try out the "generic" interface. This
+  interface does not provide any type of control messages sent to the
+  device, and does not support any kind of device flow control. All that
+  is required of your device is that it has at least one bulk in endpoint,
+  or one bulk out endpoint. 
+  
+  To enable the generic driver to recognize your device, build the driver
+  as a module and load it by the following invocation:
+	insmod usb-serial vendor=0x#### product=0x####
+  where the #### is replaced with the hex representation of your device's
+  vendor id and product id.
+
+  This driver has been successfully used to connect to the NetChip USB
+  development board, providing a way to develop USB firmware without
+  having to write a custom driver.
+
+
+CONTACT:
+
+  If anyone has any problems using this driver, with any of the above
+  specified products, please contact me, or join the Linux-USB mailing
+  list (information on joining the mailing list, as well as a link to its
+  searchable archive is at http://www.linux-usb.org/ )
+
+
+Greg Kroah-Hartman
+greg@kroah.com
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/MAINTAINERS linux.18p8/MAINTAINERS
--- linux.vanilla/MAINTAINERS	Sat Sep  9 18:42:32 2000
+++ linux.18p8/MAINTAINERS	Sun Sep  3 14:00:02 2000
@@ -93,6 +93,12 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+AACRAID ADAPTEC RAID DRIVER
+P:	Brian M. Boerner
+M:	aacraid@ntc.adaptec.com
+L:	To Be Announced
+S:	Maintained
+
 AD1816 SOUND DRIVER
 P:	Thorsten Knabe
 M:	Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
@@ -300,6 +306,13 @@
 L:	compaqandlinux@cpqlin.van-dijk.net
 W:	ftp.compaq.com/pub/products/drivers/linux
 S:	Supported
+
+COMPAQ SMART CISS RAID DRIVER 
+P:      Charles White
+M:      Charles White <arrays@compaq.com>
+L:      compaqandlinux@cpqlin.van-dijk.net
+W:	ftp.compaq.com/pub/products/drivers/linux	
+S:     	Supported 
 
 DAC960 RAID DRIVER
 P:	Leonard N. Zubkoff
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Makefile linux.18p8/Makefile
--- linux.vanilla/Makefile	Sat Sep  9 18:42:32 2000
+++ linux.18p8/Makefile	Fri Sep 15 12:40:01 2000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 17
-EXTRAVERSION =
+SUBLEVEL = 18
+EXTRAVERSION = pre8
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -111,7 +111,7 @@
 FILESYSTEMS	=fs/filesystems.a
 NETWORKS	=net/network.a
 DRIVERS		=drivers/block/block.a \
-		 drivers/char/char.a \
+		 drivers/char/char.o \
 	         drivers/misc/misc.a
 LIBS		=$(TOPDIR)/lib/lib.a
 SUBDIRS		=kernel drivers mm fs net ipc lib
@@ -191,7 +191,7 @@
 endif
 
 ifeq ($(CONFIG_USB),y)
-DRIVERS := $(DRIVERS) drivers/usb/usb.a
+DRIVERS := $(DRIVERS) drivers/usb/usbdrv.o
 endif
 
 ifeq ($(CONFIG_I2O),y)
@@ -348,7 +348,10 @@
 	if [ -f VIDEO_MODULES ]; then inst_mod VIDEO_MODULES video; fi; \
 	if [ -f FC4_MODULES   ]; then inst_mod FC4_MODULES   fc4;   fi; \
 	if [ -f IRDA_MODULES  ]; then inst_mod IRDA_MODULES  net;   fi; \
+	if [ -f USB_MODULES   ]; then inst_mod USB_MODULES   usb;   fi; \
+	if [ -f USB_SERIAL_MODULES ]; then inst_mod USB_SERIAL_MODULES usb; fi; \
 	if [ -f SK98LIN_MODULES ]; then inst_mod SK98LIN_MODULES  net;   fi; \
+	if [ -f SKFP_MODULES ]; then inst_mod SKFP_MODULES   net;   fi; \
 	\
 	for f in *.o; do [ -r $$f ] && echo $$f; done | sort > $$MODLIB/.allmods; \
 	echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Rules.make linux.18p8/Rules.make
--- linux.vanilla/Rules.make	Sat Sep  9 18:42:32 2000
+++ linux.18p8/Rules.make	Tue Sep  5 22:20:28 2000
@@ -77,7 +77,7 @@
 $(O_TARGET): $(ALL_O)
 	rm -f $@
 ifneq "$(strip $(ALL_O))" ""
-	$(LD) $(EXTRA_LDFLAGS) -r -o $@ $(ALL_O)
+	$(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(ALL_O), $^)
 else
 	$(AR) rcs $@
 endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/config.in linux.18p8/arch/alpha/config.in
--- linux.vanilla/arch/alpha/config.in	Sat Sep  9 18:42:32 2000
+++ linux.18p8/arch/alpha/config.in	Fri Sep  1 13:51:28 2000
@@ -268,7 +268,7 @@
 endmenu
 
 source drivers/char/Config.in
-
+source drivers/usb/Config.in
 source fs/Config.in
 
 if [ "$CONFIG_VT" = "y" ]; then
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/alpha_ksyms.c linux.18p8/arch/alpha/kernel/alpha_ksyms.c
--- linux.vanilla/arch/alpha/kernel/alpha_ksyms.c	Sun Jun 11 21:44:08 2000
+++ linux.18p8/arch/alpha/kernel/alpha_ksyms.c	Tue Sep 12 13:14:57 2000
@@ -37,6 +37,7 @@
 extern struct hwrpb_struct *hwrpb;
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+extern spinlock_t rtc_lock;
 
 /* these are C runtime functions with special calling conventions: */
 extern void __divl (void);
@@ -187,6 +188,8 @@
 EXPORT_SYMBOL(local_bh_count);
 EXPORT_SYMBOL(local_irq_count);
 #endif /* __SMP__ */
+
+EXPORT_SYMBOL(rtc_lock);
 
 /*
  * The following are special because they're not called
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/bios32.c linux.18p8/arch/alpha/kernel/bios32.c
--- linux.vanilla/arch/alpha/kernel/bios32.c	Sun Jun 11 21:44:08 2000
+++ linux.18p8/arch/alpha/kernel/bios32.c	Fri Sep 15 12:43:11 2000
@@ -828,6 +828,7 @@
 
 	for (dev = bus->devices; dev; dev = dev->sibling) {
 		if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
+		    (dev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) ||
 		    (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) {
 			disable_dev(dev);
 		}
@@ -840,6 +841,7 @@
 
 	for (dev = bus->devices; dev; dev = dev->sibling) {
 		if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
+		    (dev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) ||
 		    (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) {
 			layout_dev(dev);
 		}
@@ -1081,6 +1083,7 @@
 	 */
 	for (dev = pci_devices; dev; dev = dev->next) {
 		if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) &&
+		    (dev->class >> 8 != PCI_CLASS_BRIDGE_OTHER) &&
 		    (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA))
 			continue;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/time.c linux.18p8/arch/alpha/kernel/time.c
--- linux.vanilla/arch/alpha/kernel/time.c	Sun Jun 11 21:44:09 2000
+++ linux.18p8/arch/alpha/kernel/time.c	Tue Sep 12 13:14:57 2000
@@ -47,6 +47,7 @@
 
 static int set_rtc_mmss(unsigned long);
 
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * Shift amount by which scaled_ticks_per_cycle is scaled.  Shifting
@@ -455,6 +456,8 @@
 	int real_seconds, real_minutes, cmos_minutes;
 	unsigned char save_control, save_freq_select;
 
+	/* irq are locally disabled here */
+	spin_lock(&rtc_lock);
 	/* Tell the clock it's being set */
 	save_control = CMOS_READ(RTC_CONTROL);
 	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
@@ -504,6 +507,7 @@
 	 */
 	CMOS_WRITE(save_control, RTC_CONTROL);
 	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+	spin_unlock(&rtc_lock);
 
 	return retval;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/lib/csum_partial_copy.c linux.18p8/arch/alpha/lib/csum_partial_copy.c
--- linux.vanilla/arch/alpha/lib/csum_partial_copy.c	Fri Apr 21 12:45:44 2000
+++ linux.18p8/arch/alpha/lib/csum_partial_copy.c	Sat Sep  2 23:17:03 2000
@@ -173,11 +173,11 @@
 {
 	unsigned long carry = 0;
 	unsigned long word;
+	unsigned long second_dest;
 	int err = 0;
 
 	mskql(partial_dest, doff, partial_dest);
 	while (len >= 0) {
-		unsigned long second_dest;
 		err |= __get_user(word, src);
 		len -= 8;
 		insql(word, doff, second_dest);
@@ -189,35 +189,30 @@
 		carry = checksum < word;
 		dst++;
 	}
-	len += doff;
-	checksum += carry;
-	if (len >= 0) {
-		unsigned long second_dest;
+	len += 8;
+	if (len) {
+		checksum += carry;
 		err |= __get_user(word, src);
-		mskql(word, len-doff, word);
+		mskql(word, len, word);
+		len -= 8;
 		checksum += word;
 		insql(word, doff, second_dest);
-		stq_u(partial_dest | second_dest, dst);
+		len += doff;
 		carry = checksum < word;
-		if (len) {
-			ldq_u(second_dest, dst+1);
+		partial_dest |= second_dest;
+		if (len >= 0) {
+			stq_u(partial_dest, dst);
+			if (!len) goto out;
+			dst++;
 			insqh(word, doff, partial_dest);
-			mskqh(second_dest, len, second_dest);
-			stq_u(partial_dest | second_dest, dst+1);
 		}
-		checksum += carry;
-	} else if (len & 7) {
-		unsigned long second_dest;
-		err |= __get_user(word, src);
-		ldq_u(second_dest, dst);
-		mskql(word, len-doff, word);
-		checksum += word;
-		mskqh(second_dest, len, second_dest);
-		carry = checksum < word;
-		insql(word, doff, word);
-		stq_u(partial_dest | word | second_dest, dst);
-		checksum += carry;
+		doff = len;
 	}
+	ldq_u(second_dest, dst);
+	mskqh(second_dest, doff, second_dest);
+	stq_u(partial_dest | second_dest, dst);
+out:
+	checksum += carry;
 	if (err) *errp = err;
 	return checksum;
 }
@@ -283,7 +278,7 @@
 			stq_u(partial_dest | second_dest, dst+1);
 		}
 		checksum += carry;
-	} else if (len & 7) {
+	} else {
 		unsigned long second, word;
 		unsigned long second_dest;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/vmlinux.lds linux.18p8/arch/alpha/vmlinux.lds
--- linux.vanilla/arch/alpha/vmlinux.lds	Sun Jun 11 21:44:09 2000
+++ linux.18p8/arch/alpha/vmlinux.lds	Fri Sep 15 12:46:07 2000
@@ -27,11 +27,22 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
+  . = ALIGN(16);		/* __setup() commandline parameters */
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+
+  . = ALIGN(8);
+  __initcall_start = .;		/* the init functions to be called */
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
+
   . = ALIGN(2*8192);	/* Align double page for init_task_union */
   __init_end = .;
 
   /* The initial task and kernel stack */
   init_task : { *(init_task) }
+
 
   /* Global data */
   _data = .;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/vmlinux-armo.lds linux.18p8/arch/arm/vmlinux-armo.lds
--- linux.vanilla/arch/arm/vmlinux-armo.lds	Fri Apr 21 12:45:45 2000
+++ linux.18p8/arch/arm/vmlinux-armo.lds	Tue Sep  5 22:20:06 2000
@@ -41,8 +41,16 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
+  . = ALIGN(16);		/* __setup() commandline parameters */
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;		/* the init functions to be called */
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
   . = ALIGN(32768);
   __init_end = .;
+
 
   __bss_start = .;		/* BSS */
   .bss : {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/vmlinux-armv.lds linux.18p8/arch/arm/vmlinux-armv.lds
--- linux.vanilla/arch/arm/vmlinux-armv.lds	Fri Apr 21 12:45:45 2000
+++ linux.18p8/arch/arm/vmlinux-armv.lds	Tue Sep  5 22:20:06 2000
@@ -41,8 +41,17 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
+  . = ALIGN(16);		/* __setup() commandline parameters */
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+ 
+  __initcall_start = .;		/* the init functions to be called */
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
+
 
   __bss_start = .;		/* BSS */
   .bss : {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/config.in linux.18p8/arch/i386/config.in
--- linux.vanilla/arch/i386/config.in	Sat Sep  9 18:42:32 2000
+++ linux.18p8/arch/i386/config.in	Mon Sep 11 18:14:04 2000
@@ -33,6 +33,10 @@
   define_bool CONFIG_X86_GOOD_APIC y
 fi
 
+tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
+tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
+tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
+
 choice 'Maximum Physical Memory' \
 	"1GB		CONFIG_1GB \
 	 2GB		CONFIG_2GB" 1GB
@@ -109,7 +113,6 @@
   bool '   Enable PM at boot time' CONFIG_APM_DO_ENABLE
   bool '   Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
   bool '   Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
-  bool '   Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
   bool '   RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
   bool '   Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
   bool '   Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
@@ -176,7 +179,7 @@
 
 source drivers/char/Config.in
 
-# source drivers/usb/Config.in
+source drivers/usb/Config.in
 
 source fs/Config.in
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/defconfig linux.18p8/arch/i386/defconfig
--- linux.vanilla/arch/i386/defconfig	Fri Apr 21 12:45:45 2000
+++ linux.18p8/arch/i386/defconfig	Sun Sep  3 14:00:02 2000
@@ -166,6 +166,7 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/Makefile linux.18p8/arch/i386/kernel/Makefile
--- linux.vanilla/arch/i386/kernel/Makefile	Sat Sep  9 18:42:32 2000
+++ linux.18p8/arch/i386/kernel/Makefile	Mon Sep 11 18:14:04 2000
@@ -35,6 +35,30 @@
   endif
 endif
 
+ifeq ($(CONFIG_MICROCODE),y)
+OX_OBJS += microcode.o
+else
+  ifeq ($(CONFIG_MICROCODE),m)
+  MX_OBJS += microcode.o
+  endif
+endif
+
+ifeq ($(CONFIG_X86_MSR),y)
+OX_OBJS += msr.o
+else
+  ifeq ($(CONFIG_X86_MSR),m)
+  MX_OBJS += msr.o
+  endif
+endif
+
+ifeq ($(CONFIG_X86_CPUID),y)
+OX_OBJS += cpuid.o
+else
+  ifeq ($(CONFIG_X86_CPUID),m)
+  MX_OBJS += cpuid.o
+  endif
+endif
+
 ifdef CONFIG_APM
 OX_OBJS += apm.o
 endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/apm.c linux.18p8/arch/i386/kernel/apm.c
--- linux.vanilla/arch/i386/kernel/apm.c	Sun Jun 11 21:44:09 2000
+++ linux.18p8/arch/i386/kernel/apm.c	Mon Sep 11 17:05:42 2000
@@ -170,18 +170,6 @@
 #include <asm/desc.h>
 #include <asm/softirq.h>
 
-/* 2.2-2.3 Compatability defines */
-#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL
-#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL}
-#define __setup(x, y)
-#define module_init(x)
-#define set_current_state(a) current->state = (a)
-#define create_proc_info_entry(n, m, b, g) \
-	{ \
-		struct proc_dir_entry *r = create_proc_entry(n, m, b); \
-		if (r) r->get_info = g; \
-	}
-
 EXPORT_SYMBOL(apm_register_callback);
 EXPORT_SYMBOL(apm_unregister_callback);
 
@@ -1438,7 +1426,7 @@
 	return 0;
 }
 
-void __init apm_setup(char *str, int *dummy)
+static int __init apm_setup(char *str)
 {
 	int	invert;
 
@@ -1458,6 +1446,7 @@
 		if (str != NULL)
 			str += strspn(str, ", \t");
 	}
+	return 1;
 }
 
 __setup("apm=", apm_setup);
@@ -1476,13 +1465,12 @@
 	&apm_bios_fops
 };
 
-#define APM_INIT_ERROR_RETURN	return
 
-void __init apm_init(void)
+static int __init apm_init(void)
 {
 	if (apm_bios_info.version == 0) {
 		printk(KERN_INFO "apm: BIOS not found.\n");
-		APM_INIT_ERROR_RETURN;
+		return -ENODEV;
 	}
 	printk(KERN_INFO
 		"apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
@@ -1492,7 +1480,7 @@
 		driver_version);
 	if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
 		printk(KERN_INFO "apm: no 32 bit BIOS support\n");
-		APM_INIT_ERROR_RETURN;
+		return -ENODEV;
 	}
 
 	/*
@@ -1521,11 +1509,11 @@
 
 	if (apm_disabled) {
 		printk(KERN_NOTICE "apm: disabled on user request.\n");
-		APM_INIT_ERROR_RETURN;
+		return -ENODEV;
 	}
 	if ((smp_num_cpus > 1) && !power_off_enabled) {
 		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
-		APM_INIT_ERROR_RETURN;
+		return -ENODEV;
 	}
 
 	/*
@@ -1573,7 +1561,7 @@
 	if (smp_num_cpus > 1) {
 		printk(KERN_NOTICE
 		   "apm: disabled - APM is not SMP safe (power off active).\n");
-		APM_INIT_ERROR_RETURN;
+		return 0;
 	}
 
 	init_timer(&apm_timer);
@@ -1586,6 +1574,7 @@
 #ifdef CONFIG_APM_CPU_IDLE
 	acpi_idle = apm_cpu_idle;
 #endif
+	return 0;
 }
 
 module_init(apm_init)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/bios32.c linux.18p8/arch/i386/kernel/bios32.c
--- linux.vanilla/arch/i386/kernel/bios32.c	Sun Jun 11 21:44:09 2000
+++ linux.18p8/arch/i386/kernel/bios32.c	Sat Sep  2 23:44:17 2000
@@ -1055,7 +1055,6 @@
 	/*
 	 * Find and scan busses behind ServerWorks north bridge chips
 	 */
-	struct pci_bus *bus;
 	unsigned char busno, busmax;
 	pci_probe |= PCI_NO_PEER_FIXUP;
 	pci_read_config_byte(d, 0x44, &busno);
@@ -1070,7 +1069,6 @@
 	/*
 	 * Find and scan busses behind RCC LE north bridge chips
 	 */
-	struct pci_bus *bus;
 	unsigned char busno, busmax;
 	pci_probe |= PCI_NO_PEER_FIXUP;
 	pci_read_config_byte(d, 0xc8, &busno);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/bluesmoke.c linux.18p8/arch/i386/kernel/bluesmoke.c
--- linux.vanilla/arch/i386/kernel/bluesmoke.c	Sat Sep  9 18:42:32 2000
+++ linux.18p8/arch/i386/kernel/bluesmoke.c	Fri Sep  8 16:30:58 2000
@@ -22,7 +22,7 @@
 	if(mcgstl&(1<<0))	/* Recoverable ? */
 		recover=0;
 
-	printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x", smp_processor_id(), mcgstl, mcgsth);
+	printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl);
 	
 	for(i=0;i<banks;i++)
 	{
@@ -46,7 +46,10 @@
 				printk(" at %08x%08x", 
 					high, low);
 			}
-			wrmsr(0x401+i*4, low, high);
+			/* Clear it */
+			wrmsr(0x401+i*4, 0UL, 0UL);
+			/* Serialize */
+			wmb();
 		}
 	}
 	
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/cpuid.c linux.18p8/arch/i386/kernel/cpuid.c
--- linux.vanilla/arch/i386/kernel/cpuid.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/arch/i386/kernel/cpuid.c	Mon Sep 11 18:14:04 2000
@@ -0,0 +1,171 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ *   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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+
+/*
+ * cpuid.c
+ *
+ * x86 CPUID access device
+ *
+ * This device is accessed by lseek() to the appropriate CPUID level
+ * and then read in chunks of 16 bytes.  A larger size means multiple
+ * reads of consecutive levels.
+ *
+ * This driver uses /dev/cpu/%d/cpuid where %d is the minor number, and on
+ * an SMP box will direct the access to CPU %d.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/major.h>
+
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_SMP
+
+struct cpuid_command {
+  int cpu;
+  u32 reg;
+  u32 *data;
+};
+
+static void cpuid_smp_cpuid(void *cmd_block)
+{
+  struct cpuid_command *cmd = (struct cpuid_command *) cmd_block;
+  
+  if ( cmd->cpu == smp_processor_id() )
+    cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]);
+}
+
+extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+{
+  struct cpuid_command cmd;
+  
+  if ( cpu == smp_processor_id() ) {
+    cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
+  } else {
+    cmd.cpu  = cpu;
+    cmd.reg  = reg;
+    cmd.data = data;
+    
+    smp_call_function(cpuid_smp_cpuid, &cmd, 1, 1);
+  }
+}
+#else /* ! CONFIG_SMP */
+
+extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+{
+  cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
+}
+
+#endif /* ! CONFIG_SMP */
+
+static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
+{
+  switch (orig) {
+  case 0:
+    file->f_pos = offset;
+    return file->f_pos;
+  case 1:
+    file->f_pos += offset;
+    return file->f_pos;
+  default:
+    return -EINVAL;	/* SEEK_END not supported */
+  }
+}
+
+static ssize_t cpuid_read(struct file * file, char * buf,
+			size_t count, loff_t *ppos)
+{
+  u32 *tmp = (u32 *)buf;
+  u32 data[4];
+  size_t rv;
+  u32 reg = *ppos;
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  
+  if ( count % 16 )
+    return -EINVAL; /* Invalid chunk size */
+  
+  for ( rv = 0 ; count ; count -= 16 ) {
+    do_cpuid(cpu, reg, data);
+    if ( copy_to_user(tmp,&data,16) )
+      return -EFAULT;
+    tmp += 4;
+    *ppos = reg++;
+  }
+  
+  return ((char *)tmp) - buf;
+}
+
+static int cpuid_open(struct inode *inode, struct file *file)
+{
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  struct cpuinfo_x86 *c = &(cpu_data)[cpu];
+
+  if ( !(cpu_online_map & (1UL << cpu)) )
+    return -ENXIO;		/* No such CPU */
+  if ( c->cpuid_level < 0 )
+    return -EIO;		/* CPUID not supported */
+  
+  return 0;
+}
+
+/*
+ * File operations we support
+ */
+static struct file_operations cpuid_fops = {
+  llseek:	cpuid_seek,
+  read:		cpuid_read,
+  open:		cpuid_open,
+};
+
+int __init cpuid_init(void)
+{
+  if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) {
+    printk(KERN_ERR "cpuid: unable to get major %d for cpuid\n",
+	   CPUID_MAJOR);
+    return -EBUSY;
+  }
+
+  return 0;
+}
+
+#ifdef MODULE
+static void cpuid_exit(void)
+{
+}
+
+int init_module (void)
+{
+	return cpuid_init();
+}
+void cleanup_module (void)
+{
+	cpuid_exit();
+}
+#endif
+	
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
+MODULE_DESCRIPTION("x86 generic CPUID driver");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/i386_ksyms.c linux.18p8/arch/i386/kernel/i386_ksyms.c
--- linux.vanilla/arch/i386/kernel/i386_ksyms.c	Fri Apr 21 12:45:45 2000
+++ linux.18p8/arch/i386/kernel/i386_ksyms.c	Tue Sep 12 13:14:57 2000
@@ -20,6 +20,7 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern int dump_fpu(elf_fpregset_t *);
+extern spinlock_t rtc_lock;
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
 extern struct drive_info_struct drive_info;
@@ -119,3 +120,5 @@
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
 #endif
+
+EXPORT_SYMBOL(rtc_lock);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/microcode.c linux.18p8/arch/i386/kernel/microcode.c
--- linux.vanilla/arch/i386/kernel/microcode.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/arch/i386/kernel/microcode.c	Tue Sep  5 22:41:52 2000
@@ -0,0 +1,336 @@
+/*
+ *	CPU Microcode Update interface for Linux
+ *
+ *	Copyright (C) 2000 Tigran Aivazian
+ *
+ *	This driver allows to upgrade microcode on Intel processors
+ *	belonging to P6 family - PentiumPro, Pentium II, Pentium III etc.
+ *
+ *	Reference: Section 8.10 of Volume III, Intel Pentium III Manual, 
+ *	Order Number 243192 or download from:
+ *		
+ *	http://developer.intel.com/design/pentiumii/manuals/243192.htm
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	1.0	16 February 2000, Tigran Aivazian <tigran@sco.com>
+ *		Initial release.
+ *	1.01	18 February 2000, Tigran Aivazian <tigran@sco.com>
+ *		Added read() support + cleanups.
+ *	1.02	21 February 2000, Tigran Aivazian <tigran@sco.com>
+ *		Added 'device trimming' support. open(O_WRONLY) zeroes
+ *		and frees the saved copy of applied microcode.
+ *	1.03	29 February 2000, Tigran Aivazian <tigran@sco.com>
+ *		Made to use devfs (/dev/cpu/microcode) + cleanups.
+ *	1.04	06 June 2000, Simon Trimmer <simon@veritas.com>
+ *		Added misc device support (now uses both devfs and misc).
+ *		Added MICROCODE_IOCFREE ioctl to clear memory.
+ *	1.05	09 June 2000, Simon Trimmer <simon@veritas.com>
+ *		Messages for error cases (non intel & no suitable microcode).
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/miscdevice.h>
+#include <linux/smp.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+
+#define MICROCODE_MINOR 184
+#define MICROCODE_IOCFREE _IO('6',0)
+struct microcode {
+	unsigned int hdrver;
+	unsigned int rev;
+	unsigned int date;
+	unsigned int sig;
+	unsigned int cksum;
+	unsigned int ldrver;
+	unsigned int pf;
+	unsigned int reserved[5];
+	unsigned int bits[500];
+};
+
+#define MICROCODE_VERSION 	"1.05"
+
+MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
+EXPORT_NO_SYMBOLS;
+
+/* VFS interface */
+static int microcode_open(struct inode *, struct file *);
+static int microcode_release(struct inode *, struct file *);
+static ssize_t microcode_read(struct file *, char *, size_t, loff_t *);
+static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *);
+static int microcode_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+
+/* internal helpers to do the work */
+static int do_microcode_update(void);
+static void do_update_one(void *);
+
+/*
+ *  Bits in microcode_status. (31 bits of room for future expansion)
+ */
+#define MICROCODE_IS_OPEN	0	/* set if device is in use */
+
+static unsigned long microcode_status;
+
+/* the actual array of microcode blocks, each 2048 bytes */
+static struct microcode *microcode;
+static unsigned int microcode_num;
+static char *mc_applied; /* holds an array of applied microcode blocks */
+static unsigned int mc_fsize;
+
+static struct file_operations microcode_fops = {
+	read:		microcode_read,
+	write:		microcode_write,
+	ioctl:		microcode_ioctl,
+	open:		microcode_open,
+	release:	microcode_release,
+};
+
+static struct miscdevice microcode_dev = {
+	minor: MICROCODE_MINOR,
+	name:	"microcode",
+	fops:	&microcode_fops,
+};
+
+int __init microcode_init(void)
+{
+	int error = 0;
+
+	if (misc_register(&microcode_dev) < 0) {
+		printk(KERN_WARNING 
+			"microcode: can't misc_register on minor=%d\n",
+			MICROCODE_MINOR);
+		error = 1;
+	}
+	printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", 
+			MICROCODE_VERSION);
+	return 0;
+}
+
+#ifdef MODULE
+static void microcode_exit(void)
+{
+	misc_deregister(&microcode_dev);
+	if (mc_applied)
+		kfree(mc_applied);
+	printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", 
+			MICROCODE_VERSION);
+}
+
+int init_module(void)
+{
+	return microcode_init();
+}
+void cleanup_module(void)
+{
+	microcode_exit();
+}
+#endif
+
+/*
+ * We enforce only one user at a time here with open/close.
+ */
+static int microcode_open(struct inode *inode, struct file *file)
+{
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	/* one at a time, please */
+	if (test_and_set_bit(MICROCODE_IS_OPEN, &microcode_status))
+		return -EBUSY;
+
+	return 0;
+}
+
+static int microcode_release(struct inode *inode, struct file *file)
+{
+	clear_bit(MICROCODE_IS_OPEN, &microcode_status);
+	return 0;
+}
+
+/* a pointer to 'struct update_req' is passed to the IPI handler = do_update_one()
+ * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
+ * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
+ */
+struct update_req {
+	int err;
+	int slot;
+} update_req[NR_CPUS];
+
+static int do_microcode_update(void)
+{
+	int i, error = 0, err;
+	struct microcode *m;
+
+	if (smp_call_function(do_update_one, (void *)update_req, 1, 1) != 0)
+		panic("do_microcode_update(): timed out waiting for other CPUs\n");
+
+	do_update_one((void *)update_req);
+
+	for (i=0; i<smp_num_cpus; i++) {
+		err = update_req[i].err;
+		error += err;
+		if (!err) {
+			m = (struct microcode *)mc_applied + i;
+			memcpy(m, &microcode[update_req[i].slot], sizeof(struct microcode));
+		}
+	}
+	return error;
+}
+
+static void do_update_one(void *arg)
+{
+	int cpu_num = smp_processor_id();
+	struct cpuinfo_x86 *c = cpu_data + cpu_num;
+	struct update_req *req = (struct update_req *)arg + cpu_num;
+	unsigned int pf = 0, val[2], rev, sig;
+	int i,found=0;
+
+	req->err = 1; /* be pessimistic */
+
+	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6){
+		printk(KERN_ERR "microcode: CPU%d not an Intel P6\n", cpu_num );
+		return;
+	}
+
+	sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8);
+
+	if (c->x86_model >= 5) {
+		/* get processor flags from BBL_CR_OVRD MSR (0x17) */
+		rdmsr(0x17, val[0], val[1]);
+		pf = 1 << ((val[1] >> 18) & 7);
+	}
+
+	for (i=0; i<microcode_num; i++)
+		if (microcode[i].sig == sig && microcode[i].pf == pf &&
+		    microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
+
+			found=1;
+
+			rdmsr(0x8B, val[0], rev);
+			if (microcode[i].rev <= rev) {
+				printk(KERN_ERR 
+					"microcode: CPU%d not 'upgrading' to earlier revision"
+					" %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
+			} else { 
+				int sum = 0;
+				struct microcode *m = &microcode[i];
+				unsigned int *sump = (unsigned int *)(m+1);
+
+				while (--sump >= (unsigned int *)m)
+					sum += *sump;
+				if (sum != 0) {
+					printk(KERN_ERR "microcode: CPU%d aborting, "
+							"bad checksum\n", cpu_num);
+					break;
+				}
+
+				wrmsr(0x79, (unsigned int)(m->bits), 0);
+				__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+				rdmsr(0x8B, val[0], val[1]);
+
+				req->err = 0;
+				req->slot = i;
+				printk(KERN_ERR "microcode: CPU%d updated from revision "
+						"%d to %d, date=%08x\n", 
+						cpu_num, rev, val[1], m->date);
+			}
+			break;
+		}
+
+	if(!found)
+		printk(KERN_ERR "microcode: found no data for CPU%d (sig=%x, pflags=%d)\n", cpu_num, sig, pf);
+}
+
+static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
+{
+	if (*ppos >= mc_fsize)
+		return 0;
+	if (*ppos + len > mc_fsize)
+		len = mc_fsize - *ppos;
+	if (copy_to_user(buf, mc_applied + *ppos, len))
+		return -EFAULT;
+	*ppos += len;
+	return len;
+}
+
+static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
+{
+	ssize_t ret;
+
+	if (len % sizeof(struct microcode) != 0) {
+		printk(KERN_ERR "microcode: can only write in N*%d bytes units\n", 
+			sizeof(struct microcode));
+		return -EINVAL;
+	}
+	if (!mc_applied) {
+		mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode),
+				GFP_KERNEL);
+		if (!mc_applied) {
+			printk(KERN_ERR "microcode: out of memory for saved microcode\n");
+			return -ENOMEM;
+		}
+		memset(mc_applied, 0, mc_fsize);
+	}
+	
+	lock_kernel();
+	microcode_num = len/sizeof(struct microcode);
+	microcode = vmalloc(len);
+	if (!microcode) {
+		ret = -ENOMEM;
+		goto out_unlock;
+	}
+	if (copy_from_user(microcode, buf, len)) {
+		ret = -EFAULT;
+		goto out_fsize;
+	}
+	if(do_microcode_update()) {
+		ret = -EIO;
+		goto out_fsize;
+	} else {
+		mc_fsize = smp_num_cpus * sizeof(struct microcode);
+		ret = (ssize_t)len;
+	}
+out_fsize:
+	vfree(microcode);
+out_unlock:
+	unlock_kernel();
+	return ret;
+}
+
+static int microcode_ioctl(struct inode *inode, struct file *file, 
+		unsigned int cmd, unsigned long arg)
+{
+	switch(cmd) {
+		case MICROCODE_IOCFREE:
+			if (mc_applied) {
+				memset(mc_applied, 0, mc_fsize);
+				kfree(mc_applied);
+				mc_applied = NULL;
+				printk(KERN_WARNING 
+					"microcode: freed %d bytes\n", mc_fsize);
+				mc_fsize = 0;
+				return 0;
+			}
+			return -ENODATA;
+
+		default:
+			printk(KERN_ERR "microcode: unknown ioctl cmd=%d\n",
+					cmd);
+			return -EINVAL;
+	}
+	/* NOT REACHED */
+	return -EINVAL;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/msr.c linux.18p8/arch/i386/kernel/msr.c
--- linux.vanilla/arch/i386/kernel/msr.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/arch/i386/kernel/msr.c	Mon Sep 11 18:14:04 2000
@@ -0,0 +1,278 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2000 H. Peter Anvin - All Rights Reserved
+ *
+ *   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, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * msr.c
+ *
+ * x86 MSR access device
+ *
+ * This device is accessed by lseek() to the appropriate register number
+ * and then read/write in chunks of 8 bytes.  A larger size means multiple
+ * reads or writes of the same register.
+ *
+ * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on
+ * an SMP box will direct the access to CPU %d.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/smp.h>
+#include <linux/major.h>
+
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+/* Note: "err" is handled in a funny way below.  Otherwise one version
+   of gcc or another breaks. */
+
+extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
+{
+  int err;
+
+  asm volatile(
+	       "1:	wrmsr\n"
+	       "2:\n"
+	       ".section .fixup,\"ax\"\n"
+	       "3:	movl %4,%0\n"
+	       "	jmp 2b\n"
+	       ".previous\n"
+	       ".section __ex_table,\"a\"\n"
+	       "	.align 4\n"
+	       "	.long 1b,3b\n"
+	       ".previous"
+	       : "=&bDS" (err)
+	       : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0));
+
+  return err;
+}
+
+extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
+{
+  int err;
+
+  asm volatile(
+	       "1:	rdmsr\n"
+	       "2:\n"
+	       ".section .fixup,\"ax\"\n"
+	       "3:	movl %4,%0\n"
+	       "	jmp 2b\n"
+	       ".previous\n"
+	       ".section __ex_table,\"a\"\n"
+	       "	.align 4\n"
+	       "	.long 1b,3b\n"
+	       ".previous"
+	       : "=&bDS" (err), "=a" (*eax), "=d" (*edx)
+	       : "c" (reg), "i" (-EIO), "0" (0));
+
+  return err;
+}
+
+#ifdef CONFIG_SMP
+
+struct msr_command {
+  int cpu;
+  int err;
+  u32 reg;
+  u32 data[2];
+};
+
+static void msr_smp_wrmsr(void *cmd_block)
+{
+  struct msr_command *cmd = (struct msr_command *) cmd_block;
+  
+  if ( cmd->cpu == smp_processor_id() )
+    cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]);
+}
+
+static void msr_smp_rdmsr(void *cmd_block)
+{
+  struct msr_command *cmd = (struct msr_command *) cmd_block;
+  
+  if ( cmd->cpu == smp_processor_id() )
+    cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
+}
+
+extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+{
+  struct msr_command cmd;
+
+  if ( cpu == smp_processor_id() ) {
+    return wrmsr_eio(reg, eax, edx);
+  } else {
+    cmd.cpu = cpu;
+    cmd.reg = reg;
+    cmd.data[0] = eax;
+    cmd.data[1] = edx;
+    
+    smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
+    return cmd.err;
+  }
+}
+
+extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+{
+  struct msr_command cmd;
+
+  if ( cpu == smp_processor_id() ) {
+    return rdmsr_eio(reg, eax, edx);
+  } else {
+    cmd.cpu = cpu;
+    cmd.reg = reg;
+
+    smp_call_function(msr_smp_rdmsr, &cmd, 1, 1);
+    
+    *eax = cmd.data[0];
+    *edx = cmd.data[1];
+
+    return cmd.err;
+  }
+}
+
+#else /* ! CONFIG_SMP */
+
+extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+{
+  return wrmsr_eio(reg, eax, edx);
+}
+
+extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+{
+  return rdmsr_eio(reg, eax, edx);
+}
+
+#endif /* ! CONFIG_SMP */
+
+static loff_t msr_seek(struct file *file, loff_t offset, int orig)
+{
+  switch (orig) {
+  case 0:
+    file->f_pos = offset;
+    return file->f_pos;
+  case 1:
+    file->f_pos += offset;
+    return file->f_pos;
+  default:
+    return -EINVAL;	/* SEEK_END not supported */
+  }
+}
+
+static ssize_t msr_read(struct file * file, char * buf,
+			size_t count, loff_t *ppos)
+{
+  u32 *tmp = (u32 *)buf;
+  u32 data[2];
+  size_t rv;
+  u32 reg = *ppos;
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  int err;
+
+  if ( count % 8 )
+    return -EINVAL; /* Invalid chunk size */
+  
+  for ( rv = 0 ; count ; count -= 8 ) {
+    err = do_rdmsr(cpu, reg, &data[0], &data[1]);
+    if ( err )
+      return err;
+    if ( copy_to_user(tmp,&data,8) )
+      return -EFAULT;
+    tmp += 2;
+  }
+
+  return ((char *)tmp) - buf;
+}
+
+static ssize_t msr_write(struct file * file, const char * buf,
+			 size_t count, loff_t *ppos)
+{
+  const u32 *tmp = (const u32 *)buf;
+  u32 data[2];
+  size_t rv;
+  u32 reg = *ppos;
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  int err;
+
+  if ( count % 8 )
+    return -EINVAL; /* Invalid chunk size */
+  
+  for ( rv = 0 ; count ; count -= 8 ) {
+    if ( copy_from_user(&data,tmp,8) )
+      return -EFAULT;
+    err = do_wrmsr(cpu, reg, data[0], data[1]);
+    if ( err )
+      return err;
+    tmp += 2;
+  }
+
+  return ((char *)tmp) - buf;
+}
+
+static int msr_open(struct inode *inode, struct file *file)
+{
+  int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
+  struct cpuinfo_x86 *c = &(cpu_data)[cpu];
+  
+  if ( !(cpu_online_map & (1UL << cpu)) )
+    return -ENXIO;		/* No such CPU */
+  if ( !(c->x86_capability & X86_FEATURE_MSR) )
+    return -EIO;		/* MSR not supported */
+  
+  return 0;
+}
+
+/*
+ * File operations we support
+ */
+static struct file_operations msr_fops = {
+  llseek:	msr_seek,
+  read:		msr_read,
+  write:	msr_write,
+  open:		msr_open,
+};
+
+int __init msr_init(void)
+{
+  if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) {
+    printk(KERN_ERR "msr: unable to get major %d for msr\n",
+	   MSR_MAJOR);
+    return -EBUSY;
+  }
+  
+  return 0;
+}
+
+#ifdef MODULE
+static void msr_exit(void)
+{
+}
+
+int init_module(void)
+{
+	return msr_init();
+}
+void cleanup_module(void)
+{
+	msr_exit();
+}
+#endif
+
+MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
+MODULE_DESCRIPTION("x86 generic MSR driver");
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/mtrr.c linux.18p8/arch/i386/kernel/mtrr.c
--- linux.vanilla/arch/i386/kernel/mtrr.c	Fri Apr 21 12:45:45 2000
+++ linux.18p8/arch/i386/kernel/mtrr.c	Fri Sep 15 12:42:22 2000
@@ -305,7 +305,7 @@
 static unsigned int ascii_buf_bytes = 0;
 #endif
 static unsigned int *usage_table = NULL;
-static spinlock_t main_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t main_lock  __attribute((unused)) = SPIN_LOCK_UNLOCKED;
 
 /*  Private functions  */
 #ifdef CONFIG_PROC_FS
@@ -337,7 +337,8 @@
 	if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */
 	/* else fall through */
       case X86_VENDOR_CENTAUR:
-	return;
+	if(boot_cpu_data.x86 != 6)
+		return;
 	/*break;*/
     }
     /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
@@ -361,6 +362,7 @@
     {
       case X86_VENDOR_AMD:
       case X86_VENDOR_INTEL:
+      case X86_VENDOR_CENTAUR:
 	/*  Disable MTRRs, and set the default type to uncached  */
 	rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
 	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
@@ -384,8 +386,11 @@
 	if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */
 	/* else fall through */
       case X86_VENDOR_CENTAUR:
-	__restore_flags (ctxt->flags);
-	return;
+	if(boot_cpu_data.x86 != 6)
+	{
+		__restore_flags (ctxt->flags);
+		return;
+	}
 	/*break;*/
     }
     /*  Flush caches and TLBs  */
@@ -396,6 +401,7 @@
     {
       case X86_VENDOR_AMD:
       case X86_VENDOR_INTEL:
+      case X86_VENDOR_CENTAUR:
 	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
 	break;
       case X86_VENDOR_CYRIX:
@@ -436,7 +442,14 @@
 	/*  Cyrix have 8 ARRs  */
       case X86_VENDOR_CENTAUR:
         /*  and Centaur has 8 MCR's  */
-	return 8;
+	if(boot_cpu_data.x86==5)
+		return 8;
+	/*  the cyrix III has intel compatible MTRR */
+	if(boot_cpu_data.x86==6)
+	{
+		rdmsr (MTRRcap_MSR, config, dummy);
+		return (config & 0xff);
+	}
 	/*break;*/
     }
     return 0;
@@ -452,12 +465,15 @@
       case X86_VENDOR_AMD:
 	if (boot_cpu_data.x86 < 6) return 1; /* pre-Athlon CPUs */
 	/* else fall through */
+      case X86_VENDOR_CENTAUR:
+        if (boot_cpu_data.x86 == 5)
+        	return 1;	/* C6 */
+        /* CyrixIII is Intel like */
       case X86_VENDOR_INTEL:
 	rdmsr (MTRRcap_MSR, config, dummy);
 	return (config & (1<<10));
 	/*break;*/
       case X86_VENDOR_CYRIX:
-      case X86_VENDOR_CENTAUR:
 	return 1;
 	/*break;*/
     }
@@ -1135,7 +1151,7 @@
 	    printk ("mtrr: size: %lx  base: %lx\n", size, base);
 	    return -EINVAL;
 	}
-        if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR)
+        if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR && boot_cpu_data.x86 == 5)
 	{
 	    if (centaur_ctx->type_bits[type]==0) {
 		printk ("mtrr: type not supported\n");
@@ -1758,8 +1774,16 @@
 	get_free_region = cyrix_get_free_region;
 	break;
      case X86_VENDOR_CENTAUR:
-        get_mtrr = centaur_get_mcr;
-        set_mtrr_up = centaur_set_mcr_up;
+        if(boot_cpu_data.x86 == 5)
+        {
+        	get_mtrr = centaur_get_mcr;
+	        set_mtrr_up = centaur_set_mcr_up;
+	}
+	if(boot_cpu_data.x86 == 6)
+	{
+		get_mtrr = intel_get_mtrr;
+		set_mtrr_up = intel_set_mtrr_up;
+	}
         break;
     }
 }   /*  End Function mtrr_setup  */
@@ -1783,8 +1807,11 @@
       case X86_VENDOR_CYRIX:
 	cyrix_arr_init ();
 	break;
-      case X86_VENDOR_CENTAUR:
-        centaur_mcr_init ();
+      case X86_VENDOR_CENTAUR:		/* C6 and Cyrix III have different ones */
+      	if(boot_cpu_data.x86 == 5)
+	        centaur_mcr_init ();
+	if(boot_cpu_data.x86 == 6)
+		get_mtrr_state(&smp_mtrr_state);
         break;
     }
 }   /*  End Function mtrr_init_boot_cpu  */
@@ -1856,7 +1883,8 @@
 	cyrix_arr_init ();
 	break;
       case X86_VENDOR_CENTAUR:
-        centaur_mcr_init ();
+        if(boot_cpu_data.x86 == 5)
+        	centaur_mcr_init ();
         break;
     }
 #  endif  /*  !__SMP__  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/setup.c linux.18p8/arch/i386/kernel/setup.c
--- linux.vanilla/arch/i386/kernel/setup.c	Sat Sep  9 18:42:32 2000
+++ linux.18p8/arch/i386/kernel/setup.c	Thu Sep 14 01:10:04 2000
@@ -16,19 +16,25 @@
  *  Intel Mobile Pentium II detection fix. Sean Gilley, June 1999.
  *
  *  IDT Winchip tweaks, misc clean ups.
- *	Dave Jones <dave@powertweak.com>, August 1999
+ *	Dave Jones <davej@suse.de>, August 1999
  *
  *	Added proper L2 cache detection for Coppermine
  *	Dragan Stancevic <visitor@valinux.com>, October 1999
  *
  *	Improved Intel cache detection.
- *	Dave Jones <dave@powertweak.com>, October 1999
+ *	Dave Jones <davej@suse.de>, October 1999
  *
  *	Added proper Cascades CPU and L2 cache detection for Cascades
  *	and 8-way type cache happy bunch from Intel:^)
  *	Dragan Stancevic <visitor@valinux.com>, May 2000
  *
  *	Transmeta CPU detection.  H. Peter Anvin <hpa@zytor.com>, May 2000
+ *
+ *	Cleaned up get_model_name(), AMD_model(), added display_cacheinfo().
+ *	Dave Jones <davej@suse.de>, September 2000
+ *
+ *	Added Cyrix III initial detection code
+ *	Alan Cox <alan@redhat.com>, Septembr 2000
  */
 
 /*
@@ -428,19 +434,16 @@
 	conswitchp = &dummy_con;
 #endif
 #endif
-	/*
-	 *	Check the bugs that will bite us before we get booting
-	 */
-
 }
 
+
 __initfunc(static int get_model_name(struct cpuinfo_x86 *c))
 {
-	unsigned int n, dummy, *v, ecx, edx;
+	unsigned int n, dummy, *v;
 
 	/* 
 	 * Actually we must have cpuid or we could never have
-	 * figured out that this was AMD/Cyrix/Transmeta
+	 * figured out that this was AMD/Centaur/Cyrix/Transmeta
 	 * from the vendor info :-).
 	 */
 
@@ -454,49 +457,44 @@
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
 	c->x86_model_id[48] = 0;
 	
-	switch(c->x86_vendor)
-	{
-	case X86_VENDOR_AMD:
-		/*  Set MTRR capability flag if appropriate  */
-		if(boot_cpu_data.x86 == 5) {
-			if((boot_cpu_data.x86_model == 9) ||
-			   ((boot_cpu_data.x86_model == 8) && 
-			    (boot_cpu_data.x86_mask >= 8)))
-				c->x86_capability |= X86_FEATURE_MTRR;
-		}
+	return 1;
+}
 
-		/* Fall through */
 
-	case X86_VENDOR_TRANSMETA:
-		/* Cache information */
-		if (n >= 0x80000005){
-			cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
-			printk("CPU: L1 I Cache: %dK  L1 D Cache: %dK\n",
-				ecx>>24, edx>>24);
-			c->x86_cache_size=(ecx>>24)+(edx>>24);
-		}
-		if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
-			boot_cpu_data.x86 == 6 && 
-			boot_cpu_data.x86_model== 3 &&
-			boot_cpu_data.x86_mask == 0)
-		{
-			/* AMD errata T13 (order #21922) */
-			printk("CPU: L2 Cache: 64K\n");
-			c->x86_cache_size = 64;
-		}
-		else if (n >= 0x80000006){
-			cpuid(0x80000006, &dummy, &dummy, &ecx, &edx);
-			printk("CPU: L2 Cache: %dK\n", ecx>>16);
-			c->x86_cache_size = ecx>>16;
-		}
-		break;
+__initfunc (static void display_cacheinfo(struct cpuinfo_x86 *c))
+{
+	unsigned int n, dummy, ecx, edx;
 
-	default:		/* Cyrix */
-		break;
+	cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
+
+	if (n >= 0x80000005){
+		cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
+		printk("CPU: L1 I Cache: %dK  L1 D Cache: %dK\n",
+			ecx>>24, edx>>24);
+		c->x86_cache_size=(ecx>>24)+(edx>>24);
+	}
+
+	/* Yes this can occur - the CyrixIII just has a large L1 */
+	if (n < 0x80000006)
+		return;	/* No function to get L2 info */
+
+	cpuid(0x80000006, &dummy, &dummy, &ecx, &edx);
+	c->x86_cache_size = ecx>>16;
+
+	/* AMD errata T13 (order #21922) */
+	if(boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+		boot_cpu_data.x86 == 6 && 
+		boot_cpu_data.x86_model== 3 &&
+		boot_cpu_data.x86_mask == 0)
+	{
+		c->x86_cache_size = 64;
 	}
-	return 1;
+
+	printk("CPU: L2 Cache: %dK\n", c->x86_cache_size);
 }
 
+
+
 __initfunc(static int amd_model(struct cpuinfo_x86 *c))
 {
 	u32 l, h;
@@ -517,7 +515,7 @@
 				/* Anyone with a K5 want to fill this in */				
 				break;
 			}
-			
+
 			/* K6 with old style WHCR */
 			if( c->x86_model < 8 ||
 				(c->x86_model== 8 && c->x86_mask < 8))
@@ -537,16 +535,17 @@
 					restore_flags(flags);
 					printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
 						mbytes);
-					
+
 				}
 				break;
 			}
-			if (c->x86_model == 8 || c->x86_model == 9)
+			if (c->x86_model == 8 || c->x86_model == 9 || c->x86_model == 13)
 			{
 				/* The more serious chips .. */
 				
 				if(mbytes>4092)
 					mbytes=4092;
+
 				rdmsr(0xC0000082, l, h);
 				if((l&0xFFFF0000)==0)
 				{
@@ -559,17 +558,35 @@
 					printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
 						mbytes);
 				}
+
+				/*  Set MTRR capability flag if appropriate  */
+				if((boot_cpu_data.x86_model == 9) ||
+				  ((boot_cpu_data.x86_model == 8) && 
+				   (boot_cpu_data.x86_mask >= 8)))
+					c->x86_capability |= X86_FEATURE_MTRR;
 				break;
 			}
 			break;
+
 		case 6:	/* An Athlon. We can trust the BIOS probably */
 		{
 			break;
 		}
-		
 	}
+
+	display_cacheinfo(c);
 	return r;
 }
+
+__initfunc(static void intel_model(struct cpuinfo_x86 *c))
+{
+	unsigned int *v = (unsigned int *) c->x86_model_id;
+	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+	c->x86_model_id[48] = 0;
+	printk("CPU: %s\n", c->x86_model_id);
+}
 			
 
 /*
@@ -691,18 +708,17 @@
 		 */
 		
 #ifdef CONFIG_PCI_QUIRKS
-                /* It isnt really a PCI quirk directly, but the cure is the
-       	           same. The MediaGX has deep magic SMM stuff that handles the
-                   SB emulation. It thows away the fifo on disable_dma() which
-                   is wrong and ruins the audio. 
-                   
-                   Bug2: VSA1 has a wrap bug so that using maximum sized DMA 
-                   causes bad things. According to NatSemi VSA2 has another
-                   bug to do with 'hlt'. I've not seen any boards using VSA2
-                   and X doesn't seem to support it either so who cares 8).
-                   VSA1 we work around however.
+		/* It isnt really a PCI quirk directly, but the cure is the
+		   same. The MediaGX has deep magic SMM stuff that handles the
+		   SB emulation. It thows away the fifo on disable_dma() which
+		   is wrong and ruins the audio. 
                    
-                  */
+		   Bug2: VSA1 has a wrap bug so that using maximum sized DMA 
+		   causes bad things. According to NatSemi VSA2 has another
+		   bug to do with 'hlt'. I've not seen any boards using VSA2
+		   and X doesn't seem to support it either so who cares 8).
+		   VSA1 we work around however.
+		*/
 
 		printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bug.\n");
                 isa_dma_bridge_buggy = 2;
@@ -759,12 +775,13 @@
 
 __initfunc(static void transmeta_model(struct cpuinfo_x86 *c))
 {
-	unsigned int cap_mask, uk, max, dummy, n, ecx, edx;
+	unsigned int cap_mask, uk, max, dummy;
 	unsigned int cms_rev1, cms_rev2;
 	unsigned int cpu_rev, cpu_freq, cpu_flags;
 	char cpu_info[65];
 
 	get_model_name(c);	/* Same as AMD/Cyrix */
+	display_cacheinfo(c);
 
 	/* Print CMS and CPU revision */
 	cpuid(0x80860000, &max, &dummy, &dummy, &dummy);
@@ -895,6 +912,7 @@
 {
 	int i;
 	char *p = NULL;
+	extern void mcheck_init(void);
 
 	c->loops_per_sec = loops_per_sec;
 	c->x86_cache_size = -1;
@@ -917,7 +935,7 @@
 		printk(KERN_INFO "CPU serial number disabled.\n");
 	}
 
-	mcheck_init(c);
+	mcheck_init();
 	
 	if (c->x86_vendor == X86_VENDOR_CYRIX) {
 		cyrix_model(c);
@@ -931,6 +949,14 @@
 		transmeta_model(c);
 		return;
 	}
+	
+	if(c->x86_vendor == X86_VENDOR_CENTAUR && c->x86==6)
+	{
+		/* The Cyrix III supports model naming and cache queries */
+		get_model_name(c);
+		display_cacheinfo(c);
+		return;
+	}
 
 	if (c->cpuid_level > 1) {
 		/* supports eax=2  call */
@@ -974,7 +1000,19 @@
 				break;
 		}
 	}
-
+	
+	/*
+	 *	Intel finally adopted the AMD/Cyrix extended id naming
+	 *	stuff
+	 */
+	 
+	if(c->x86_vendor ==X86_VENDOR_INTEL && c->x86 == 15)
+	{
+		c->x86 = 6;
+		intel_model(c);
+		return;
+	}
+	
 	for (i = 0; i < sizeof(cpu_models)/sizeof(struct cpu_model_info); i++) {
 		if (cpu_models[i].vendor == c->x86_vendor &&
 		    cpu_models[i].x86 == c->x86) {
@@ -986,14 +1024,13 @@
 			if ((cpu_models[i].vendor == X86_VENDOR_INTEL)
 			    && (cpu_models[i].x86 == 6)){ 
 				if(c->x86_model == 6 && c->x86_cache_size == 128) {
-                            		p = "Celeron (Mendocino)"; 
-                          	}
-			  	else { 
-                            	if (c->x86_model == 5 && c->x86_cache_size == 0) {
-				  	p = "Celeron (Covington)";
-			    	}
-                        }
-                    }
+					p = "Celeron (Mendocino)"; 
+				} else { 
+					if (c->x86_model == 5 && c->x86_cache_size == 0) {
+						p = "Celeron (Covington)";
+					}
+				}
+			}
 		}
 	}
 
@@ -1026,6 +1063,49 @@
 	"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
 
 
+__initfunc(void setup_centaur(struct cpuinfo_x86 *c))
+{
+	u32 hv,lv;
+	
+	/* Centaur C6 Series */
+	if(c->x86==5)
+	{
+		rdmsr(0x107, lv, hv);
+		printk("Centaur FSR was 0x%X ",lv);
+		lv|=(1<<1 | 1<<2 | 1<<7);
+		/* lv|=(1<<6);	- may help too if the board can cope */
+		printk("now 0x%X\n", lv);
+		wrmsr(0x107, lv, hv);
+		/* Emulate MTRRs using Centaur's MCR. */
+		c->x86_capability |= X86_FEATURE_MTRR;
+
+		/* Disable TSC on C6 as per errata. */
+		if (c->x86_model ==4) {
+			printk ("Disabling bugged TSC.\n");
+			c->x86_capability &= ~X86_FEATURE_TSC;
+		}
+
+		/* Set 3DNow! on Winchip 2 and above. */
+		if (c->x86_model >=8)
+		    c->x86_capability |= X86_FEATURE_AMD3D;
+
+		c->x86_capability |=X86_FEATURE_CX8;
+	}
+	/* Cyrix III 'Samuel' CPU */
+	if(c->x86 == 6 && c->x86_model == 6)
+	{
+		rdmsr(0x1107, lv, hv);
+		lv|=(1<<1);	/* Report CX8 */
+		lv|=(1<<7);	/* PGE enable */
+		wrmsr(0x1107, lv, hv);
+		/* Cyrix III */
+		c->x86_capability |= X86_FEATURE_CX8;
+		rdmsr(0x80000001, lv, hv);
+		if(hv&(1<<31))
+			c->x86_capability |= X86_FEATURE_AMD3D;
+	}	
+}
+
 __initfunc(void print_cpu_info(struct cpuinfo_x86 *c))
 {
 	char *vendor = NULL;
@@ -1049,27 +1129,7 @@
 		printk("\n");
 
 	if(c->x86_vendor == X86_VENDOR_CENTAUR) {
-		u32 hv,lv;
-		rdmsr(0x107, lv, hv);
-		printk("Centaur FSR was 0x%X ",lv);
-		lv|=(1<<1 | 1<<2 | 1<<7);
-		/* lv|=(1<<6);	- may help too if the board can cope */
-		printk("now 0x%X\n", lv);
-		wrmsr(0x107, lv, hv);
-		/* Emulate MTRRs using Centaur's MCR. */
-		c->x86_capability |= X86_FEATURE_MTRR;
-
-		/* Disable TSC on C6 as per errata. */
-		if (c->x86_model ==4) {
-			printk ("Disabling bugged TSC.\n");
-			c->x86_capability &= ~X86_FEATURE_TSC;
-		}
-
-		/* Set 3DNow! on Winchip 2 and above. */
-		if (c->x86_model >=8)
-		    c->x86_capability |= X86_FEATURE_AMD3D;
-
-		c->x86_capability |=X86_FEATURE_CX8;
+		setup_centaur(c);
 	}
 }
 
@@ -1146,13 +1206,19 @@
 			x86_cap_flags[16] = "pat";
 			x86_cap_flags[17] = "pse36";
 			x86_cap_flags[18] = "psn";
+			x86_cap_flags[19] = "cflush";
+			x86_cap_flags[21] = "dtrace";
+			x86_cap_flags[22] = "acpi";
 			x86_cap_flags[24] = "fxsr";
 			x86_cap_flags[25] = "xmm";
+			x86_cap_flags[26] = "xmm2";
+			x86_cap_flags[27] = "ssnp";
+			x86_cap_flags[29] = "acc";
 			break;
 
 		    case X86_VENDOR_CENTAUR:
 			if (c->x86_model >=8)	/* Only Winchip2 and above */
-			    x86_cap_flags[31] = "3dnow";
+				x86_cap_flags[31] = "3dnow";
 			break;
 
 		    default:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/smp.c linux.18p8/arch/i386/kernel/smp.c
--- linux.vanilla/arch/i386/kernel/smp.c	Sat Sep  9 18:42:32 2000
+++ linux.18p8/arch/i386/kernel/smp.c	Mon Sep 11 17:41:24 2000
@@ -658,7 +658,7 @@
 	return virt_to_phys(trampoline_base);
 }
 
-extern unsigned long i386_endbase __initdata;
+extern unsigned long i386_endbase;
 /*
  *	We are called very early to get the low memory for the
  *	SMP bootup trampoline page.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/time.c linux.18p8/arch/i386/kernel/time.c
--- linux.vanilla/arch/i386/kernel/time.c	Sun Jun 11 21:44:09 2000
+++ linux.18p8/arch/i386/kernel/time.c	Tue Sep 12 13:16:22 2000
@@ -77,6 +77,9 @@
 unsigned long fast_gettimeoffset_quotient=0;
 
 extern rwlock_t xtime_lock;
+extern volatile unsigned long lost_ticks;
+
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
 static inline unsigned long do_fast_gettimeoffset(void)
 {
@@ -112,6 +115,8 @@
 
 #ifndef CONFIG_X86_TSC
 
+spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
+
 /* This function must be called with interrupts disabled 
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
  * 
@@ -156,6 +161,8 @@
 	 */
 	unsigned long jiffies_t;
 
+	/* gets recalled with irq locally disabled */
+	spin_lock(&i8253_lock);
 	/* timer count may underflow right here */
 	outb_p(0x00, 0x43);	/* latch the count ASAP */
 
@@ -214,6 +221,7 @@
 		}
 	} else
 		jiffies_p = jiffies_t;
+	spin_unlock(&i8253_lock);
 
 	count_p = count;
 
@@ -237,7 +245,6 @@
  */
 void do_gettimeofday(struct timeval *tv)
 {
-	extern volatile unsigned long lost_ticks;
 	unsigned long flags;
 	unsigned long usec, sec;
 
@@ -271,6 +278,7 @@
 	 * would have done, and then undo it!
 	 */
 	tv->tv_usec -= do_gettimeoffset();
+	tv->tv_usec -= lost_ticks * (1000000 / HZ);
 
 	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
@@ -301,6 +309,8 @@
 	int real_seconds, real_minutes, cmos_minutes;
 	unsigned char save_control, save_freq_select;
 
+	/* gets recalled with irq locally disabled */
+	spin_lock(&rtc_lock);
 	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
 	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
 
@@ -346,6 +356,7 @@
 	 */
 	CMOS_WRITE(save_control, RTC_CONTROL);
 	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+	spin_unlock(&rtc_lock);
 
 	return retval;
 }
@@ -447,10 +458,19 @@
 
 		rdtscl(last_tsc_low);
 
+#if 0 /*
+       * SUBTLE: this is not necessary from here because it's implicit in the
+       * write xtime_lock.
+       */
+		spin_lock(&i8253_lock);
+#endif
 		outb_p(0x00, 0x43);     /* latch the count ASAP */
 
 		count = inb_p(0x40);    /* read the latched count */
 		count |= inb(0x40) << 8;
+#if 0
+		spin_unlock(&i8253_lock);
+#endif
 
 		count = ((LATCH-1) - count) * TICK_SIZE;
 		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/traps.c linux.18p8/arch/i386/kernel/traps.c
--- linux.vanilla/arch/i386/kernel/traps.c	Sat Sep  9 18:42:32 2000
+++ linux.18p8/arch/i386/kernel/traps.c	Mon Sep 11 17:51:59 2000
@@ -399,6 +399,7 @@
 	/* Ok, finally something we can handle */
 	tsk->tss.trap_no = 1;
 	tsk->tss.error_code = error_code;
+	tsk->tss.debugreg[DR_STATUS] = condition;
 	force_sig(SIGTRAP, tsk);
 	return;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/get_address.c linux.18p8/arch/i386/math-emu/get_address.c
--- linux.vanilla/arch/i386/math-emu/get_address.c	Fri Apr 21 12:45:46 2000
+++ linux.18p8/arch/i386/math-emu/get_address.c	Fri Sep  1 13:15:46 2000
@@ -155,6 +155,7 @@
 { 
   struct desc_struct descriptor;
   unsigned long base_address, limit, address, seg_top;
+  unsigned short selector;
 
   segment--;
 
@@ -172,14 +173,16 @@
       /* fs and gs aren't used by the kernel, so they still have their
 	 user-space values. */
     case PREFIX_FS_-1:
-      /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
+      /* The extra variable is needed here to get gcc to use a 16 bit register
 	 in the assembler statement. */
-      __asm__("mov %%fs,%0":"=r" ((unsigned short)addr->selector));
+      __asm__("mov %%fs,%0":"=r" (selector));
+      addr->selector = selector;
       break;
     case PREFIX_GS_-1:
-      /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register
+      /* The extra variable is needed here to get gcc to use a 16 bit register
 	 in the assembler statement. */
-      __asm__("mov %%gs,%0":"=r" ((unsigned short)addr->selector));
+      __asm__("mov %%gs,%0":"=r" (selector));
+      addr->selector = selector;
       break;
     default:
       addr->selector = PM_REG_(segment);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/math-emu/poly_tan.c linux.18p8/arch/i386/math-emu/poly_tan.c
--- linux.vanilla/arch/i386/math-emu/poly_tan.c	Fri Apr 21 12:45:46 2000
+++ linux.18p8/arch/i386/math-emu/poly_tan.c	Mon Sep 11 17:41:24 2000
@@ -89,7 +89,7 @@
 	{
 	  FPU_settag0(TAG_Valid);
 	  significand(st0_ptr) = 0x8a51e04daabda360LL;
-	  setexponent16(st0_ptr, 0x41 + EXTENDED_Ebias | SIGN_Negative);
+	  setexponent16(st0_ptr, (0x41 + EXTENDED_Ebias) | SIGN_Negative);
 	  return;
 	}
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/mm/init.c linux.18p8/arch/i386/mm/init.c
--- linux.vanilla/arch/i386/mm/init.c	Fri Apr 21 12:45:46 2000
+++ linux.18p8/arch/i386/mm/init.c	Mon Sep 11 17:41:24 2000
@@ -384,7 +384,7 @@
 		printk(".\n");
 }
 
-extern unsigned long i386_endbase __initdata;
+extern unsigned long i386_endbase;
 
 __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/mm/ioremap.c linux.18p8/arch/i386/mm/ioremap.c
--- linux.vanilla/arch/i386/mm/ioremap.c	Fri Apr 21 12:45:46 2000
+++ linux.18p8/arch/i386/mm/ioremap.c	Fri Sep  1 14:04:15 2000
@@ -110,7 +110,18 @@
 	 * Don't allow anybody to remap normal RAM that we're using..
 	 */
 	if (phys_addr < virt_to_phys(high_memory))
-		return NULL;
+           {
+		char *temp_addr, *temp_end;
+		int i;
+
+		temp_addr = __va(phys_addr);
+		temp_end = temp_addr + (size - 1);
+	      
+		for(i = MAP_NR(temp_addr); i < MAP_NR(temp_end); i++) {
+			if(!PageReserved(mem_map + i))
+				return NULL;
+		}
+	   }
 
 	/*
 	 * Mappings have to be page-aligned
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/vmlinux.lds.S linux.18p8/arch/i386/vmlinux.lds.S
--- linux.vanilla/arch/i386/vmlinux.lds.S	Fri Apr 21 12:45:46 2000
+++ linux.18p8/arch/i386/vmlinux.lds.S	Tue Sep  5 22:20:06 2000
@@ -42,8 +42,16 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
+  . = ALIGN(16);		/* __setup() commandline parameters */
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;		/* the init functions to be called */
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
+
 
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/m68k/vmlinux.lds linux.18p8/arch/m68k/vmlinux.lds
--- linux.vanilla/arch/m68k/vmlinux.lds	Fri Apr 21 12:45:46 2000
+++ linux.18p8/arch/m68k/vmlinux.lds	Tue Sep  5 22:20:06 2000
@@ -35,6 +35,7 @@
 
   _edata = .;			/* End of data section */
 
+
   . = ALIGN(16);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
@@ -42,6 +43,13 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
+  . = ALIGN(16);		/* __setup() commandline parameters */
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;		/* the init functions to be called */
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
   . = ALIGN(8192);
   __init_end = .;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/vmlinux.lds linux.18p8/arch/ppc/vmlinux.lds
--- linux.vanilla/arch/ppc/vmlinux.lds	Fri Apr 21 12:45:47 2000
+++ linux.18p8/arch/ppc/vmlinux.lds	Tue Sep  5 22:20:06 2000
@@ -71,8 +71,16 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
+  . = ALIGN(16);		/* __setup() commandline parameters */
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;		/* the init functions to be called */
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
+
 
   . = ALIGN(4096);
   __pmac_begin = .;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/vmlinux.lds linux.18p8/arch/s390/vmlinux.lds
--- linux.vanilla/arch/s390/vmlinux.lds	Fri Apr 21 12:45:48 2000
+++ linux.18p8/arch/s390/vmlinux.lds	Tue Sep  5 22:20:06 2000
@@ -42,8 +42,16 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
+  . = ALIGN(16);		/* __setup() commandline parameters */
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;		/* the init functions to be called */
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
+
 
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/mm/srmmu.c linux.18p8/arch/sparc/mm/srmmu.c
--- linux.vanilla/arch/sparc/mm/srmmu.c	Fri Apr 21 12:45:48 2000
+++ linux.18p8/arch/sparc/mm/srmmu.c	Wed Sep 13 16:48:19 2000
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.187.2.9 2000/03/05 17:39:18 davem Exp $
+/* $Id: srmmu.c,v 1.187.2.10 2000/09/07 04:44:48 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -2056,8 +2056,8 @@
 			goto done;
 		inode = file->f_dentry->d_inode;
 		offset = (address & PAGE_MASK) - vma->vm_start;
-		vmaring = inode->i_mmap; 
-		do {
+		vmaring = inode->i_mmap_shared; 
+		if (vmaring) do {
 			/* Do not mistake ourselves as another mapping. */
 			if(vmaring == vma)
 				continue;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/mm/sun4c.c linux.18p8/arch/sparc/mm/sun4c.c
--- linux.vanilla/arch/sparc/mm/sun4c.c	Fri Apr 21 12:45:48 2000
+++ linux.18p8/arch/sparc/mm/sun4c.c	Wed Sep 13 16:48:19 2000
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.173.2.5 1999/10/11 08:24:44 davem Exp $
+/* $Id: sun4c.c,v 1.173.2.6 2000/09/07 04:44:48 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -2420,9 +2420,9 @@
 		inode = dentry->d_inode;
 	if (inode) {
 		unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
-		struct vm_area_struct *vmaring = inode->i_mmap; 
+		struct vm_area_struct *vmaring = inode->i_mmap_shared; 
 		int alias_found = 0;
-		do {
+		if (vmaring) do {
 			unsigned long vaddr = vmaring->vm_start + offset;
 			unsigned long start;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/vmlinux.lds linux.18p8/arch/sparc/vmlinux.lds
--- linux.vanilla/arch/sparc/vmlinux.lds	Fri Apr 21 12:45:48 2000
+++ linux.18p8/arch/sparc/vmlinux.lds	Sun Sep 10 14:47:06 2000
@@ -40,8 +40,17 @@
   .text.init : { *(.text.init) }
   __init_text_end = .;
   .data.init : { *(.data.init) }
+  . = ALIGN(16);		/* __setup() commandline parameters */
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;		/* the init functions to be called */
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
+
+
   __bss_start = .;
   .sbss      : { *(.sbss) *(.scommon) }
   .bss       :
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/config.in linux.18p8/arch/sparc64/config.in
--- linux.vanilla/arch/sparc64/config.in	Sat Sep  9 18:42:34 2000
+++ linux.18p8/arch/sparc64/config.in	Fri Sep  1 14:13:19 2000
@@ -247,9 +247,10 @@
 			tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100
 			tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN
 		fi
-#		bool 'FDDI driver support' CONFIG_FDDI
-#		if [ "$CONFIG_FDDI" = "y" ]; then
-#		fi
+		bool 'FDDI driver support' CONFIG_FDDI
+		if [ "$CONFIG_FDDI" = "y" ]; then
+			tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP
+		fi
 	fi
 	endmenu
 fi
@@ -271,6 +272,12 @@
     dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
   fi
 fi
+endmenu
+
+mainmenu_option next_comment
+comment 'XFree86 DRI support'
+bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
+dep_tristate '  Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM
 endmenu
 
 source fs/Config.in
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/defconfig linux.18p8/arch/sparc64/defconfig
--- linux.vanilla/arch/sparc64/defconfig	Sat Sep  9 18:42:34 2000
+++ linux.18p8/arch/sparc64/defconfig	Sun Sep 10 14:49:09 2000
@@ -31,8 +31,6 @@
 # CONFIG_FB_PM2_FIFO_DISCONNECT is not set
 CONFIG_FB_PM2_PCI=y
 CONFIG_FB_ATY=y
-# CONFIG_FB_MATROX is not set
-# CONFIG_FB_ATY128 is not set
 CONFIG_FB_SBUS=y
 CONFIG_FB_CREATOR=y
 CONFIG_FB_CGSIX=y
@@ -262,6 +260,8 @@
 CONFIG_NE2K_PCI=m
 CONFIG_EEXPRESS_PRO100=m
 CONFIG_SK98LIN=m
+CONFIG_FDDI=y
+CONFIG_SKFP=m
 
 #
 # Unix 98 PTY support
@@ -274,6 +274,12 @@
 #
 CONFIG_VIDEO_DEV=y
 CONFIG_VIDEO_BT848=y
+
+#
+# XFree86 DRI support
+#
+CONFIG_DRM=y
+CONFIG_DRM_FFB=m
 
 #
 # Filesystems
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/entry.S linux.18p8/arch/sparc64/kernel/entry.S
--- linux.vanilla/arch/sparc64/kernel/entry.S	Fri Apr 21 12:45:48 2000
+++ linux.18p8/arch/sparc64/kernel/entry.S	Wed Sep 13 16:48:19 2000
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.103.2.5 2000/03/06 22:30:22 davem Exp $
+/* $Id: entry.S,v 1.103.2.6 2000/09/08 14:00:04 jj Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -958,9 +958,9 @@
 
 1:		b,pt		%xcc, ret_sys_call
 		 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
-sparc_exit:	rdpr		%otherwin, %g1
-		rdpr		%pstate, %g2
+sparc_exit:	rdpr		%pstate, %g2
 		wrpr		%g2, PSTATE_IE, %pstate
+		rdpr		%otherwin, %g1
 		rdpr		%cansave, %g3
 		add		%g3, %g1, %g3
 		wrpr		%g3, 0x0, %cansave
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/ioctl32.c linux.18p8/arch/sparc64/kernel/ioctl32.c
--- linux.vanilla/arch/sparc64/kernel/ioctl32.c	Sat Sep  9 18:42:34 2000
+++ linux.18p8/arch/sparc64/kernel/ioctl32.c	Sun Sep 10 14:49:10 2000
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.62.2.13 2000/07/27 01:50:59 davem Exp $
+/* $Id: ioctl32.c,v 1.62.2.16 2000/09/05 00:10:54 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -41,6 +41,9 @@
 #include <linux/netdevice.h>
 #include <linux/smb_fs.h>
 #include <linux/blkdev.h>
+#include <linux/in6.h>
+#include <linux/ipv6_route.h>
+#include <net/sock.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -622,30 +625,64 @@
 
 };
 
+struct in6_rtmsg32 {
+	struct in6_addr		rtmsg_dst;
+	struct in6_addr		rtmsg_src;
+	struct in6_addr		rtmsg_gateway;
+	u32			rtmsg_type;
+	u16			rtmsg_dst_len;
+	u16			rtmsg_src_len;
+	u32			rtmsg_metric;
+	u32			rtmsg_info;
+	u32			rtmsg_flags;
+	s32			rtmsg_ifindex;
+};
+
+extern struct socket *sockfd_lookup(int fd, int *err);
+
 static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	struct rtentry r;
+	int ret;
+	void *r = NULL;
+	struct in6_rtmsg r6;
+	struct rtentry r4;
 	char devname[16];
 	u32 rtdev;
-	int ret;
 	mm_segment_t old_fs = get_fs();
-	
-	ret = copy_from_user (&r.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr));
-	ret |= __get_user (r.rt_flags, &(((struct rtentry32 *)arg)->rt_flags));
-	ret |= __get_user (r.rt_metric, &(((struct rtentry32 *)arg)->rt_metric));
-	ret |= __get_user (r.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu));
-	ret |= __get_user (r.rt_window, &(((struct rtentry32 *)arg)->rt_window));
-	ret |= __get_user (r.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt));
-	ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev));
-	if (rtdev) {
-		ret |= copy_from_user (devname, (char *)A(rtdev), 15);
-		r.rt_dev = devname; devname[15] = 0;
-	} else
-		r.rt_dev = 0;
+	struct socket *mysock = sockfd_lookup(fd, &ret);
+
+	if (mysock && mysock->sk && mysock->sk->family == AF_INET6) { /* ipv6 */
+		ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst),
+			3 * sizeof(struct in6_addr));
+		ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type));
+		ret |= __get_user (r6.rtmsg_dst_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst_len));
+		ret |= __get_user (r6.rtmsg_src_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_src_len));
+		ret |= __get_user (r6.rtmsg_metric, &(((struct in6_rtmsg32 *)arg)->rtmsg_metric));
+		ret |= __get_user (r6.rtmsg_info, &(((struct in6_rtmsg32 *)arg)->rtmsg_info));
+		ret |= __get_user (r6.rtmsg_flags, &(((struct in6_rtmsg32 *)arg)->rtmsg_flags));
+		ret |= __get_user (r6.rtmsg_ifindex, &(((struct in6_rtmsg32 *)arg)->rtmsg_ifindex));
+		
+		r = (void *)&r6;
+	} else { /* ipv4 */
+		ret = copy_from_user (&r4.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr));
+		ret |= __get_user (r4.rt_flags, &(((struct rtentry32 *)arg)->rt_flags));
+		ret |= __get_user (r4.rt_metric, &(((struct rtentry32 *)arg)->rt_metric));
+		ret |= __get_user (r4.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu));
+		ret |= __get_user (r4.rt_window, &(((struct rtentry32 *)arg)->rt_window));
+		ret |= __get_user (r4.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt));
+		ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev));
+		if (rtdev) {
+			ret |= copy_from_user (devname, (char *)A(rtdev), 15);
+			r4.rt_dev = devname; devname[15] = 0;
+		} else
+			r4.rt_dev = 0;
+
+		r = (void *)&r4;
+	}
 	if (ret)
 		return -EFAULT;
 	set_fs (KERNEL_DS);
-	ret = sys_ioctl (fd, cmd, (long)&r);
+	ret = sys_ioctl (fd, cmd, (unsigned long) r);
 	set_fs (old_fs);
 	return ret;
 }
@@ -1739,6 +1776,544 @@
 	return err;
 }
 
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+/* This really belongs in include/linux/drm.h -DaveM */
+#include "../../../drivers/char/drm/drm.h"
+
+typedef struct drm32_version {
+	int    version_major;	  /* Major version			    */
+	int    version_minor;	  /* Minor version			    */
+	int    version_patchlevel;/* Patch level			    */
+	int    name_len;	  /* Length of name buffer		    */
+	u32    name;		  /* Name of driver			    */
+	int    date_len;	  /* Length of date buffer		    */
+	u32    date;		  /* User-space buffer to hold date	    */
+	int    desc_len;	  /* Length of desc buffer		    */
+	u32    desc;		  /* User-space buffer to hold desc	    */
+} drm32_version_t;
+#define DRM32_IOCTL_VERSION    DRM_IOWR(0x00, drm32_version_t)
+
+static int drm32_version(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_version_t *uversion = (drm32_version_t *)arg;
+	char *name_ptr, *date_ptr, *desc_ptr;
+	u32 tmp1, tmp2, tmp3;
+	drm_version_t kversion;
+	mm_segment_t old_fs;
+	int ret;
+
+	memset(&kversion, 0, sizeof(kversion));
+	if (get_user(kversion.name_len, &uversion->name_len) ||
+	    get_user(kversion.date_len, &uversion->date_len) ||
+	    get_user(kversion.desc_len, &uversion->desc_len) ||
+	    get_user(tmp1, &uversion->name) ||
+	    get_user(tmp2, &uversion->date) ||
+	    get_user(tmp3, &uversion->desc))
+		return -EFAULT;
+
+	name_ptr = (char *) A(tmp1);
+	date_ptr = (char *) A(tmp2);
+	desc_ptr = (char *) A(tmp3);
+
+	ret = -ENOMEM;
+	if (kversion.name_len && name_ptr) {
+		kversion.name = kmalloc(kversion.name_len, GFP_KERNEL);
+		if (!kversion.name)
+			goto out;
+	}
+	if (kversion.date_len && date_ptr) {
+		kversion.date = kmalloc(kversion.date_len, GFP_KERNEL);
+		if (!kversion.date)
+			goto out;
+	}
+	if (kversion.desc_len && desc_ptr) {
+		kversion.desc = kmalloc(kversion.desc_len, GFP_KERNEL);
+		if (!kversion.desc)
+			goto out;
+	}
+
+        old_fs = get_fs();
+	set_fs(KERNEL_DS);
+        ret = sys_ioctl (fd, DRM_IOCTL_VERSION, (unsigned long)&kversion);
+        set_fs(old_fs);
+
+	if (!ret) {
+		if ((kversion.name &&
+		     copy_to_user(name_ptr, kversion.name, kversion.name_len)) ||
+		    (kversion.date &&
+		     copy_to_user(date_ptr, kversion.date, kversion.date_len)) ||
+		    (kversion.desc &&
+		     copy_to_user(desc_ptr, kversion.desc, kversion.desc_len)))
+			ret = -EFAULT;
+		if (put_user(kversion.version_major, &uversion->version_major) ||
+		    put_user(kversion.version_minor, &uversion->version_minor) ||
+		    put_user(kversion.version_patchlevel, &uversion->version_patchlevel) ||
+		    put_user(kversion.name_len, &uversion->name_len) ||
+		    put_user(kversion.date_len, &uversion->date_len) ||
+		    put_user(kversion.desc_len, &uversion->desc_len))
+			ret = -EFAULT;
+	}
+
+out:
+	if (kversion.name)
+		kfree(kversion.name);
+	if (kversion.date)
+		kfree(kversion.date);
+	if (kversion.desc)
+		kfree(kversion.desc);
+	return ret;
+}
+
+typedef struct drm32_unique {
+	int	unique_len;	  /* Length of unique			    */
+	u32	unique;		  /* Unique name for driver instantiation   */
+} drm32_unique_t;
+#define DRM32_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm32_unique_t)
+#define DRM32_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm32_unique_t)
+
+static int drm32_getsetunique(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_unique_t *uarg = (drm32_unique_t *)arg;
+	drm_unique_t karg;
+	mm_segment_t old_fs;
+	char *uptr;
+	u32 tmp;
+	int ret;
+
+	if (get_user(karg.unique_len, &uarg->unique_len))
+		return -EFAULT;
+	karg.unique = NULL;
+
+	if (get_user(tmp, &uarg->unique))
+		return -EFAULT;
+
+	uptr = (char *) A(tmp);
+
+	if (uptr) {
+		karg.unique = kmalloc(karg.unique_len, GFP_KERNEL);
+		if (!karg.unique)
+			return -ENOMEM;
+		if (cmd == DRM32_IOCTL_SET_UNIQUE &&
+		    copy_from_user(karg.unique, uptr, karg.unique_len)) {
+			kfree(karg.unique);
+			return -EFAULT;
+		}
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	if (cmd == DRM32_IOCTL_GET_UNIQUE)
+		ret = sys_ioctl (fd, DRM_IOCTL_GET_UNIQUE, (unsigned long)&karg);
+	else
+		ret = sys_ioctl (fd, DRM_IOCTL_SET_UNIQUE, (unsigned long)&karg);
+        set_fs(old_fs);
+
+	if (!ret) {
+		if (cmd == DRM32_IOCTL_GET_UNIQUE &&
+		    uptr != NULL &&
+		    copy_to_user(uptr, karg.unique, karg.unique_len))
+			ret = -EFAULT;
+		if (put_user(karg.unique_len, &uarg->unique_len))
+			ret = -EFAULT;
+	}
+
+	if (karg.unique != NULL)
+		kfree(karg.unique);
+
+	return ret;
+}
+
+typedef struct drm32_map {
+	u32		offset;	 /* Requested physical address (0 for SAREA)*/
+	u32		size;	 /* Requested physical size (bytes)	    */
+	drm_map_type_t	type;	 /* Type of memory to map		    */
+	drm_map_flags_t flags;	 /* Flags				    */
+	u32		handle;  /* User-space: "Handle" to pass to mmap    */
+				 /* Kernel-space: kernel-virtual address    */
+	int		mtrr;	 /* MTRR slot used			    */
+				 /* Private data			    */
+} drm32_map_t;
+#define DRM32_IOCTL_ADD_MAP    DRM_IOWR(0x15, drm32_map_t)
+
+static int drm32_addmap(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_map_t *uarg = (drm32_map_t *) arg;
+	drm_map_t karg;
+	mm_segment_t old_fs;
+	u32 tmp;
+	int ret;
+
+	ret  = get_user(karg.offset, &uarg->offset);
+	ret |= get_user(karg.size, &uarg->size);
+	ret |= get_user(karg.type, &uarg->type);
+	ret |= get_user(karg.flags, &uarg->flags);
+	ret |= get_user(tmp, &uarg->handle);
+	ret |= get_user(karg.mtrr, &uarg->mtrr);
+	if (ret)
+		return -EFAULT;
+
+	karg.handle = (void *) A(tmp);
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_ADD_MAP, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		ret  = put_user(karg.offset, &uarg->offset);
+		ret |= put_user(karg.size, &uarg->size);
+		ret |= put_user(karg.type, &uarg->type);
+		ret |= put_user(karg.flags, &uarg->flags);
+		tmp = (u32) (long)karg.handle;
+		ret |= put_user(tmp, &uarg->handle);
+		ret |= put_user(karg.mtrr, &uarg->mtrr);
+		if (ret)
+			ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+typedef struct drm32_buf_info {
+	int	       count;	/* Entries in list			     */
+	u32	       list;    /* (drm_buf_desc_t *) */ 
+} drm32_buf_info_t;
+#define DRM32_IOCTL_INFO_BUFS  DRM_IOWR(0x18, drm32_buf_info_t)
+
+static int drm32_info_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_info_t *uarg = (drm32_buf_info_t *)arg;
+	drm_buf_desc_t *ulist;
+	drm_buf_info_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret;
+	u32 tmp;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->list))
+		return -EFAULT;
+
+	ulist = (drm_buf_desc_t *) A(tmp);
+
+	orig_count = karg.count;
+
+	karg.list = kmalloc(karg.count * sizeof(drm_buf_desc_t), GFP_KERNEL);
+	if (!karg.list)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_INFO_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (karg.count <= orig_count &&
+		    (copy_to_user(ulist, karg.list,
+				  karg.count * sizeof(drm_buf_desc_t))))
+			ret = -EFAULT;
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+	kfree(karg.list);
+
+	return ret;
+}
+
+typedef struct drm32_buf_free {
+	int	       count;
+	u32	       list;	/* (int *) */
+} drm32_buf_free_t;
+#define DRM32_IOCTL_FREE_BUFS  DRM_IOW( 0x1a, drm32_buf_free_t)
+
+static int drm32_free_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_free_t *uarg = (drm32_buf_free_t *)arg;
+	drm_buf_free_t karg;
+	mm_segment_t old_fs;
+	int *ulist;
+	int ret;
+	u32 tmp;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->list))
+		return -EFAULT;
+
+	ulist = (int *) A(tmp);
+
+	karg.list = kmalloc(karg.count * sizeof(int), GFP_KERNEL);
+	if (!karg.list)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	if (copy_from_user(karg.list, ulist, (karg.count * sizeof(int))))
+		goto out;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_FREE_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+out:
+	kfree(karg.list);
+
+	return ret;
+}
+
+typedef struct drm32_buf_pub {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	u32		  address;     /* Address of buffer (void *)	     */
+} drm32_buf_pub_t;
+
+typedef struct drm32_buf_map {
+	int	      count;	/* Length of buflist			    */
+	u32	      virtual;	/* Mmaped area in user-virtual (void *)	    */
+	u32 	      list;	/* Buffer information (drm_buf_pub_t *)	    */
+} drm32_buf_map_t;
+#define DRM32_IOCTL_MAP_BUFS   DRM_IOWR(0x19, drm32_buf_map_t)
+
+static int drm32_map_bufs(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_buf_map_t *uarg = (drm32_buf_map_t *)arg;
+	drm32_buf_pub_t *ulist;
+	drm_buf_map_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret, i;
+	u32 tmp1, tmp2;
+
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp1, &uarg->virtual) ||
+	    get_user(tmp2, &uarg->list))
+		return -EFAULT;
+
+	karg.virtual = (void *) A(tmp1);
+	ulist = (drm32_buf_pub_t *) A(tmp2);
+
+	orig_count = karg.count;
+
+	karg.list = kmalloc(karg.count * sizeof(drm_buf_pub_t), GFP_KERNEL);
+	if (!karg.list)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	for (i = 0; i < karg.count; i++) {
+		if (get_user(karg.list[i].idx, &ulist[i].idx) ||
+		    get_user(karg.list[i].total, &ulist[i].total) ||
+		    get_user(karg.list[i].used, &ulist[i].used) ||
+		    get_user(tmp1, &ulist[i].address))
+			goto out;
+
+		karg.list[i].address = (void *) A(tmp1);
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_MAP_BUFS, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		for (i = 0; i < orig_count; i++) {
+			tmp1 = (u32) (long) karg.list[i].address;
+			if (put_user(karg.list[i].idx, &ulist[i].idx) ||
+			    put_user(karg.list[i].total, &ulist[i].total) ||
+			    put_user(karg.list[i].used, &ulist[i].used) ||
+			    put_user(tmp1, &ulist[i].address)) {
+				ret = -EFAULT;
+				goto out;
+			}
+		}
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+out:
+	kfree(karg.list);
+	return ret;
+}
+
+typedef struct drm32_dma {
+				/* Indices here refer to the offset into
+				   buflist in drm_buf_get_t.  */
+	int		context;	  /* Context handle		    */
+	int		send_count;	  /* Number of buffers to send	    */
+	u32		send_indices;	  /* List of handles to buffers (int *) */
+	u32		send_sizes;	  /* Lengths of data to send (int *) */
+	drm_dma_flags_t flags;		  /* Flags			    */
+	int		request_count;	  /* Number of buffers requested    */
+	int		request_size;	  /* Desired size for buffers	    */
+	u32		request_indices;  /* Buffer information (int *)	    */
+	u32		request_sizes;    /* (int *) */
+	int		granted_count;	  /* Number of buffers granted	    */
+} drm32_dma_t;
+#define DRM32_IOCTL_DMA	     DRM_IOWR(0x29, drm32_dma_t)
+
+/* RED PEN	The DRM layer blindly dereferences the send/request
+ * 		indice/size arrays even though they are userland
+ * 		pointers.  -DaveM
+ */
+static int drm32_dma(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_dma_t *uarg = (drm32_dma_t *) arg;
+	int *u_si, *u_ss, *u_ri, *u_rs;
+	drm_dma_t karg;
+	mm_segment_t old_fs;
+	int ret;
+	u32 tmp1, tmp2, tmp3, tmp4;
+
+	karg.send_indices = karg.send_sizes = NULL;
+	karg.request_indices = karg.request_sizes = NULL;
+
+	if (get_user(karg.context, &uarg->context) ||
+	    get_user(karg.send_count, &uarg->send_count) ||
+	    get_user(tmp1, &uarg->send_indices) ||
+	    get_user(tmp2, &uarg->send_sizes) ||
+	    get_user(karg.flags, &uarg->flags) ||
+	    get_user(karg.request_count, &uarg->request_count) ||
+	    get_user(karg.request_size, &uarg->request_size) ||
+	    get_user(tmp3, &uarg->request_indices) ||
+	    get_user(tmp4, &uarg->request_sizes) ||
+	    get_user(karg.granted_count, &uarg->granted_count))
+		return -EFAULT;
+
+	u_si = (int *) A(tmp1);
+	u_ss = (int *) A(tmp2);
+	u_ri = (int *) A(tmp3);
+	u_rs = (int *) A(tmp4);
+
+	if (karg.send_count) {
+		karg.send_indices = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+		karg.send_sizes = kmalloc(karg.send_count * sizeof(int), GFP_KERNEL);
+
+		ret = -ENOMEM;
+		if (!karg.send_indices || !karg.send_sizes)
+			goto out;
+
+		ret = -EFAULT;
+		if (copy_from_user(karg.send_indices, u_si,
+				   (karg.send_count * sizeof(int))) ||
+		    copy_from_user(karg.send_sizes, u_ss,
+				   (karg.send_count * sizeof(int))))
+			goto out;
+	}
+
+	if (karg.request_count) {
+		karg.request_indices = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+		karg.request_sizes = kmalloc(karg.request_count * sizeof(int), GFP_KERNEL);
+
+		ret = -ENOMEM;
+		if (!karg.request_indices || !karg.request_sizes)
+			goto out;
+
+		ret = -EFAULT;
+		if (copy_from_user(karg.request_indices, u_ri,
+				   (karg.request_count * sizeof(int))) ||
+		    copy_from_user(karg.request_sizes, u_rs,
+				   (karg.request_count * sizeof(int))))
+			goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_DMA, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (put_user(karg.context, &uarg->context) ||
+		    put_user(karg.send_count, &uarg->send_count) ||
+		    put_user(karg.flags, &uarg->flags) ||
+		    put_user(karg.request_count, &uarg->request_count) ||
+		    put_user(karg.request_size, &uarg->request_size) ||
+		    put_user(karg.granted_count, &uarg->granted_count))
+			ret = -EFAULT;
+
+		if (karg.send_count) {
+			if (copy_to_user(u_si, karg.send_indices,
+					 (karg.send_count * sizeof(int))) ||
+			    copy_to_user(u_ss, karg.send_sizes,
+					 (karg.send_count * sizeof(int))))
+				ret = -EFAULT;
+		}
+		if (karg.request_count) {
+			if (copy_to_user(u_ri, karg.request_indices,
+					 (karg.request_count * sizeof(int))) ||
+			    copy_to_user(u_rs, karg.request_sizes,
+					 (karg.request_count * sizeof(int))))
+				ret = -EFAULT;
+		}
+	}
+
+out:
+	if (karg.send_indices)
+		kfree(karg.send_indices);
+	if (karg.send_sizes)
+		kfree(karg.send_sizes);
+	if (karg.request_indices)
+		kfree(karg.request_indices);
+	if (karg.request_sizes)
+		kfree(karg.request_sizes);
+
+	return ret;
+}
+
+typedef struct drm32_ctx_res {
+	int		count;
+	u32		contexts; /* (drm_ctx_t *) */
+} drm32_ctx_res_t;
+#define DRM32_IOCTL_RES_CTX    DRM_IOWR(0x26, drm32_ctx_res_t)
+
+static int drm32_res_ctx(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	drm32_ctx_res_t *uarg = (drm32_ctx_res_t *) arg;
+	drm_ctx_t *ulist;
+	drm_ctx_res_t karg;
+	mm_segment_t old_fs;
+	int orig_count, ret;
+	u32 tmp;
+
+	karg.contexts = NULL;
+	if (get_user(karg.count, &uarg->count) ||
+	    get_user(tmp, &uarg->contexts))
+		return -EFAULT;
+
+	ulist = (drm_ctx_t *) A(tmp);
+
+	orig_count = karg.count;
+	if (karg.count && ulist) {
+		karg.contexts = kmalloc((karg.count * sizeof(drm_ctx_t)), GFP_KERNEL);
+		if (!karg.contexts)
+			return -ENOMEM;
+		if (copy_from_user(karg.contexts, ulist,
+				   (karg.count * sizeof(drm_ctx_t)))) {
+			kfree(karg.contexts);
+			return -EFAULT;
+		}
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_ioctl(fd, DRM_IOCTL_RES_CTX, (unsigned long) &karg);
+	set_fs(old_fs);
+
+	if (!ret) {
+		if (orig_count) {
+			if (copy_to_user(ulist, karg.contexts,
+					 (orig_count * sizeof(drm_ctx_t))))
+				ret = -EFAULT;
+		}
+		if (put_user(karg.count, &uarg->count))
+			ret = -EFAULT;
+	}
+
+	if (karg.contexts)
+		kfree(karg.contexts);
+
+	return ret;
+}
+
+#endif /* defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) */
+
 asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct file * filp;
@@ -1930,6 +2505,44 @@
 		error = do_smb_getmountuid(fd, cmd, arg);
 		goto out;
 
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+	case DRM32_IOCTL_VERSION:
+		error = drm32_version(fd, cmd, arg);
+		goto out;
+
+	case DRM32_IOCTL_GET_UNIQUE:
+		error = drm32_getsetunique(fd, cmd, arg);
+		goto out;
+
+	case DRM32_IOCTL_SET_UNIQUE:
+		error = drm32_getsetunique(fd, cmd, arg);
+		goto out;
+
+	case DRM32_IOCTL_ADD_MAP:
+		error = drm32_addmap(fd, cmd, arg);
+		goto out;
+
+	case DRM32_IOCTL_INFO_BUFS:
+		error = drm32_info_bufs(fd, cmd, arg);
+		goto out;
+
+	case DRM32_IOCTL_FREE_BUFS:
+		error = drm32_free_bufs(fd, cmd, arg);
+		goto out;
+
+	case DRM32_IOCTL_MAP_BUFS:
+		error = drm32_map_bufs(fd, cmd, arg);
+		goto out;
+
+	case DRM32_IOCTL_DMA:
+		error = drm32_dma(fd, cmd, arg);
+		goto out;
+
+	case DRM32_IOCTL_RES_CTX:
+		error = drm32_res_ctx(fd, cmd, arg);
+		goto out;
+#endif /* DRM */
+
 	/* List here exlicitly which ioctl's are known to have
 	 * compatable types passed or none at all...
 	 */
@@ -2486,6 +3099,30 @@
 
 	/* SMB ioctls which do not need any translations */
 	case SMB_IOC_NEWCONN:
+
+#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
+	/* DRM ioctls which do not need any translations */
+	case DRM_IOCTL_GET_MAGIC:
+	case DRM_IOCTL_IRQ_BUSID:
+	case DRM_IOCTL_AUTH_MAGIC:
+	case DRM_IOCTL_BLOCK:
+	case DRM_IOCTL_UNBLOCK:
+	case DRM_IOCTL_CONTROL:
+	case DRM_IOCTL_ADD_BUFS:
+	case DRM_IOCTL_MARK_BUFS:
+	case DRM_IOCTL_ADD_CTX:
+	case DRM_IOCTL_RM_CTX:
+	case DRM_IOCTL_MOD_CTX:
+	case DRM_IOCTL_GET_CTX:
+	case DRM_IOCTL_SWITCH_CTX:
+	case DRM_IOCTL_NEW_CTX:
+	case DRM_IOCTL_ADD_DRAW:
+	case DRM_IOCTL_RM_DRAW:
+	case DRM_IOCTL_LOCK:
+	case DRM_IOCTL_UNLOCK:
+	case DRM_IOCTL_FINISH:
+#endif /* DRM */
+
 
 		error = sys_ioctl (fd, cmd, arg);
 		goto out;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/sparc64_ksyms.c linux.18p8/arch/sparc64/kernel/sparc64_ksyms.c
--- linux.vanilla/arch/sparc64/kernel/sparc64_ksyms.c	Sat Sep  9 18:42:34 2000
+++ linux.18p8/arch/sparc64/kernel/sparc64_ksyms.c	Sun Sep 10 14:49:10 2000
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.58.2.8 2000/06/14 07:41:19 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.58.2.9 2000/09/05 00:10:54 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -83,6 +83,7 @@
 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 int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
                 
 extern void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
@@ -196,6 +197,9 @@
 EXPORT_SYMBOL(insl);
 EXPORT_SYMBOL(pci_dma_wsync);
 #endif
+
+/* I/O device mmaping on Sparc64. */
+EXPORT_SYMBOL(io_remap_page_range);
 
 /* Solaris/SunOS binary compatibility */
 EXPORT_SYMBOL(_sigpause_common);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/sys_sparc32.c linux.18p8/arch/sparc64/kernel/sys_sparc32.c
--- linux.vanilla/arch/sparc64/kernel/sys_sparc32.c	Sat Sep  9 18:42:34 2000
+++ linux.18p8/arch/sparc64/kernel/sys_sparc32.c	Fri Sep 15 12:51:22 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.107.2.9 2000/06/20 17:12:25 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107.2.13 2000/09/14 10:39:24 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -45,6 +45,9 @@
 #include <linux/stat.h>
 #include <linux/timex.h>
 #include <linux/filter.h>
+#include <linux/in6.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -1377,7 +1380,7 @@
 
 static void *do_ncp_super_data_conv(void *raw_data)
 {
-	struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data;
+	struct ncp_mount_data news, *n = &news; 
 	struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
 
 	n->dir_mode = n32->dir_mode;
@@ -1387,6 +1390,7 @@
 	memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
 	n->wdog_pid = n32->wdog_pid;
 	n->mounted_uid = n32->mounted_uid;
+	memcpy(raw_data, n, sizeof(struct ncp_mount_data)); 
 	return raw_data;
 }
 
@@ -1401,7 +1405,7 @@
 
 static void *do_smb_super_data_conv(void *raw_data)
 {
-	struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
+	struct smb_mount_data news, *s = &news;
 	struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
 
 	s->version = s32->version;
@@ -1410,6 +1414,7 @@
 	s->gid = s32->gid;
 	s->file_mode = s32->file_mode;
 	s->dir_mode = s32->dir_mode;
+	memcpy(raw_data, s, sizeof(struct smb_mount_data)); 
 	return raw_data;
 }
 
@@ -2665,42 +2670,86 @@
 extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
 				     char *optval, int optlen);
 
-asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+static int do_set_attach_filter(int fd, int level, int optname,
 				char *optval, int optlen)
 {
-	if (optname == SO_ATTACH_FILTER) {
-		struct sock_fprog32 {
-			__u16 len;
-			__u32 filter;
-		} *fprog32 = (struct sock_fprog32 *)optval;
-		struct sock_fprog kfprog;
-		struct sock_filter *kfilter;
-		unsigned int fsize;
-		mm_segment_t old_fs;
-		__u32 uptr;
-		int ret;
+	struct sock_fprog32 {
+		__u16 len;
+		__u32 filter;
+	} *fprog32 = (struct sock_fprog32 *)optval;
+	struct sock_fprog kfprog;
+	struct sock_filter *kfilter;
+	unsigned int fsize;
+	mm_segment_t old_fs;
+	__u32 uptr;
+	int ret;
 
-		if (get_user(kfprog.len, &fprog32->len) ||
-		    __get_user(uptr, &fprog32->filter))
-			return -EFAULT;
-		kfprog.filter = (struct sock_filter *)A(uptr);
-		fsize = kfprog.len * sizeof(struct sock_filter);
-		kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
-		if (kfilter == NULL)
-			return -ENOMEM;
-		if (copy_from_user(kfilter, kfprog.filter, fsize)) {
-			kfree(kfilter);
-			return -EFAULT;
-		}
-		kfprog.filter = kfilter;
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		ret = sys_setsockopt(fd, level, optname,
-				     (char *)&kfprog, sizeof(kfprog));
-		set_fs(old_fs);
+	if (get_user(kfprog.len, &fprog32->len) ||
+	    __get_user(uptr, &fprog32->filter))
+		return -EFAULT;
+
+	kfprog.filter = (struct sock_filter *)A(uptr);
+	fsize = kfprog.len * sizeof(struct sock_filter);
+
+	kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+	if (kfilter == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(kfilter, kfprog.filter, fsize)) {
 		kfree(kfilter);
-		return ret;
+		return -EFAULT;
 	}
+
+	kfprog.filter = kfilter;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *)&kfprog, sizeof(kfprog));
+	set_fs(old_fs);
+
+	kfree(kfilter);
+
+	return ret;
+}
+
+static int do_set_icmpv6_filter(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct icmp6_filter kfilter;
+	mm_segment_t old_fs;
+	int ret, i;
+
+	if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
+		return -EFAULT;
+
+
+	for (i = 0; i < 8; i += 2) {
+		u32 tmp = kfilter.data[i];
+
+		kfilter.data[i] = kfilter.data[i + 1];
+		kfilter.data[i + 1] = tmp;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_setsockopt(fd, level, optname,
+			     (char *) &kfilter, sizeof(kfilter));
+	set_fs(old_fs);
+
+	return ret;
+}
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	if (optname == SO_ATTACH_FILTER)
+		return do_set_attach_filter(fd, level, optname,
+					    optval, optlen);
+	if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
+		return do_set_icmpv6_filter(fd, level, optname,
+					    optval, optlen);
+
 	return sys_setsockopt(fd, level, optname, optval, optlen);
 }
 
@@ -4021,4 +4070,56 @@
 		ret = -EFAULT;
 
 	return ret;
+}
+
+struct __sysctl_args32 {
+	u32 name;
+	int nlen;
+	u32 oldval;
+	u32 oldlenp;
+	u32 newval;
+	u32 newlen;
+	u32 __unused[4];
+};
+
+extern int do_sysctl(int *name, int nlen,
+		     void *oldval, size_t *oldlenp,
+		     void *newval, size_t newlen);
+
+asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
+{
+	struct __sysctl_args32 tmp;
+	int error;
+	size_t oldlen, *oldlenp = NULL;
+	unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+
+	if (copy_from_user(&tmp, args, sizeof(tmp)))
+		return -EFAULT;
+
+	if (tmp.oldval && tmp.oldlenp) {
+		/* Duh, this is ugly and might not work if sysctl_args
+		   is in read-only memory, but do_sysctl does indirectly
+		   a lot of uaccess in both directions and we'd have to
+		   basically copy the whole sysctl.c here, and
+		   glibc's __sysctl uses rw memory for the structure
+		   anyway.  */
+		if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||
+		    put_user(oldlen, (size_t *)addr))
+			return -EFAULT;
+		oldlenp = (size_t *)addr;
+	}
+
+	lock_kernel();
+	error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),
+			  oldlenp, (void *)A(tmp.newval), tmp.newlen);
+	unlock_kernel();
+	if (oldlenp) {
+		if (!error) {
+			if (get_user(oldlen, (size_t *)addr) ||
+			    put_user(oldlen, (u32 *)A(tmp.oldlenp)))
+				error = -EFAULT;
+		}
+		copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
+	}
+	return error;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/systbls.S linux.18p8/arch/sparc64/kernel/systbls.S
--- linux.vanilla/arch/sparc64/kernel/systbls.S	Fri Apr 21 12:45:48 2000
+++ linux.18p8/arch/sparc64/kernel/systbls.S	Sun Sep 10 14:49:10 2000
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.53.2.4 2000/03/24 00:03:28 davem Exp $
+/* $Id: systbls.S,v 1.53.2.5 2000/08/23 04:18:26 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -69,7 +69,7 @@
 	.word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
-/*250*/	.word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+/*250*/	.word sys_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
 	.word sys_aplib
 
 	/* Now the 64-bit native Linux syscall table. */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/vmlinux.lds linux.18p8/arch/sparc64/vmlinux.lds
--- linux.vanilla/arch/sparc64/vmlinux.lds	Fri Apr 21 12:45:49 2000
+++ linux.18p8/arch/sparc64/vmlinux.lds	Sun Sep 10 14:47:06 2000
@@ -39,8 +39,17 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
+  . = ALIGN(16);		/* __setup() commandline parameters */
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;		/* the init functions to be called */
+  .initcall.init : { *(.initcall.init) }
+  __initcall_end = .;
   . = ALIGN(8192);
   __init_end = .;
+
+
   __bss_start = .;
   .sbss      : { *(.sbss) *(.scommon) }
   .bss       :
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ap1000/ap.c linux.18p8/drivers/ap1000/ap.c
--- linux.vanilla/drivers/ap1000/ap.c	Fri Apr 21 12:45:50 2000
+++ linux.18p8/drivers/ap1000/ap.c	Tue Sep 12 12:55:07 2000
@@ -20,7 +20,6 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/fs.h>
-#include <linux/ext2_fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/module.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/ap1000/ddv.c linux.18p8/drivers/ap1000/ddv.c
--- linux.vanilla/drivers/ap1000/ddv.c	Fri Apr 21 12:45:50 2000
+++ linux.18p8/drivers/ap1000/ddv.c	Tue Sep 12 12:55:07 2000
@@ -16,7 +16,6 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/fs.h>
-#include <linux/ext2_fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/mm.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/Config.in linux.18p8/drivers/block/Config.in
--- linux.vanilla/drivers/block/Config.in	Sun Jun 11 21:44:11 2000
+++ linux.18p8/drivers/block/Config.in	Mon Sep 11 18:06:33 2000
@@ -40,6 +40,7 @@
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
           bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
           if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+			bool '     ALI 15X3 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_ALI15X3
             bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
             bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
             bool '     VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586
@@ -138,6 +139,10 @@
 if [ "$CONFIG_PCI" = "y" ]; then
   tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA
 fi
+if [ "$CONFIG_PCI" = "y" ]; then
+  tristate 'Compaq CISS Array support' CONFIG_BLK_CPQ_CISS_DA
+fi
+
 
 if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
   define_bool CONFIG_BLK_DEV_HD y
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/DAC960.c linux.18p8/drivers/block/DAC960.c
--- linux.vanilla/drivers/block/DAC960.c	Sat Sep  9 18:42:34 2000
+++ linux.18p8/drivers/block/DAC960.c	Sun Sep 10 14:46:08 2000
@@ -19,8 +19,8 @@
 */
 
 
-#define DAC960_DriverVersion			"2.2.8"
-#define DAC960_DriverDate			"19 August 2000"
+#define DAC960_DriverVersion			"2.2.9"
+#define DAC960_DriverDate			"7 September 2000"
 
 
 #include <linux/version.h>
@@ -310,13 +310,8 @@
 
 static void DAC960_WaitForCommand(DAC960_Controller_T *Controller)
 {
-  WaitQueue_T WaitQueueEntry = { current, NULL };
-  add_wait_queue(&Controller->CommandWaitQueue, &WaitQueueEntry);
-  current->state = TASK_UNINTERRUPTIBLE;
-  spin_unlock(&io_request_lock);
-  schedule();
-  current->state = TASK_RUNNING;
-  remove_wait_queue(&Controller->CommandWaitQueue, &WaitQueueEntry);
+  spin_unlock_irq(&io_request_lock);
+  __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands);
   spin_lock_irq(&io_request_lock);
 }
 
@@ -5053,7 +5048,8 @@
 	}
       Geometry.start =
 	Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].start_sect;
-      return copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T));
+      return (copy_to_user(UserGeometry, &Geometry,
+			   sizeof(DiskGeometry_T)) ? -EFAULT : 0);
     case BLKGETSIZE:
       /* Get Device Size. */
       if ((long *) Argument == NULL) return -EINVAL;
@@ -5161,8 +5157,8 @@
 	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));
+	return (copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
+			     sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0);
       }
     case DAC960_IOCTL_V1_EXECUTE_COMMAND:
       {
@@ -6484,7 +6480,7 @@
   unsigned char CommandBuffer[80];
   int Length;
   if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
-  copy_from_user(CommandBuffer, Buffer, Count);
+  if (copy_from_user(CommandBuffer, Buffer, Count)) return -EFAULT;
   CommandBuffer[Count] = '\0';
   Length = strlen(CommandBuffer);
   if (CommandBuffer[Length-1] == '\n')
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/Makefile linux.18p8/drivers/block/Makefile
--- linux.vanilla/drivers/block/Makefile	Fri Apr 21 12:45:50 2000
+++ linux.18p8/drivers/block/Makefile	Mon Sep 11 18:06:33 2000
@@ -142,6 +142,10 @@
 IDE_OBJS += pdc4030.o
 endif
 
+ifeq ($(CONFIG_BLK_DEV_ALI15X3),y)
+IDE_OBJS += alim15x3.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_TRM290),y)
 IDE_OBJS += trm290.o
 endif
@@ -243,6 +247,14 @@
 else
   ifeq ($(CONFIG_BLK_CPQ_DA),m)
   M_OBJS += cpqarray.o
+  endif
+endif
+
+ifeq ($(CONFIG_BLK_CPQ_CISS_DA),y)
+L_OBJS += cciss.o
+else
+  ifeq ($(CONFIG_BLK_CPQ_CISS_DA),m)
+  M_OBJS += cciss.o
   endif
 endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/alim15x3.c linux.18p8/drivers/block/alim15x3.c
--- linux.vanilla/drivers/block/alim15x3.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/block/alim15x3.c	Mon Sep 11 18:06:33 2000
@@ -0,0 +1,743 @@
+/*
+ *
+ *  Copyright (C) 1998-99 Michel Aubry, Maintainer
+ *  Copyright (C) 1998-99 Andrzej Krzysztofowicz, Maintainer
+ *  Copyright (C) 1998-99 Andre Hedrick, Integrater and Maintainer
+ *
+ *  (U)DMA capable version of ali 1543(C), 1535(D)
+ *
+ */
+
+/*  ======================================================
+ *  linux/drivers/block/alim15x3.c
+ *  version: 1.0 beta3 (Sep. 6, 1999)
+ *	e-mail your problems to cjtsai@ali.com.tw
+ *
+ *  Note: if you want to combine the code to kernel 2.3.x
+ *  you should ---
+ *		change:		//#define ALI_KERNEL_2_3_X
+ *		to:			#define ALI_KERNEL_2_3_X
+ *  and replace the "alim15x3.c" exists in kernel 2.3.x
+ *  with this file. I am not very sure that this file can 
+ *  support all 2.3.x. Because I only test it in kernel
+ *  version 2.3.16. So, before you replace the file, backup
+ *	the old one.
+ * ======================================================= */
+
+/* ===================== important =======================
+ *  for 2.2.x, you should use "//#define ALI_KERNEL_2_3_X"
+ *  for 2.3.x, you should use "#define ALI_KERNEL_2_3_X"
+ * ======================================================= */
+//#define ALI_KERNEL_2_3_X
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#if defined(ALI_KERNEL_2_3_X)
+#include <linux/ide.h>
+#else
+#include "ide.h"
+#endif
+
+#include "ide_modes.h"
+
+static int m5229_revision = -1;
+static int chip_is_1543c_e = 0;
+static int cable_80_pin[2] = { 0, 0 };
+
+/* This is fun.  -DaveM */
+#define IDE_SETXFER			0x03
+#define IDE_SETFEATURE		0xef
+
+#define IDE_DMA2_ENABLE		0x22	// dma
+#define IDE_DMA1_ENABLE		0x21
+#define IDE_DMA0_ENABLE		0x20
+
+#define IDE_UDMA4_ENABLE	0x44	// ultra 66
+#define IDE_UDMA3_ENABLE	0x43
+
+#define IDE_UDMA2_ENABLE	0x42	// ultra 33
+#define IDE_UDMA1_ENABLE	0x41
+#define IDE_UDMA0_ENABLE	0x40
+
+
+
+#if defined(ALI_KERNEL_2_3_X)
+// =====================   Support 2.3.x   =====================
+
+
+#define DISPLAY_ALI_TIMINGS
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy);
+extern int (*ali_display_info)(char *, char **, off_t, int, int);  /* ide-proc.c */
+struct pci_dev *bmide_dev;
+
+char *fifo[4] = {
+	"FIFO Off",
+	"FIFO On ",
+	"DMA mode",
+	"PIO mode" };
+
+char *udmaT[8] = {
+	"1.5T",
+	"  2T",
+	"2.5T",
+	"  3T",
+	"3.5T",
+	"  4T",
+	"  6T",
+	"  8T"
+};
+
+char *channel_status[8] = {
+	"OK            ",
+	"busy          ",
+	"DRQ           ",
+	"DRQ busy      ",
+	"error         ",
+	"error busy    ",
+	"error DRQ     ",
+	"error DRQ busy"
+};
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
+{
+	byte confreg0 = 0, confreg1 =0, progif = 0;
+	int errors = 0;
+
+	if (pci_read_config_byte(dev, 0x50, &confreg1))
+		goto veryspecialsettingserror;
+	if (!(confreg1 & 0x02))
+		if (pci_write_config_byte(dev, 0x50, confreg1 | 0x02))
+			goto veryspecialsettingserror;
+
+	if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif))
+		goto veryspecialsettingserror;
+	if (!(progif & 0x40)) {
+		/*
+		 * The way to enable them is to set progif
+		 * writable at 0x4Dh register, and set bit 6
+		 * of progif to 1:
+		 */
+		if (pci_read_config_byte(dev, 0x4d, &confreg0))
+			goto veryspecialsettingserror;
+		if (confreg0 & 0x80)
+			if (pci_write_config_byte(dev, 0x4d, confreg0 & ~0x80))
+				goto veryspecialsettingserror;
+		if (pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x40))
+			goto veryspecialsettingserror;
+		if (confreg0 & 0x80)
+			if (pci_write_config_byte(dev, 0x4d, confreg0))
+				errors++;
+	}
+
+	if ((pci_read_config_byte(dev, PCI_CLASS_PROG, &progif)) || (!(progif & 0x40)))
+		goto veryspecialsettingserror;
+
+	printk("%s: enabled read of IDE channels state (en/dis-abled) %s.\n",
+		name, errors ? "with Error(s)" : "Succeeded" );
+	return 0;
+
+veryspecialsettingserror:
+	printk("%s: impossible to enable read of IDE channels state (en/dis-abled)!\n", name);
+	return 0;
+}
+
+static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
+{
+	ide_pio_data_t d;
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	int s_time, a_time, c_time;
+	byte s_clc, a_clc, r_clc;
+	unsigned long flags;
+	int bus_speed = ide_system_bus_speed();
+	int port = hwif->index ? 0x5c : 0x58;
+
+	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+	s_time = ide_pio_timings[pio].setup_time;
+	a_time = ide_pio_timings[pio].active_time;
+	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+		s_clc = 0;
+	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+		a_clc = 0;
+	c_time = ide_pio_timings[pio].cycle_time;
+
+#if 0
+	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+		r_clc = 0;
+#endif
+
+	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+		r_clc = 1;
+	} else {
+		if (r_clc >= 16)
+		r_clc = 0;
+	}
+	save_flags(flags);
+	cli();
+	pci_write_config_byte(dev, port, s_clc);
+	pci_write_config_byte(dev, port+drive->select.b.unit+2, (a_clc << 4) | r_clc);
+	restore_flags(flags);
+
+	/*
+	 * setup   active  rec
+	 * { 70,   165,    365 },   PIO Mode 0
+	 * { 50,   125,    208 },   PIO Mode 1
+	 * { 30,   100,    110 },   PIO Mode 2
+	 * { 30,   80,     70  },   PIO Mode 3 with IORDY
+	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
+	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
+	 */
+}
+
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+static int ali_get_info(char *buffer, char **addr, off_t offset, int count, int dummy)
+{
+	byte reg53h, reg5xh, reg5yh, reg5xh1, reg5yh1;
+	unsigned int bibma;
+	byte c0, c1;
+	byte rev, tmp;
+	char *p = buffer;
+	char *q;
+
+	/* fetch rev. */
+	pci_read_config_byte(bmide_dev, 0x08, &rev);
+	if (rev >= 0xc1)	/* M1543C or newer */
+		udmaT[7] = " ???";
+	else
+		fifo[3]  = "   ???  ";
+
+	/* first fetch bibma: */
+	pci_read_config_dword(bmide_dev, 0x20, &bibma);
+	bibma = (bibma & 0xfff0) ;
+	/*
+	 * at that point bibma+0x2 et bibma+0xa are byte
+	 * registers to investigate:
+	 */
+	c0 = inb((unsigned short)bibma + 0x02);
+	c1 = inb((unsigned short)bibma + 0x0a);
+
+	p += sprintf(p,
+		"\n                                Ali M15x3 Chipset.\n");
+	p += sprintf(p,
+		"                                ------------------\n");
+	pci_read_config_byte(bmide_dev, 0x78, &reg53h);
+	p += sprintf(p, "PCI Clock: %d.\n", reg53h);
+
+	pci_read_config_byte(bmide_dev, 0x53, &reg53h);
+	p += sprintf(p,
+		"CD_ROM FIFO:%s, CD_ROM DMA:%s\n",
+		(reg53h & 0x02) ? "Yes" : "No ",
+		(reg53h & 0x01) ? "Yes" : "No " );
+	pci_read_config_byte(bmide_dev, 0x74, &reg53h);
+	p += sprintf(p,
+		"FIFO Status: contains %d Words, runs%s%s\n\n",
+		(reg53h & 0x3f),
+		(reg53h & 0x40) ? " OVERWR" : "",
+		(reg53h & 0x80) ? " OVERRD." : "." );
+
+	p += sprintf(p,
+		"-------------------primary channel-------------------secondary channel---------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x09, &reg53h);
+	p += sprintf(p,
+		"channel status:       %s                               %s\n",
+		(reg53h & 0x20) ? "On " : "Off",
+		(reg53h & 0x10) ? "On " : "Off" );
+
+	p += sprintf(p,
+		"both channels togth:  %s                               %s\n",
+		(c0&0x80) ? "No " : "Yes",
+		(c1&0x80) ? "No " : "Yes" );
+
+	pci_read_config_byte(bmide_dev, 0x76, &reg53h);
+	p += sprintf(p,
+		"Channel state:        %s                    %s\n",
+		channel_status[reg53h & 0x07],
+		channel_status[(reg53h & 0x70) >> 4] );
+
+	pci_read_config_byte(bmide_dev, 0x58, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5c, &reg5yh);
+	p += sprintf(p,
+		"Add. Setup Timing:    %dT                                %dT\n",
+		(reg5xh & 0x07) ? (reg5xh & 0x07) : 8,
+		(reg5yh & 0x07) ? (reg5yh & 0x07) : 8 );
+
+	pci_read_config_byte(bmide_dev, 0x59, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5d, &reg5yh);
+	p += sprintf(p,
+		"Command Act. Count:   %dT                                %dT\n"
+		"Command Rec. Count:   %dT                               %dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8, 
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"----------------drive0-----------drive1------------drive0-----------drive1------\n\n");
+	p += sprintf(p,
+		"DMA enabled:      %s              %s               %s              %s\n",
+		(c0&0x20) ? "Yes" : "No ",
+		(c0&0x40) ? "Yes" : "No ",
+		(c1&0x20) ? "Yes" : "No ",
+		(c1&0x40) ? "Yes" : "No " );
+
+	pci_read_config_byte(bmide_dev, 0x54, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x55, &reg5yh);
+	q = "FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n";
+	if (rev < 0xc1) {
+		if ((rev == 0x20) && (pci_read_config_byte(bmide_dev, 0x4f, &tmp), (tmp &= 0x20))) {
+			p += sprintf(p, q, 8, 8, 8, 8);
+		} else {
+			p += sprintf(p, q,
+				(reg5xh & 0x03) + 12,
+				((reg5xh & 0x30)>>4) + 12,
+				(reg5yh & 0x03) + 12,
+				((reg5yh & 0x30)>>4) + 12 );
+		}
+	} else {
+		p += sprintf(p, q,
+			(tmp = (reg5xh & 0x03)) ? (tmp << 3) : 4,
+			(tmp = ((reg5xh & 0x30)>>4)) ? (tmp << 3) : 4,
+			(tmp = (reg5yh & 0x03)) ? (tmp << 3) : 4,
+			(tmp = ((reg5yh & 0x30)>>4)) ? (tmp << 3) : 4 );
+	}
+
+#if 0
+	p += sprintf(p, 
+		"FIFO threshold:   %2d Words         %2d Words          %2d Words         %2d Words\n",
+		(reg5xh & 0x03) + 12,
+		((reg5xh & 0x30)>>4) + 12,
+		(reg5yh & 0x03) + 12,
+		((reg5yh & 0x30)>>4) + 12 );
+#endif
+
+	p += sprintf(p,
+		"FIFO mode:        %s         %s          %s         %s\n",
+		fifo[((reg5xh & 0x0c) >> 2)],
+		fifo[((reg5xh & 0xc0) >> 6)],
+		fifo[((reg5yh & 0x0c) >> 2)],
+		fifo[((reg5yh & 0xc0) >> 6)] );
+
+	pci_read_config_byte(bmide_dev, 0x5a, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x5b, &reg5xh1);
+	pci_read_config_byte(bmide_dev, 0x5e, &reg5yh);
+	pci_read_config_byte(bmide_dev, 0x5f, &reg5yh1);
+
+	p += sprintf(p,/*
+		"------------------drive0-----------drive1------------drive0-----------drive1------\n")*/
+		"Dt RW act. Cnt    %2dT              %2dT               %2dT              %2dT\n"
+		"Dt RW rec. Cnt    %2dT              %2dT               %2dT              %2dT\n\n",
+		(reg5xh & 0x70) ? ((reg5xh & 0x70) >> 4) : 8,
+		(reg5xh1 & 0x70) ? ((reg5xh1 & 0x70) >> 4) : 8,
+		(reg5yh & 0x70) ? ((reg5yh & 0x70) >> 4) : 8,
+		(reg5yh1 & 0x70) ? ((reg5yh1 & 0x70) >> 4) : 8,
+		(reg5xh & 0x0f) ? (reg5xh & 0x0f) : 16,
+		(reg5xh1 & 0x0f) ? (reg5xh1 & 0x0f) : 16,
+		(reg5yh & 0x0f) ? (reg5yh & 0x0f) : 16,
+		(reg5yh1 & 0x0f) ? (reg5yh1 & 0x0f) : 16 );
+
+	p += sprintf(p,
+		"-----------------------------------UDMA Timings--------------------------------\n\n");
+
+	pci_read_config_byte(bmide_dev, 0x56, &reg5xh);
+	pci_read_config_byte(bmide_dev, 0x57, &reg5yh);
+	p += sprintf(p,
+		"UDMA:             %s               %s                %s               %s\n"
+		"UDMA timings:     %s             %s              %s             %s\n\n",
+		(reg5xh & 0x08) ? "OK" : "No",
+		(reg5xh & 0x80) ? "OK" : "No",
+		(reg5yh & 0x08) ? "OK" : "No",
+		(reg5yh & 0x80) ? "OK" : "No",
+		udmaT[(reg5xh & 0x07)],
+		udmaT[(reg5xh & 0x70) >> 4],
+		udmaT[reg5yh & 0x07],
+		udmaT[(reg5yh & 0x70) >> 4] );
+
+	return p-buffer; /* => must be less than 4k! */
+}
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */
+
+
+// ===================   End Support 2.3.x   ===================
+#endif	// defined(ALI_KERNEL_2_3_X)
+
+
+
+static __inline__ unsigned char dma2_bits_to_command(unsigned char bits)
+{
+	if(bits & 0x04)
+		return IDE_DMA2_ENABLE;
+	if(bits & 0x02)
+		return IDE_DMA1_ENABLE;
+	return IDE_DMA0_ENABLE;
+}
+
+static __inline__ unsigned char udma2_bits_to_command(unsigned char bits)
+{
+	if(bits & 0x10)
+		return IDE_UDMA4_ENABLE;
+	if(bits & 0x08)
+		return IDE_UDMA3_ENABLE;
+	if(bits & 0x04)
+		return IDE_UDMA2_ENABLE;
+	if(bits & 0x02)
+		return IDE_UDMA1_ENABLE;
+	return IDE_UDMA0_ENABLE;
+}
+
+static __inline__ int wait_for_ready(ide_drive_t *drive)
+{
+	int timeout = 20000;
+	byte stat;
+
+	while(--timeout) {
+		stat = GET_STAT();	// printk("STAT(%2x) ", stat);
+		
+		if(!(stat & BUSY_STAT)) {
+			if((stat & READY_STAT) || (stat & ERR_STAT))
+				break;
+		}
+		udelay(150);
+	}
+	if((stat & ERR_STAT) || timeout <= 0)
+		return 1;
+	return 0;
+}
+
+static void ali15x3_do_setfeature(ide_drive_t *drive, byte command)
+{
+	unsigned long flags;
+	byte old_select;
+
+	save_flags(flags);
+	cli();
+		
+	old_select = IN_BYTE(IDE_SELECT_REG);	//  save old selected device
+	OUT_BYTE(drive->select.all, IDE_SELECT_REG);	// "SELECT "
+
+	OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);	// "SETXFER "	
+	OUT_BYTE(command, IDE_NSECTOR_REG);	// "CMND "
+	
+	if(wait_for_ready(drive))	// "wait "
+		goto out;
+
+	OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG);	// "SETFEATURE "
+	(void) wait_for_ready(drive);	// "wait "
+
+out:	
+	OUT_BYTE(old_select, IDE_SELECT_REG);	// restore to old "selected device"
+	restore_flags(flags);
+}
+
+static void ali15x3_dma2_enable(ide_drive_t *drive, unsigned long dma_base)
+{
+	byte unit = (drive->select.b.unit & 0x01);
+	byte bits = (drive->id->dma_mword | drive->id->dma_1word) & 0x07;
+	byte tmpbyte;
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;		
+	
+/*	if((((drive->id->dma_mword & 0x0007) << 8) !=
+	   (drive->id->dma_mword & 0x0700)))*/
+		ali15x3_do_setfeature(drive, dma2_bits_to_command(bits));
+
+	// clear "ultra enable" bit
+	pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
+	if(unit)
+		tmpbyte &= 0x7f;
+	else
+		tmpbyte &= 0xf7;
+	save_flags(flags);
+	cli();
+	pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
+	restore_flags(flags);
+	drive->id->dma_ultra = 0x00;
+
+	/* Enable DMA*/
+	outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+
+	printk(" ALI15X3: MultiWord DMA enabled\n");
+}
+
+static void ali15x3_udma_enable(ide_drive_t *drive, unsigned long dma_base)
+{	
+	byte unit = (drive->select.b.unit & 0x01);
+	byte bits = drive->id->dma_ultra & 0x1f;	
+	byte tmpbyte;
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	unsigned char udma_mode = 0;
+	int m5229_udma_setting_index = hwif->channel? 0x57 : 0x56;
+
+	if(bits & 0x18) {	// 00011000, disk: ultra66
+		if(m5229_revision < 0xc2) {		// controller: ultra33
+			bits = 0x04;	// 00000100, use ultra33, mode 2			
+			drive->id->dma_ultra &= ~0xFF00;
+			drive->id->dma_ultra |= 0x0004;			
+		}
+		else {	// controller: ultra66
+			// Try to detect word93 bit13 and 80-pin cable (from host view)
+			if( ! ( (drive->id->word93 & 0x2000) && cable_80_pin[hwif->channel] ) ) {	
+				bits = 0x04;	// 00000100, use ultra33, mode 2
+				drive->id->dma_ultra &= ~0xFF00;
+				drive->id->dma_ultra |= 0x0004;
+			}
+		}
+	}
+
+	// set feature only if we are not in that mode
+/*	if(((drive->id->dma_ultra & 0x001f) << 8) !=
+	   (drive->id->dma_ultra & 0x1f00))*/
+		ali15x3_do_setfeature(drive, udma_mode = udma2_bits_to_command(bits));
+	udma_mode &= 0x0f;	// get UDMA mode
+
+	/* Enable DMA and UltraDMA */
+	outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
+
+	// m5229 ultra
+	pci_read_config_byte(hwif->pci_dev, m5229_udma_setting_index, &tmpbyte);
+	
+	tmpbyte &= (0x0f << ( (1-unit) << 2) );	// clear bit0~3 or bit 4~7
+	// enable ultra dma and set timing
+	tmpbyte |= ( (0x08 | (4-udma_mode) ) << (unit << 2) );
+	// set to m5229
+	save_flags(flags);
+	cli();		
+	pci_write_config_byte(hwif->pci_dev, m5229_udma_setting_index, tmpbyte);
+	restore_flags(flags);
+
+	if(udma_mode >= 3) { // ultra 66
+		pci_read_config_byte(hwif->pci_dev, 0x4b, &tmpbyte);
+		tmpbyte |= 1;			
+		save_flags(flags);
+		cli();
+		pci_write_config_byte(hwif->pci_dev, 0x4b, tmpbyte);		
+		restore_flags(flags);
+	}
+
+	printk(" ALI15X3: Ultra DMA enabled\n");
+}
+
+static int ali15x3_dma_onoff(ide_drive_t *drive, int enable)
+{
+	if(enable) {
+		ide_hwif_t *hwif = HWIF(drive);
+		unsigned long dma_base = hwif->dma_base;
+		struct hd_driveid *id = drive->id;
+				
+		if((id->field_valid & 0x0004) && 
+		   (id->dma_ultra & 0x001f)) {
+			// 1543C_E, in ultra mode, some WDC "harddisk" will cause "CRC" errors
+			// (even if no CRC problem), so we try to use "DMA" here
+			if( m5229_revision <= 0x20)
+				ali15x3_dma2_enable(drive, dma_base);	/* Normal MultiWord DMA modes. */
+			else if( (m5229_revision < 0xC2) && 
+			   ( (drive->media!=ide_disk) || (chip_is_1543c_e && strstr(id->model, "WDC ")) ) )
+				ali15x3_dma2_enable(drive, dma_base);	/* Normal MultiWord DMA modes. */
+			else	// >= 0xC2 or 0xC1 with no problem
+				ali15x3_udma_enable(drive, dma_base);	/* UltraDMA modes. */
+		} else {
+			ali15x3_dma2_enable(drive, dma_base);	/* Normal MultiWord DMA modes. */		
+		}
+	}
+
+	drive->using_dma = enable;	// on, off
+	return 0;
+}
+
+static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
+{
+	struct hd_driveid *id = drive->id;
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if( (m5229_revision<=0x20) && (drive->media!=ide_disk) )
+		return hwif->dmaproc(ide_dma_off_quietly, drive);	
+
+	/* Even if the drive is not _currently_ in a DMA
+	 * mode, we succeed, and we'll enable it manually
+	 * below in alim15x3_dma_onoff */
+	if((id != NULL) && 
+	   (id->capability & 1) &&	// dma supported
+	   hwif->autodma ) {		
+		if(id->field_valid & 0x0004)	// word 88 is valid
+			if(id->dma_ultra & 0x001F)	// 00011111 => ultra dma mode 0~4
+				return hwif->dmaproc(ide_dma_on, drive);
+
+		if(id->field_valid & 0x0002)	// words 64~70 is valid
+			if((id->dma_mword & 0x0007)	// word 63, multiword DMA mode 0~2
+			 || (id->dma_1word & 0x0007)) // word 62, single word DMA mode 0~2
+				return hwif->dmaproc(ide_dma_on, drive);
+	}
+
+	return hwif->dmaproc(ide_dma_off_quietly, drive);
+}
+
+static int ali15x3_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+		case ide_dma_check:
+			return ali15x3_config_drive_for_dma(drive);
+		case ide_dma_on:
+		case ide_dma_off:
+		case ide_dma_off_quietly:
+			return ali15x3_dma_onoff(drive, (func == ide_dma_on));					
+		case ide_dma_write:
+			if( (m5229_revision < 0xC2) && (drive->media != ide_disk) )
+				return 1;	/* try PIO instead of DMA */
+			break;
+		default:
+	}
+
+	return ide_dmaproc(func, drive);	// use standard DMA stuff
+}
+
+void __init ide_init_ali15x3 (ide_hwif_t *hwif)
+{	
+	unsigned long flags;
+	byte tmp_m5229_revision;
+
+	struct pci_dev *dev_m1533, *dev_m5229 = hwif->pci_dev;
+	byte ideic, inmir, tmpbyte;	
+	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
+								  1, 11, 0, 12, 0, 14, 0, 15 };
+
+	hwif->irq = hwif->channel ? 15 : 14;	
+
+	// look for ISA bridge m1533
+	for (dev_m1533=pci_devices; dev_m1533; dev_m1533=dev_m1533->next)
+		if(dev_m1533->vendor==PCI_VENDOR_ID_AL && 
+		   dev_m1533->device==PCI_DEVICE_ID_AL_M1533)
+			break;	// we find it
+
+	pci_read_config_byte(dev_m1533, 0x58, &ideic);	// read IDE interface control
+	ideic = ideic & 0x03;	// bit0, bit1
+	
+	/* get IRQ for IDE Controller */
+	if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) { // get SIRQ1 routing table
+		pci_read_config_byte(dev_m1533, 0x44, &inmir);	
+		inmir = inmir & 0x0f;
+		hwif->irq = irq_routing_table[inmir];
+	}	
+	else if (hwif->channel && !(ideic & 0x01)) { // get SIRQ2 routing table
+		pci_read_config_byte(dev_m1533, 0x75, &inmir);
+		inmir = inmir & 0x0f;
+		hwif->irq = irq_routing_table[inmir];
+	}
+	
+	// read m5229 revision to a temp variable
+	pci_read_config_byte(dev_m5229, PCI_REVISION_ID, &tmp_m5229_revision);
+
+	if(m5229_revision == -1)	{	// only do it one time.
+		m5229_revision = 0;	// change the default to 0	
+		printk("\n************************************\n");
+		printk("*    ALi IDE driver (1.0 beta3)    *\n");
+		printk("*       Chip Revision is %02X        *\n", tmp_m5229_revision);
+		printk("*  Maximum capability is ");
+		if(tmp_m5229_revision >= 0xC2)
+			printk("- UDMA 66 *\n");
+		else if(tmp_m5229_revision >= 0xC0)
+			printk("- UDMA 33 *\n");
+		else if(tmp_m5229_revision == 0x20)
+			printk("  -  DMA  *\n");
+		else
+			printk("  -  PIO  *\n");
+		printk("************************************\n\n");	
+
+		// support CD-ROM DMA mode
+		pci_read_config_byte(dev_m5229, 0x53, &tmpbyte);
+		tmpbyte = (tmpbyte & (~0x02)) | 0x01;
+		save_flags(flags);
+		cli();		
+		pci_write_config_byte(dev_m5229, 0x53, tmpbyte);
+		restore_flags(flags);
+	}
+	
+	if ( (hwif->dma_base) && (tmp_m5229_revision>=0x20) ) {
+		
+#if defined(ALI_KERNEL_2_3_X)
+		if(tmp_m5229_revision>=0xC2)
+			hwif->udma_four = 1;
+		else
+			hwif->udma_four = 0;
+#endif
+		
+		if(m5229_revision == 0) {	// only do it one time
+			m5229_revision = tmp_m5229_revision;	// keep it
+
+			if(m5229_revision >= 0xC2) {	// 1543C-B?, 1535, 1535D, 1553
+				// Note 1: not all "motherboard" support this detection
+				// Note 2: if no udma 66 device, the detection may "error".
+				//		   but in this case, we will not set the device to 
+				//		   ultra 66, the detection result is not important
+				save_flags(flags);
+				cli();
+				// enable "Cable Detection", m5229, 0x4b, bit3
+				pci_read_config_byte(dev_m5229, 0x4b, &tmpbyte);
+				pci_write_config_byte(dev_m5229, 0x4b, tmpbyte | 0x08);
+
+				// set south-bridge's enable bit, m1533, 0x79
+				pci_read_config_byte(dev_m1533, 0x79, &tmpbyte);
+				if(m5229_revision==0xC2)		// 1543C-B0 (m1533, 0x79, bit 2)
+					pci_write_config_byte(dev_m1533, 0x79, tmpbyte | 0x04);
+				else if	(m5229_revision==0xC3)	// 1553/1535 (m1533, 0x79, bit 1)
+					pci_write_config_byte(dev_m1533, 0x79, tmpbyte | 0x02);
+				restore_flags(flags);
+								
+				// Ultra66 cable detection (from Host View)
+				// m5229, 0x4a, bit0: primary, bit1: secondary 80 pin
+				pci_read_config_byte(dev_m5229, 0x4a, &tmpbyte);
+				if(! (tmpbyte & 0x01))	// 0x4a, bit0 is 0 => 
+					cable_80_pin[0] = 1;	// primary channel has 80-pin (from host view)
+				if(! (tmpbyte & 0x02))	// 0x4a, bit1 is 0 =>				
+					cable_80_pin[1] = 1;	// secondary channel has 80-pin (from host view)					
+			} else {
+				// revision 0x20 (1543-E, 1543-F)
+				// revision 0xC0, 0xC1 (1543C-C, 1543C-D, 1543C-E)
+				// clear CD-ROM DMA write bit, m5229, 0x4b, bit 7
+				pci_read_config_byte(dev_m5229, 0x4b, &tmpbyte);
+				save_flags(flags);
+				cli();
+				pci_write_config_byte(dev_m5229, 0x4b, tmpbyte & 0x7F);	// clear bit 7
+				restore_flags(flags);
+
+				// check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+				pci_read_config_byte(dev_m1533, 0x5e, &tmpbyte);
+				chip_is_1543c_e = ( (tmpbyte & 0x1e) == 0x12 ) ? 1: 0;
+			}			
+		}
+		
+		// M1543 or newer for DMAing
+		hwif->dmaproc = &ali15x3_dmaproc;
+		hwif->autodma = 1;
+	} else {
+		// if both channel use PIO, then chip revision is not important.
+		// we should't assign m5229_revision here (assign it will affect
+		// the chip detection procedure above --- if(! m5229_revision)
+		hwif->autodma = 0;			
+		hwif->drives[0].autotune = 1;
+		hwif->drives[1].autotune = 1;
+	}
+	
+#if defined(ALI_KERNEL_2_3_X) 
+	hwif->tuneproc = &ali15x3_tune_drive;
+#if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
+	bmide_dev = hwif->pci_dev;
+	ali_display_info = &ali_get_info;
+#endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */	
+#endif  /* defined(ALI_KERNEL_2_3_X) */	
+	
+	return;
+}
\ No newline at end of file
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/cciss.c linux.18p8/drivers/block/cciss.c
--- linux.vanilla/drivers/block/cciss.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/block/cciss.c	Fri Sep  1 13:34:06 2000
@@ -0,0 +1,1934 @@
+/*
+ *    Disk Array driver for Compaq SMART2 Controllers
+ *    Copyright 2000 Compaq Computer Corporation
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *    NON INFRINGEMENT.  See the GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/proc_fs.h>
+#include <linux/capability.h>
+#include <linux/hdreg.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+#include <asm/io.h>
+
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/genhd.h>
+
+#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
+#define DRIVER_NAME "Compaq CISS Driver (v 1.0.0)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(1,0,0)
+
+/* Embedded module documentation macros - see modules.h */
+MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation");
+MODULE_DESCRIPTION("Driver for Compaq Smart Array Controller 5300");
+
+#include "cciss_cmd.h"
+#include "cciss.h"
+#include <linux/cciss_ioctl.h>
+
+#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type))
+
+/*  board_id = Subsystem Device ID & Vendor ID
+ *  product = Marketing Name for the board
+ *  access = Address of the struct of function pointers 
+ */
+static struct board_type products[] = {
+	{ 0x40700E11, "Smart Array 5300",	&SA5_access },
+};
+
+/* How long to wait (in millesconds) for board to go into simple mode */
+#define MAX_CONFIG_WAIT 1000 
+
+#define READ_AHEAD 	 128
+#define NR_CMDS		 128 /* #commands that can be outstanding */
+#define MAX_CTLR 8
+static int nr_ctlr =0; 
+static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+static struct proc_dir_entry *proc_cciss = NULL;
+
+static void do_cciss_request(int i);
+/*
+ * This is a hack.  This driver eats a major number for each controller, and
+ * sets blkdev[xxx].request_fn to each one of these so the real request
+ * function knows what controller its working with.
+ */
+#define DO_CCISS_REQUEST(x) { do_cciss_request(x); }
+
+static void do_cciss_request0(void) DO_CCISS_REQUEST(0);
+static void do_cciss_request1(void) DO_CCISS_REQUEST(1);
+static void do_cciss_request2(void) DO_CCISS_REQUEST(2);
+static void do_cciss_request3(void) DO_CCISS_REQUEST(3);
+static void do_cciss_request4(void) DO_CCISS_REQUEST(4);
+static void do_cciss_request5(void) DO_CCISS_REQUEST(5);
+static void do_cciss_request6(void) DO_CCISS_REQUEST(6);
+static void do_cciss_request7(void) DO_CCISS_REQUEST(7);
+
+static int cciss_open(struct inode *inode, struct file *filep);
+static int cciss_release(struct inode *inode, struct file *filep);
+static int cciss_ioctl(struct inode *inode, struct file *filep, 
+		unsigned int cmd, unsigned long arg);
+
+static int revalidate_allvol(kdev_t dev);
+static int revalidate_logvol(kdev_t dev, int maxusage);
+static int frevalidate_logvol(kdev_t dev);
+
+static void cciss_getgeometry(int cntl_num);
+
+static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c);
+static void start_io( ctlr_info_t *h);
+
+static struct file_operations cciss_fops  = {
+        NULL,                        /* lseek - default */
+        block_read,                  /* read - general block-dev read */
+        block_write,                 /* write - general block-dev write */
+        NULL,                        /* readdir - bad */
+        NULL,                        /* select */
+        cciss_ioctl,                  /* ioctl */
+        NULL,                        /* mmap */
+        cciss_open,                     /* open code */
+        NULL,
+        cciss_release,                  /* release */
+        block_fsync,                  /* fsync */
+        NULL,                        /* fasync */
+        NULL,                   /* Disk change */
+        frevalidate_logvol,     /* revalidate */
+};
+
+/*
+ * Report information about this controller.
+ */
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+        off_t pos = 0;
+        off_t len = 0;
+        int size, i, ctlr;
+        ctlr_info_t *h = (ctlr_info_t*)data;
+        drive_info_struct *drv;
+
+        ctlr = h->ctlr;
+        size = sprintf(buffer, "%s:  Compaq %s Controller\n"
+                "       Board ID: %08lx\n"
+		"       Firmware Version: %c%c%c%c\n"
+                "       Memory Address: %08lx\n"
+                "       IRQ: 0x%x\n"
+                "       Logical drives: %d\n"
+                "       Current Q depth: %d\n"
+		"       Current # commands on controller %d\n"
+                "       Max Q depth since init: %d\n"
+		"       Max # commands on controller since init: %d\n"
+		"       Max SG entries since init: %d\n\n",
+                h->devname,
+                h->product_name,
+                (unsigned long)h->board_id,
+		h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
+                (unsigned long)h->vaddr,
+                (unsigned int)h->intr,
+                h->num_luns, 
+                h->Qdepth, h->commands_outstanding,
+		h->maxQsinceinit, h->max_outstanding, h->maxSG);
+
+        pos += size; len += size;
+	for(i=0; i<h->num_luns; i++) {
+                drv = &h->drv[i];
+                size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n",
+                                ctlr, i, drv->block_size, drv->nr_blocks);
+                pos += size; len += size;
+        }
+
+	size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
+                        h->nr_allocs, h->nr_frees);
+        pos += size; len += size;
+
+        *eof = 1;
+        *start = buffer+offset;
+        len -= offset;
+        if (len>length)
+                len = length;
+        return len;
+}
+
+/*
+ * Get us a file in /proc/cciss that says something about each controller.
+ * Create /proc/cciss if it doesn't exist yet.
+ */
+static void cciss_procinit(int i)
+{
+        struct proc_dir_entry *pd;
+
+        if (proc_cciss == NULL) {
+                proc_cciss = create_proc_entry("cciss", S_IFDIR|S_IRUGO|S_IXUGO,                                                                &proc_root);
+                if (!proc_cciss) 
+			return;
+        }
+
+        pd = create_proc_entry(hba[i]->devname, S_IFREG|S_IRUGO, proc_cciss);
+        if (!pd) 
+		return;
+        pd->read_proc = cciss_proc_get_info;
+        pd->data = hba[i];
+}
+
+/* 
+ * For operations that cannot sleep, a command block is allocated at init, 
+ * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
+ * which ones are free or in use.  For operations that can wait for kmalloc 
+ * to possible sleep, this routine can be called with a NULL pointer. 
+ * cmd_free() MUST be called with a NULL pointer if cmd_alloc was. 
+ */ 
+static CommandList_struct * cmd_alloc(ctlr_info_t *h)
+{
+	CommandList_struct *c;
+	int i; 
+	u64bit temp64;
+
+	if (h == NULL)
+	{
+		c = (CommandList_struct *)kmalloc(sizeof(CommandList_struct), 
+			GFP_KERNEL);
+        	if(c==NULL)
+                 	return NULL;
+		memset(c, 0, sizeof(CommandList_struct));
+
+		c->err_info = (ErrorInfo_struct *)kmalloc(
+					sizeof(ErrorInfo_struct), GFP_KERNEL);
+	
+		if (c->err_info == NULL)
+		{
+			kfree(c);
+			return NULL;
+		}
+		memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+	} else /* get it out of the controllers pool */ 
+	{
+	     	do {
+                	i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
+                        if (i == NR_CMDS)
+                                return NULL;
+                } while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0);
+#ifdef CCISS_DEBUG
+		printk(KERN_DEBUG "cciss: using command buffer %d\n", i);
+#endif
+                c = h->cmd_pool + i;
+		memset(c, 0, sizeof(CommandList_struct));			
+		c->err_info = h->errinfo_pool + i;
+		memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+                h->nr_allocs++;
+        }
+
+
+	temp64.val = (__u64) virt_to_bus(c->err_info);
+	c->ErrDesc.Addr.lower = temp64.val32.lower;
+	c->ErrDesc.Addr.upper = temp64.val32.upper;
+	c->ErrDesc.Len = sizeof(ErrorInfo_struct);
+       	c->busaddr = virt_to_bus(c);
+        return c;
+
+
+}
+
+/* 
+ * Frees a command block that was previously allocated with cmd_alloc(). 
+ */
+static void cmd_free(ctlr_info_t *h, CommandList_struct *c)
+{
+	int i;
+
+	if( h == NULL)
+	{ 
+		kfree(c->err_info);
+		kfree(c);	
+	} else 
+	{
+		i = c - h->cmd_pool;
+		clear_bit(i%32, h->cmd_pool_bits+(i/32));
+                h->nr_frees++;
+        }
+}
+
+/*  
+ * fills in the disk information. 
+ */
+static void cciss_geninit( struct gendisk *g)
+{
+	int ctlr = -1; 
+	drive_info_struct *drv;
+	int i,j;
+
+	/* find the controller this gendisk data is from */ 
+	for(i=0; i < nr_ctlr; i++)
+	{
+		if ( g == &(hba[i]->gendisk))
+		{
+			ctlr = i;
+			break;
+		}
+	}
+	if ( ctlr < 0) 
+	{
+		printk(KERN_WARNING "cciss: gendisk data invalid\n");
+		return;
+	}
+	/* Loop through each real device */ 
+	g->nr_real = 0; 
+	for(i=0; i< NWD; i++)
+	{
+		drv = &(hba[ctlr]->drv[i]);
+		if( !(drv->nr_blocks))
+			continue;
+		hba[ctlr]->hd[i << NWD_SHIFT].nr_sects = 
+		hba[ctlr]->sizes[i << NWD_SHIFT] = drv->nr_blocks;
+
+		/* for each partition */ 
+		for(j=0; j<MAX_PART; j++)
+		{
+			hba[ctlr]->blocksizes[(i<<NWD_SHIFT) + j] = 1024; 
+
+			hba[ctlr]->hardsizes[ (i<<NWD_SHIFT) + j] = 
+				drv->block_size;
+		}
+		g->nr_real++;
+	}
+}
+/*
+ * Open.  Make sure the device is really there.
+ */
+static int cciss_open(struct inode *inode, struct file *filep)
+{
+	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "cciss_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk);
+#endif /* CCISS_DEBUG */ 
+
+	if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
+		return -ENXIO;
+
+	if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0)
+		return -ENXIO;
+
+	/*
+	 * Root is allowed to open raw volume zero even if its not configured
+	 * so array config can still work.  I don't think I really like this,
+	 * but I'm already using way to many device nodes to claim another one
+	 * for "raw controller".
+	 */
+	if (suser()
+		&& (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) 
+		&& (MINOR(inode->i_rdev)!= 0))
+		return -ENXIO;
+
+	hba[ctlr]->drv[dsk].usage_count++;
+	hba[ctlr]->usage_count++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+/*
+ * Close.  Sync first.
+ */
+static int cciss_release(struct inode *inode, struct file *filep)
+{
+	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "cciss_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk);
+#endif /* CCISS_DEBUG */
+
+	fsync_dev(inode->i_rdev);
+
+	hba[ctlr]->drv[dsk].usage_count--;
+	hba[ctlr]->usage_count--;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * ioctl 
+ */
+static int cciss_ioctl(struct inode *inode, struct file *filep, 
+		unsigned int cmd, unsigned long arg)
+{
+	int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
+	int dsk  = MINOR(inode->i_rdev) >> NWD_SHIFT;
+	int diskinfo[4];
+	struct hd_geometry *geo = (struct hd_geometry *)arg;
+
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);
+#endif /* CCISS_DEBUG */ 
+	
+	switch(cmd) {
+	case HDIO_GETGEO:
+		if (hba[ctlr]->drv[dsk].cylinders) {
+			diskinfo[0] = hba[ctlr]->drv[dsk].heads;
+			diskinfo[1] = hba[ctlr]->drv[dsk].sectors;
+			diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;
+		} else {
+			diskinfo[0] = 0xff;
+			diskinfo[1] = 0x3f;
+			diskinfo[2] = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f);		}
+		put_user(diskinfo[0], &geo->heads);
+		put_user(diskinfo[1], &geo->sectors);
+		put_user(diskinfo[2], &geo->cylinders);
+		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].start_sect, &geo->start);
+		return 0;
+	case BLKGETSIZE:
+		if (!arg) return -EINVAL;
+		put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (long*)arg);
+		return 0;
+	case BLKRASET:
+		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+		if (!(inode->i_rdev)) return -EINVAL;
+		if (arg>0xff) return -EINVAL;
+		read_ahead[MAJOR(inode->i_rdev)] = arg;
+		return 0;
+	case BLKRAGET:
+		if (!arg) return -EINVAL;
+		put_user(read_ahead[MAJOR(inode->i_rdev)], (int*)arg);
+		return 0;
+	case BLKRRPART:
+		return revalidate_logvol(inode->i_rdev, 1);
+
+	case CCISS_GETPCIINFO:
+	{
+		cciss_pci_info_struct pciinfo;
+
+		if (!arg) return -EINVAL;
+		pciinfo.bus = hba[ctlr]->pci_bus;
+		pciinfo.dev_fn = hba[ctlr]->pci_dev_fn;
+		pciinfo.board_id = hba[ctlr]->board_id;
+		copy_to_user_ret((void *) arg, &pciinfo,  
+			sizeof( cciss_pci_info_struct),  -EFAULT);
+		return(0);
+	}	
+	case CCISS_GETINTINFO:
+	{
+		cciss_coalint_struct intinfo;
+		ctlr_info_t *c = hba[ctlr];
+
+		if (!arg) return -EINVAL;
+		intinfo.delay = readl(&c->cfgtable->HostWrite.CoalIntDelay);
+		intinfo.count = readl(&c->cfgtable->HostWrite.CoalIntCount);
+		copy_to_user_ret((void *) arg, &intinfo,
+                        sizeof( cciss_coalint_struct),  -EFAULT);
+                return(0);
+        }
+	case CCISS_SETINTINFO:
+        {
+                cciss_coalint_struct intinfo;
+                ctlr_info_t *c = hba[ctlr];
+		unsigned long flags;
+		int i;
+
+		if (!arg) return -EINVAL;	
+		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		copy_from_user_ret(&intinfo, (void *) arg, 
+			sizeof( cciss_coalint_struct),  -EFAULT);
+		if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
+
+		{
+//			printk("cciss_ioctl: delay and count cannot be 0\n");
+			return( -EINVAL);
+		}
+		spin_lock_irqsave(&io_request_lock, flags);
+		/* Can only safely update if no commands outstanding */ 
+		if (c->commands_outstanding > 0 )
+		{
+//			printk("cciss_ioctl: cannot change coalasing "
+//				"%d commands outstanding on controller\n", 
+//					c->commands_outstanding);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			return(-EINVAL);
+		}
+		/* Update the field, and then ring the doorbell */ 
+		writel( intinfo.delay, 
+			&(c->cfgtable->HostWrite.CoalIntDelay));
+		writel( intinfo.count, 
+                        &(c->cfgtable->HostWrite.CoalIntCount));
+		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
+
+		for(i=0;i<MAX_CONFIG_WAIT;i++)
+		{
+			if (!(readl(c->vaddr + SA5_DOORBELL) 
+					& CFGTBL_ChangeReq))
+				break;
+			/* delay and try again */
+			udelay(1000);
+		}	
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		if (i >= MAX_CONFIG_WAIT)
+			return( -EFAULT);
+                return(0);
+        }
+	case CCISS_GETNODENAME:
+        {
+                NodeName_type NodeName;
+                ctlr_info_t *c = hba[ctlr];
+		int i; 
+
+		if (!arg) return -EINVAL;
+		for(i=0;i<16;i++)
+			NodeName[i] = readb(&c->cfgtable->ServerName[i]);
+                copy_to_user_ret((void *) arg, NodeName,
+                        sizeof( NodeName_type),  -EFAULT);
+                return(0);
+        }
+	case CCISS_SETNODENAME:
+	{
+		NodeName_type NodeName;
+		ctlr_info_t *c = hba[ctlr];
+		unsigned long flags;
+		int i;
+
+		if (!arg) return -EINVAL;
+		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+		
+		copy_from_user_ret(NodeName, (void *) arg, 
+			sizeof( NodeName_type),  -EFAULT);
+
+		spin_lock_irqsave(&io_request_lock, flags);
+
+			/* Update the field, and then ring the doorbell */ 
+		for(i=0;i<16;i++)
+			writeb( NodeName[i], &c->cfgtable->ServerName[i]);
+			
+		writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
+
+		for(i=0;i<MAX_CONFIG_WAIT;i++)
+		{
+			if (!(readl(c->vaddr + SA5_DOORBELL) 
+					& CFGTBL_ChangeReq))
+				break;
+			/* delay and try again */
+			udelay(1000);
+		}	
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		if (i >= MAX_CONFIG_WAIT)
+			return( -EFAULT);
+                return(0);
+        }
+
+	case CCISS_GETHEARTBEAT:
+        {
+                Heartbeat_type heartbeat;
+                ctlr_info_t *c = hba[ctlr];
+
+		if (!arg) return -EINVAL;
+                heartbeat = readl(&c->cfgtable->HeartBeat);
+                copy_to_user_ret((void *) arg, &heartbeat,
+                        sizeof( Heartbeat_type),  -EFAULT);
+                return(0);
+        }
+	case CCISS_GETBUSTYPES:
+        {
+                BusTypes_type BusTypes;
+                ctlr_info_t *c = hba[ctlr];
+
+		if (!arg) return -EINVAL;
+                BusTypes = readl(&c->cfgtable->BusTypes);
+                copy_to_user_ret((void *) arg, &BusTypes,
+                        sizeof( BusTypes_type),  -EFAULT);
+                return(0);
+        }
+	case CCISS_GETFIRMVER:
+        {
+		FirmwareVer_type firmware;
+
+		if (!arg) return -EINVAL;
+		memcpy(firmware, hba[ctlr]->firm_ver, 4);
+
+                copy_to_user_ret((void *) arg, firmware,
+                        sizeof( FirmwareVer_type),  -EFAULT);
+                return(0);
+        }
+        case CCISS_GETDRIVVER:
+        {
+		DriverVer_type DriverVer = DRIVER_VERSION;
+
+                if (!arg) return -EINVAL;
+
+                copy_to_user_ret((void *) arg, &DriverVer,
+                        sizeof( DriverVer_type),  -EFAULT);
+                return(0);
+        }
+
+	case CCISS_REVALIDVOLS:
+                return( revalidate_allvol(inode->i_rdev));
+	
+	case CCISS_PASSTHRU:
+	{
+		IOCTL_Command_struct iocommand;
+		ctlr_info_t *h = hba[ctlr];
+		CommandList_struct *c;
+		char 	*buff = NULL;
+		u64bit	temp64;
+		unsigned long flags;
+
+		if (!arg) return -EINVAL;
+	
+		if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+
+		copy_from_user_ret(&iocommand, (void *) arg,
+                        sizeof( IOCTL_Command_struct),  -EFAULT); 
+		if((iocommand.buf_size < 1) && 
+				(iocommand.Request.Type.Direction != XFER_NONE))
+		{	
+			return -EINVAL;
+		} 
+		/* Check kmalloc limits */
+		if(iocommand.buf_size > 128000)
+			return -EINVAL;
+		if(iocommand.buf_size > 0)
+		{
+			buff =  kmalloc(iocommand.buf_size, GFP_KERNEL);
+			if( buff == NULL) 
+				return -EFAULT;
+		}
+		if (iocommand.Request.Type.Direction == XFER_WRITE)
+		{
+			/* Copy the data into the buffer we created */ 
+			copy_from_user_ret(buff, iocommand.buf,
+                        	iocommand.buf_size,  -EFAULT);
+		}
+		if ((c = cmd_alloc(NULL)) == NULL)
+		{
+			if(buff!=NULL)
+				kfree(buff);
+			return -ENOMEM;
+		}
+			// Fill in the command type 
+		c->cmd_type = CMD_IOCTL_PEND;
+			// Fill in Command Header 
+		c->Header.ReplyQueue = 0;  // unused in simple mode
+		if( iocommand.buf_size > 0) 	// buffer to fill 
+		{
+			c->Header.SGList = 1;
+			c->Header.SGTotal= 1;
+		} else	// no buffers to fill  
+		{
+			c->Header.SGList = 0;
+                	c->Header.SGTotal= 0;
+		}
+		c->Header.LUN = iocommand.LUN_info;
+		c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
+		
+		// Fill in Request block 
+		c->Request = iocommand.Request; 
+	
+		// Fill in the scatter gather information
+		if (iocommand.buf_size > 0 ) 
+		{	
+			temp64.val = (__u64) virt_to_bus(buff);
+			c->SG[0].Addr.lower = temp64.val32.lower;
+			c->SG[0].Addr.upper = temp64.val32.upper;
+			c->SG[0].Len = iocommand.buf_size;
+			c->SG[0].Ext = 0;  // we are not chaining
+		}
+		/* Put the request on the tail of the request queue */
+		spin_lock_irqsave(&io_request_lock, flags);
+		addQ(&h->reqQ, c);
+		h->Qdepth++;
+		start_io(h);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+
+		/* Wait for completion */
+		while(c->cmd_type != CMD_IOCTL_DONE)
+		{
+			schedule_timeout(1);
+			rmb();
+		}
+
+		/* Copy the error information out */ 
+		iocommand.error_info = *(c->err_info);
+		if ( copy_to_user((void *) arg, &iocommand,
+                        sizeof( IOCTL_Command_struct) ) < 0 )
+		{
+			cmd_free(NULL, c);
+			if (buff != NULL) 
+				kfree(buff);
+			return( -EFAULT);	
+		} 	
+
+		if (iocommand.Request.Type.Direction == XFER_READ)
+                {
+                        /* Copy the data out of the buffer we created */
+                        if (copy_to_user(iocommand.buf, buff, 
+                        	iocommand.buf_size) < 0) 
+			{
+			             cmd_free(NULL, c);
+			             kfree(buff);
+			}
+                }
+		cmd_free(NULL, c);
+                if (buff != NULL)
+                	kfree(buff);
+                return(0);
+	} 
+
+	RO_IOCTLS(inode->i_rdev, arg);
+
+	default:
+		return -EBADRQC;
+	}
+	
+}
+
+/* Borrowed and adapted from sd.c */
+static int revalidate_logvol(kdev_t dev, int maxusage)
+{
+        int ctlr, target;
+        struct gendisk *gdev;
+        unsigned long flags;
+        int max_p;
+        int start;
+        int i;
+
+        target = MINOR(dev) >> NWD_SHIFT;
+        ctlr = MAJOR(dev) - MAJOR_NR;
+        gdev = &(hba[ctlr]->gendisk);
+
+        spin_lock_irqsave(&io_request_lock, flags);
+        if (hba[ctlr]->drv[target].usage_count > maxusage) {
+                spin_unlock_irqrestore(&io_request_lock, flags);
+                printk(KERN_WARNING "cpqarray: Device busy for "
+                        "revalidation (usage=%d)\n",
+                        hba[ctlr]->drv[target].usage_count);
+                return -EBUSY;
+        }
+        hba[ctlr]->drv[target].usage_count++;
+        spin_unlock_irqrestore(&io_request_lock, flags);
+
+        max_p = gdev->max_p;
+        start = target << gdev->minor_shift;
+
+        for(i=max_p; i>=0; i--) {
+                int minor = start+i;
+                kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
+                struct super_block *sb = get_super(devi);
+                sync_dev(devi);
+                if (sb) invalidate_inodes(sb);
+                invalidate_buffers(devi);
+                gdev->part[minor].start_sect = 0;
+                gdev->part[minor].nr_sects = 0;
+
+                /* reset the blocksize so we can read the partition table */
+                blksize_size[MAJOR_NR+ctlr][minor] = 1024;
+        }
+	gdev->part[start].nr_sects =  hba[ctlr]->drv[target].nr_blocks;
+        resetup_one_dev(gdev, target);
+        hba[ctlr]->drv[target].usage_count--;
+        return 0;
+}
+
+static int frevalidate_logvol(kdev_t dev)
+{
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "cciss: frevalidate has been called\n");
+#endif /* CCISS_DEBUG */ 
+	return revalidate_logvol(dev, 0);
+}
+
+/*
+ * revalidate_allvol is for online array config utilities.  After a
+ * utility reconfigures the drives in the array, it can use this function
+ * (through an ioctl) to make the driver zap any previous disk structs for
+ * that controller and get new ones.
+ *
+ * Right now I'm using the getgeometry() function to do this, but this
+ * function should probably be finer grained and allow you to revalidate one
+ * particualar logical volume (instead of all of them on a particular
+ * controller).
+ */
+static int revalidate_allvol(kdev_t dev)
+{
+	int ctlr, i;
+	unsigned long flags;
+
+	ctlr = MAJOR(dev) - MAJOR_NR;
+        if (MINOR(dev) != 0)
+                return -ENXIO;
+
+        spin_lock_irqsave(&io_request_lock, flags);
+        if (hba[ctlr]->usage_count > 1) {
+                spin_unlock_irqrestore(&io_request_lock, flags);
+                printk(KERN_WARNING "cciss: Device busy for volume"
+                        " revalidation (usage=%d)\n", hba[ctlr]->usage_count);
+                return -EBUSY;
+        }
+        spin_unlock_irqrestore(&io_request_lock, flags);
+        hba[ctlr]->usage_count++;
+
+        /*
+         * Set the partition and block size structures for all volumes
+         * on this controller to zero.  We will reread all of this data
+         */
+	memset(hba[ctlr]->hd,         0, sizeof(struct hd_struct) * 256);
+        memset(hba[ctlr]->sizes,      0, sizeof(int) * 256);
+        memset(hba[ctlr]->blocksizes, 0, sizeof(int) * 256);
+        memset(hba[ctlr]->hardsizes,  0, sizeof(int) * 256);
+        memset(hba[ctlr]->drv,        0, sizeof(drive_info_struct)
+						* CISS_MAX_LUN);
+        hba[ctlr]->gendisk.nr_real = 0;
+
+        /*
+         * Tell the array controller not to give us any interupts while
+         * we check the new geometry.  Then turn interrupts back on when
+         * we're done.
+         */
+        hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_OFF);
+        cciss_getgeometry(ctlr);
+        hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_ON);
+
+        cciss_geninit(&(hba[ctlr]->gendisk));
+        for(i=0; i<NWD; i++)
+                if (hba[ctlr]->sizes[ i<<NWD_SHIFT ])
+                        revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
+
+        hba[ctlr]->usage_count--;
+        return 0;
+}
+
+
+
+/*
+ *   Wait polling for a command to complete.
+ *   The memory mapped FIFO is polled for the completion.
+ *   Used only at init time, interrupts disabled.
+ */
+static unsigned long pollcomplete(int ctlr)
+{
+        unsigned long done;
+        int i;
+
+        /* Wait (up to 2 seconds) for a command to complete */
+
+        for (i = 200000; i > 0; i--) {
+                done = hba[ctlr]->access.command_completed(hba[ctlr]);
+                if (done == FIFO_EMPTY) {
+                        udelay(10);     /* a short fixed delay */
+                } else
+                        return (done);
+        }
+        /* Invalid address to tell caller we ran out of time */
+        return 1;
+}
+/*
+ * Send a command to the controller, and wait for it to complete.  
+ * Only used at init time. 
+ */
+static int sendcmd(
+	__u8	cmd,
+	int	ctlr,
+	void	*buff,
+	size_t	size,
+	unsigned int use_unit_num,
+	unsigned int log_unit,
+	__u8	page_code )
+{
+	CommandList_struct *c;
+	int i;
+	unsigned long complete;
+	ctlr_info_t *info_p= hba[ctlr];
+	u64bit temp64;
+
+	c = cmd_alloc(info_p);
+	if (c == NULL)
+	{
+		printk(KERN_WARNING "cciss: unable to get memory");
+		return(IO_ERROR);
+	}
+	// Fill in Command Header 
+	c->Header.ReplyQueue = 0;  // unused in simple mode
+	if( buff != NULL) 	// buffer to fill 
+	{
+		c->Header.SGList = 1;
+		c->Header.SGTotal= 1;
+	} else	// no buffers to fill  
+	{
+		c->Header.SGList = 0;
+                c->Header.SGTotal= 0;
+	}
+	c->Header.Tag.lower = c->busaddr;  // use the kernel address the cmd block for tag
+	// Fill in Request block 	
+	switch(cmd)
+	{
+		case  CISS_INQUIRY:
+			/* If the logical unit number is 0 then, this is going
+				to controller so It's a physical command
+				mode = 0 target = 0.
+				So we have nothing to write. 
+				Otherwise 
+				mode = 1  target = LUNID
+			*/
+			if(use_unit_num != 0)
+			{
+				c->Header.LUN.LogDev.VolId=
+                                	hba[ctlr]->drv[log_unit].LunID;
+                        	c->Header.LUN.LogDev.Mode = 1;
+			}
+			/* are we trying to read a vital product page */
+			if(page_code != 0)
+			{
+				c->Request.CDB[1] = 0x01;
+				c->Request.CDB[2] = page_code;
+			}
+			c->Request.CDBLen = 6;
+			c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+			c->Request.Type.Attribute = ATTR_SIMPLE;  
+			c->Request.Type.Direction = XFER_READ; // Read 
+			c->Request.Timeout = 0; // Don't time out 
+			c->Request.CDB[0] =  CISS_INQUIRY;
+			c->Request.CDB[4] = size  & 0xFF;  
+		break;
+		case CISS_REPORT_LOG:
+                        /* Talking to controller so It's a physical command
+                                mode = 00 target = 0.
+                                So we have nothing to write.
+                        */
+                        c->Request.CDBLen = 12;
+                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Attribute = ATTR_SIMPLE; 
+                        c->Request.Type.Direction = XFER_READ; // Read
+                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.CDB[0] = CISS_REPORT_LOG;
+                        c->Request.CDB[6] = (size >> 24) & 0xFF;  //MSB
+                        c->Request.CDB[7] = (size >> 16) & 0xFF;
+                        c->Request.CDB[8] = (size >> 8) & 0xFF;
+                        c->Request.CDB[9] = size & 0xFF;
+                break;
+
+		case CCISS_READ_CAPACITY:
+			c->Header.LUN.LogDev.VolId= 
+				hba[ctlr]->drv[log_unit].LunID;
+			c->Header.LUN.LogDev.Mode = 1;
+			c->Request.CDBLen = 10;
+                        c->Request.Type.Type =  TYPE_CMD; // It is a command.
+                        c->Request.Type.Attribute = ATTR_SIMPLE; 
+                        c->Request.Type.Direction = XFER_READ; // Read
+                        c->Request.Timeout = 0; // Don't time out
+                        c->Request.CDB[0] = CCISS_READ_CAPACITY;
+		break;
+		default:
+			printk(KERN_WARNING
+				"cciss:  Unknown Command 0x%c sent attempted\n",
+				  cmd);
+			cmd_free(info_p, c);
+			return(IO_ERROR);
+	};
+	// Fill in the scatter gather information
+	if (size > 0 ) 
+	{
+		temp64.val = (__u64) virt_to_bus(buff);
+		c->SG[0].Addr.lower = temp64.val32.lower;
+		c->SG[0].Addr.upper = temp64.val32.upper;
+		c->SG[0].Len = size;
+		c->SG[0].Ext = 0;  // we are not chaining
+	}
+	/*
+         * Disable interrupt
+         */
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "cciss: turning intr off\n");
+#endif /* CCISS_DEBUG */ 
+        info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
+	
+	/* Make sure there is room in the command FIFO */
+        /* Actually it should be completely empty at this time. */
+        for (i = 200000; i > 0; i--) 
+	{
+		/* if fifo isn't full go */
+                if (!(info_p->access.fifo_full(info_p))) 
+		{
+			
+                        break;
+                }
+                udelay(10);
+                printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
+                        " waiting!\n", ctlr);
+        }
+        /*
+         * Send the cmd
+         */
+        info_p->access.submit_command(info_p, c);
+        complete = pollcomplete(ctlr);
+
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "cciss: command completed\n");
+#endif /* CCISS_DEBUG */
+
+	if (complete != 1) {
+		if ( (complete & CISS_ERROR_BIT)
+		     && (complete & ~CISS_ERROR_BIT) == c->busaddr)
+		     {
+			/* if data overrun or underun on Report command 
+				ignore it 
+			*/
+			if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
+			     (c->Request.CDB[0] == CISS_INQUIRY)) &&
+				((c->err_info->CommandStatus == 
+					CMD_DATA_OVERRUN) || 
+				 (c->err_info->CommandStatus == 
+					CMD_DATA_UNDERRUN)
+			 	))
+			{
+				complete = c->busaddr;
+			} else
+			{
+				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+				" Error %x \n", ctlr, 
+					c->err_info->CommandStatus); 
+				printk(KERN_WARNING "ciss ciss%d: sendcmd"
+				" offensive info\n"
+				"  size %x\n   num %x   value %x\n", ctlr,
+				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
+				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
+				  c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
+				cmd_free(info_p,c);
+				return(IO_ERROR);
+			}
+		}
+                if (complete != c->busaddr) {
+                        printk( KERN_WARNING "cciss cciss%d: SendCmd "
+                      "Invalid command list address returned! (%lx)\n",
+                                ctlr, complete);
+                        cmd_free(info_p, c);
+                        return (IO_ERROR);
+                }
+        } else {
+                printk( KERN_WARNING
+                        "cciss cciss%d: SendCmd Timeout out, "
+                        "No command list address returned!\n",
+                        ctlr);
+                cmd_free(info_p, c);
+                return (IO_ERROR);
+        }
+	cmd_free(info_p, c);
+        return (IO_OK);
+} 
+/*
+ * Map (physical) PCI mem into (virtual) kernel space
+ */
+static ulong remap_pci_mem(ulong base, ulong size)
+{
+        ulong page_base        = ((ulong) base) & PAGE_MASK;
+        ulong page_offs        = ((ulong) base) - page_base;
+        ulong page_remapped    = (ulong) ioremap(page_base, page_offs+size);
+
+        return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL);
+}
+
+/*
+ * Enqueuing and dequeuing functions for cmdlists.
+ */
+static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
+{
+        if (*Qptr == NULL) {
+                *Qptr = c;
+                c->next = c->prev = c;
+        } else {
+                c->prev = (*Qptr)->prev;
+                c->next = (*Qptr);
+                (*Qptr)->prev->next = c;
+                (*Qptr)->prev = c;
+        }
+}
+
+static inline CommandList_struct *removeQ(CommandList_struct **Qptr, 
+						CommandList_struct *c)
+{
+        if (c && c->next != c) {
+                if (*Qptr == c) *Qptr = c->next;
+                c->prev->next = c->next;
+                c->next->prev = c->prev;
+        } else {
+                *Qptr = NULL;
+        }
+        return c;
+}
+
+/* 
+ * Takes jobs of the Q and sends them to the hardware, then puts it on 
+ * the Q to wait for completion. 
+ */ 
+static void start_io( ctlr_info_t *h)
+{
+	CommandList_struct *c;
+	
+	while(( c = h->reqQ) != NULL )
+	{
+		/* can't do anything if fifo is full */
+		if ((h->access.fifo_full(h)))
+		{
+			printk(KERN_WARNING "cciss: fifo full \n");
+			return;
+		}
+		/* Get the frist entry from the Request Q */ 
+		removeQ(&(h->reqQ), c);
+		h->Qdepth--;
+	
+		/* Tell the controller execute command */ 
+		h->access.submit_command(h, c);
+		
+		/* Put job onto the completed Q */ 
+		addQ (&(h->cmpQ), c); 
+	}
+}
+
+static inline void complete_buffers( struct buffer_head *bh, int status)
+{
+	struct buffer_head *xbh;
+	
+	while(bh)
+	{
+		xbh = bh->b_reqnext; 
+		bh->b_reqnext = NULL; 
+		bh->b_end_io(bh, status);
+		bh = xbh;
+	}
+} 
+/* checks the status of the job and calls complete buffers to mark all 
+ * buffers for the completed job. 
+ */ 
+static inline void complete_command( CommandList_struct *cmd, int timeout)
+{
+	int status = 1;
+	
+	if (timeout)
+		status = 0; 
+	if(cmd->err_info->CommandStatus != 0) 
+	{ /* an error has occured */ 
+		switch(cmd->err_info->CommandStatus)
+		{
+			case CMD_TARGET_STATUS:
+				printk(KERN_WARNING "cciss: cmd %p has "
+					" completed with errors\n", cmd);
+				if( cmd->err_info->ScsiStatus)
+                		{
+                    			printk(KERN_WARNING "cciss: cmd %p "
+					"has SCSI Status = %x\n",
+                        			cmd,  
+						cmd->err_info->ScsiStatus);
+                		}
+
+			break;
+			case CMD_DATA_UNDERRUN:
+				printk(KERN_WARNING "cciss: cmd %p has"
+					" completed with data underrun "
+					"reported\n", cmd);
+			break;
+			case CMD_DATA_OVERRUN:
+				printk(KERN_WARNING "cciss: cmd %p has"
+					" completed with data overrun "
+					"reported\n", cmd);
+			break;
+			case CMD_INVALID:
+				printk(KERN_WARNING "cciss: cmd %p is "
+					"reported invalid\n", cmd);
+				status = 0;
+			break;
+			case CMD_PROTOCOL_ERR:
+                                printk(KERN_WARNING "cciss: cmd %p has "
+					"protocol error \n", cmd);
+                                status = 0;
+                        break;
+			case CMD_HARDWARE_ERR:
+                                printk(KERN_WARNING "cciss: cmd %p had " 
+                                        " hardware error\n", cmd);
+                                status = 0;
+                        break;
+			case CMD_CONNECTION_LOST:
+				printk(KERN_WARNING "cciss: cmd %p had "
+					"connection lost\n", cmd);
+				status=0;
+			break;
+			case CMD_ABORTED:
+				printk(KERN_WARNING "cciss: cmd %p was "
+					"aborted\n", cmd);
+				status=0;
+			break;
+			case CMD_ABORT_FAILED:
+				printk(KERN_WARNING "cciss: cmd %p reports "
+					"abort failed\n", cmd);
+				status=0;
+			break;
+			case CMD_UNSOLICITED_ABORT:
+				printk(KERN_WARNING "cciss: cmd %p aborted "
+					"do to an unsolicited abort\n", cmd);
+				status=0;
+			break;
+			case CMD_TIMEOUT:
+				printk(KERN_WARNING "cciss: cmd %p timedout\n",
+					cmd);
+				status=0;
+			break;
+			default:
+				printk(KERN_WARNING "cciss: cmd %p returned "
+					"unknown status %x\n", cmd, 
+						cmd->err_info->CommandStatus); 
+				status=0;
+		}
+	}
+	complete_buffers(cmd->bh, status);
+}
+/* 
+ * Get a request and submit it to the controller. 
+ * Currently we do one request at a time.  Ideally we would like to send
+ * everything to the controller on the first call, but there is a danger
+ * of holding the io_request_lock for to long.  
+ */
+static void do_cciss_request(int ctlr)
+{
+	ctlr_info_t *h= hba[ctlr];
+	CommandList_struct *c;
+	int log_unit, start_blk, seg, sect;
+	char *lastdataend;
+	struct buffer_head *bh;
+	struct request *creq;
+	u64bit temp64;
+
+	/* loop till creq is null or current_request is inactive */
+	creq = blk_dev[MAJOR_NR+ctlr].current_request;
+	if ((creq == NULL) || (creq->rq_status == RQ_INACTIVE))
+	{
+		/* nothing to do... restart processing and return */ 
+		start_io(h);
+		return;
+	}
+	if ((ctlr != (MAJOR(creq->rq_dev)-MAJOR_NR)) || (ctlr > nr_ctlr)
+		|| (h == NULL))
+	{
+#ifdef CCISS_DEBUG
+		printk(KERN_WARNING "cciss: doreq cmd of %d, %x at %p\n",
+			ctlr, creq->rq_dev, creq);
+#endif /* CCISS_DEBUG */
+		complete_buffers(creq->bh, 0);
+		return;
+	}
+	if (( c = cmd_alloc(h)) == NULL)
+	{
+		start_io(h);
+		return;
+	}
+	c->cmd_type = CMD_RWREQ;      
+	bh = c->bh = creq->bh;
+	
+	/* fill in the request */ 
+	log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; 
+	c->Header.ReplyQueue = 0;  // unused in simple mode
+	c->Header.Tag.lower = c->busaddr;  // use the physical address the cmd block for tag
+	c->Header.LUN.LogDev.VolId= hba[ctlr]->drv[log_unit].LunID;
+	c->Header.LUN.LogDev.Mode = 1;
+	c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
+	c->Request.Type.Type =  TYPE_CMD; // It is a command. 
+	c->Request.Type.Attribute = ATTR_SIMPLE; 
+	c->Request.Type.Direction = 
+		(creq->cmd == READ) ? XFER_READ: XFER_WRITE; 
+	c->Request.Timeout = 0; // Don't time out	
+	c->Request.CDB[0] = (creq->cmd == READ) ? CCISS_READ : CCISS_WRITE;
+	start_blk = hba[ctlr]->hd[MINOR(creq->rq_dev)].start_sect + creq->sector;
+	if (bh == NULL)
+		panic("cciss: bh== NULL?");
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
+		(int) creq->nr_sectors);	
+#endif /* CCISS_DEBUG */
+	seg = 0; 
+	lastdataend = NULL;
+	sect = 0;
+	while(bh)
+	{
+		sect += bh->b_size/512;
+		if (bh->b_size % 512)
+		{
+			printk(KERN_CRIT "cciss:  Oh Man.  %d+%d, size=%d\n", 
+				(int) creq->sector, sect, (int) bh->b_size);
+			panic("b_size 512 != 0\n");
+		}
+		if (bh->b_data == lastdataend)
+		{  // tack it on to the last segment 
+			c->SG[seg-1].Len +=bh->b_size;
+			lastdataend += bh->b_size;
+		} else
+		{
+			c->SG[seg].Len = bh->b_size;
+			temp64.val = (__u64) virt_to_bus(bh->b_data);
+			c->SG[seg].Addr.lower = temp64.val32.lower;
+			c->SG[seg].Addr.upper = temp64.val32.upper;
+			c->SG[0].Ext = 0;  // we are not chaining
+			lastdataend = bh->b_data + bh->b_size;
+			if( ++seg == MAXSGENTRIES)
+			{
+				break; 
+			}
+		}
+		bh = bh->b_reqnext;
+	}
+	/* track how many SG entries we are using */ 
+	if( seg > h->maxSG)
+		h->maxSG = seg; 
+
+	/* adjusting the remaining request, if any */ 
+	creq-> sector+= sect;
+	creq->nr_sectors -= sect; 
+
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", sect, seg);
+#endif /* CCISS_DEBUG */
+
+	c->Header.SGList = c->Header.SGTotal = seg;
+	c->Request.CDB[1]= 0;
+	c->Request.CDB[2]= (start_blk >> 24) & 0xff;	//MSB
+	c->Request.CDB[3]= (start_blk >> 16) & 0xff;
+	c->Request.CDB[4]= (start_blk >>  8) & 0xff;
+	c->Request.CDB[5]= start_blk & 0xff;
+	c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB
+	// c->Request.CDB[7]= (sect >> 16) & 0xff; 
+	c->Request.CDB[7]= (sect >>  8) & 0xff; 
+	c->Request.CDB[8]= sect & 0xff; 
+	c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
+
+	/* check to see if we going to complete the entire request */ 
+	/* if so, mark this request as Done and ready the next one */ 
+	if (creq->nr_sectors)
+	{
+#ifdef CCISS_DEBUG
+		printk(KERN_DEBUG "cciss: More to do on the same request %p %ld\n", 
+			creq, creq->nr_sectors);
+#endif /* CCISS_DEBUG */
+
+		creq->bh = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+	} else
+	{
+#ifdef CCISS_DEBUG
+		printk(KERN_DEBUG "cciss: Done with %p, queueing %p\n", creq, creq->next);
+#endif /* CCISS_DEBUG */
+
+		creq->rq_status = RQ_INACTIVE;
+		blk_dev[MAJOR_NR+ctlr].current_request = creq->next;
+		wake_up(&wait_for_request);
+	}
+	addQ(&(h->reqQ),c);
+	h->Qdepth++;
+	if(h->Qdepth > h->maxQsinceinit)
+		h->maxQsinceinit = h->Qdepth; 
+	start_io(h);
+}
+
+static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	ctlr_info_t *h = dev_id;
+	CommandList_struct *c;
+	unsigned long flags;
+	__u32 a, a1;
+
+
+	/* Is this interrupt for us? */
+	if ( h->access.intr_pending(h) == 0)
+		return;
+
+	/*
+	 * If there are completed commands in the completion queue,
+	 * we had better do something about it.
+	 */
+	spin_lock_irqsave(&io_request_lock, flags);
+	while( h->access.intr_pending(h))
+	{
+		while((a = h->access.command_completed(h)) != FIFO_EMPTY) 
+		{
+			a1 = a;
+			a &= ~3;
+			if ((c = h->cmpQ) == NULL)
+			{  
+				printk(KERN_WARNING "cpqarray: Completion of %08lx ignored\n", (unsigned long)a1);
+				continue;	
+			} 
+			while(c->busaddr != a) {
+				c = c->next;
+				if (c == h->cmpQ) 
+					break;
+			}
+			/*
+			 * If we've found the command, take it off the
+			 * completion Q and free it
+			 */
+			 if (c->busaddr == a) {
+				removeQ(&h->cmpQ, c);
+				if (c->cmd_type == CMD_RWREQ) {
+					complete_command(c, 0);
+					cmd_free(h, c);
+				} else if (c->cmd_type == CMD_IOCTL_PEND) {
+					c->cmd_type = CMD_IOCTL_DONE;
+				}
+				continue;
+			}
+		}
+	}
+	/*
+	 * See if we can queue up some more IO
+	 */
+	do_cciss_request(h->ctlr);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+/* 
+ *  We cannot read the structure directly, for portablity we must use 
+ *   the io functions.
+ *   This is for debug only. 
+ */
+#ifdef CCISS_DEBUG
+static void print_cfg_table( CfgTable_struct *tb)
+{
+	int i;
+	char temp_name[17];
+
+	printk("Controller Configuration information\n");
+	printk("------------------------------------\n");
+	for(i=0;i<4;i++)
+		temp_name[i] = readb(&(tb->Signature[i]));
+	temp_name[4]='\0';
+	printk("   Signature = %s\n", temp_name); 
+	printk("   Spec Number = %d\n", readl(&(tb->SpecValence)));
+	printk("   Transport methods supported = 0x%x\n", 
+				readl(&(tb-> TransportSupport)));
+	printk("   Transport methods active = 0x%x\n", 
+				readl(&(tb->TransportActive)));
+	printk("   Requested transport Method = 0x%x\n", 
+			readl(&(tb->HostWrite.TransportRequest)));
+	printk("   Coalese Interrupt Delay = 0x%x\n", 
+			readl(&(tb->HostWrite.CoalIntDelay)));
+	printk("   Coalese Interrupt Count = 0x%x\n", 
+			readl(&(tb->HostWrite.CoalIntCount)));
+	printk("   Max outstanding commands = 0x%d\n", 
+			readl(&(tb->CmdsOutMax)));
+	printk("   Bus Types = 0x%x\n", readl(&(tb-> BusTypes)));
+	for(i=0;i<16;i++)
+		temp_name[i] = readb(&(tb->ServerName[i]));
+	temp_name[16] = '\0';
+	printk("   Server Name = %s\n", temp_name);
+	printk("   Heartbeat Counter = 0x%x\n\n\n", 
+			readl(&(tb->HeartBeat)));
+}
+#endif /* CCISS_DEBUG */
+
+static int cciss_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn)
+{
+	ushort vendor_id, device_id, command;
+	unchar cache_line_size, latency_timer;
+	unchar irq, revision;
+	uint addr[6];
+	__u32 board_id;
+	struct pci_dev *pdev;
+
+	int i;
+
+	pdev = pci_find_slot(bus, device_fn);
+	vendor_id = pdev->vendor;
+	device_id = pdev->device;
+	irq = pdev->irq;
+
+	for(i=0; i<6; i++)
+		addr[i] = pdev->base_address[i];
+	(void) pcibios_read_config_word(bus, device_fn,
+					PCI_COMMAND,&command);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CLASS_REVISION,&revision);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_CACHE_LINE_SIZE, &cache_line_size);
+	(void) pcibios_read_config_byte(bus, device_fn,
+					PCI_LATENCY_TIMER, &latency_timer);
+
+	(void) pcibios_read_config_dword(bus, device_fn, 0x2c, &board_id);
+
+#ifdef CCISS_DEBUG
+	printk("vendor_id = %x\n", vendor_id);
+	printk("device_id = %x\n", device_id);
+	printk("command = %x\n", command);
+	for(i=0; i<6; i++)
+		printk("addr[%d] = %x\n", i, addr[i]);
+	printk("revision = %x\n", revision);
+	printk("irq = %x\n", irq);
+	printk("cache_line_size = %x\n", cache_line_size);
+	printk("latency_timer = %x\n", latency_timer);
+	printk("board_id = %x\n", board_id);
+#endif /* CCISS_DEBUG */ 
+
+	c->intr = irq;
+
+	/*
+	 * Memory base addr is first addr , the second points to the config
+         *   table
+	 */
+	c->paddr = addr[0];
+	c->vaddr = remap_pci_mem(c->paddr, 128);
+	c->cfgtable = (CfgTable_struct *) remap_pci_mem(addr[1], 
+						sizeof(CfgTable_struct));
+	c->board_id = board_id;
+
+#ifdef CCISS_DEBUG
+	print_cfg_table(c->cfgtable); 
+#endif /* CCISS_DEBUG */
+	for(i=0; i<NR_PRODUCTS; i++) {
+		if (board_id == products[i].board_id) {
+			c->product_name = products[i].product_name;
+			c->access = *(products[i].access);
+			break;
+		}
+	}
+	if (i == NR_PRODUCTS) {
+		printk(KERN_WARNING "cciss: Sorry, I don't know how"
+			" to access the Smart Array controller %08lx\n", 
+				(unsigned long)board_id);
+		return -1;
+	}
+#ifdef CCISS_DEBUG
+	printk("Trying to put board into Simple mode\n");
+#endif /* CCISS_DEBUG */ 
+	c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
+	/* Update the field, and then ring the doorbell */ 
+	writel( CFGTBL_Trans_Simple, 
+		&(c->cfgtable->HostWrite.TransportRequest));
+	writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
+
+	for(i=0;i<MAX_CONFIG_WAIT;i++)
+	{
+		if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
+			break;
+		/* delay and try again */
+		udelay(1000);
+	}	
+
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "I counter got to %d %x\n", i, readl(c->vaddr + SA5_DOORBELL));
+#endif /* CCISS_DEBUG */
+#ifdef CCISS_DEBUG
+	print_cfg_table(c->cfgtable);	
+#endif /* CCISS_DEBUG */ 
+
+	if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
+	{
+		printk(KERN_WARNING "cciss: unable to get board into"
+					" simple mode\n");
+		return -1;
+	}
+	return 0;
+
+}
+/* 
+ * Scans PCI space for any controllers that this driver can control. 
+ */
+static int cciss_pci_detect(void)
+{
+
+	int index;
+	unchar bus=0, dev_fn=0;
+	
+		for(index=0; ; index++) {
+			if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
+			 	PCI_DEVICE_ID_COMPAQ_CISS, 
+					index, &bus, &dev_fn))
+				break;
+			printk(KERN_DEBUG "cciss: Device %x has been found at %x %x\n",
+				PCI_DEVICE_ID_COMPAQ_CISS, bus, dev_fn);
+			if (index == 1000000) break;
+			if (nr_ctlr == 8) {
+				printk(KERN_WARNING "cciss: This driver"
+				" supports a maximum of 8 controllers.\n");
+				break;
+			}
+			hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+			if(hba[nr_ctlr]==NULL)
+			{
+				printk(KERN_ERR "cciss: out of memory.\n");
+				continue;
+			}
+			memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
+			if (cciss_pci_init(hba[nr_ctlr], bus, dev_fn) != 0)
+			{
+				kfree(hba[nr_ctlr]);
+				continue;
+			}
+			sprintf(hba[nr_ctlr]->devname, "cciss%d", nr_ctlr);
+			hba[nr_ctlr]->ctlr = nr_ctlr;
+			hba[nr_ctlr]->pci_bus = bus;
+			hba[nr_ctlr]->pci_dev_fn = dev_fn;
+			nr_ctlr++;
+
+		}
+	return nr_ctlr;
+
+}
+
+/* 
+ * Gets information about the local volumes attached to the controller. 
+ */ 
+static void cciss_getgeometry(int cntl_num)
+{
+	ReportLunData_struct *ld_buff;
+	ReadCapdata_struct *size_buff;
+	InquiryData_struct *inq_buff;
+	int return_code;
+	int i;
+	int listlength = 0;
+	int lunid = 0;
+	int block_size;
+	int total_size; 
+
+	ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
+	if (ld_buff == NULL)
+	{
+		printk(KERN_ERR "cciss: out of memory\n");
+		return;
+	}
+	memset(ld_buff, 0, sizeof(ReportLunData_struct));
+	size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
+        if (size_buff == NULL)
+        {
+                printk(KERN_ERR "cciss: out of memory\n");
+		kfree(ld_buff);
+                return;
+        }
+	inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+        if (inq_buff == NULL)
+        {
+                printk(KERN_ERR "cciss: out of memory\n");
+                kfree(ld_buff);
+		kfree(size_buff);
+                return;
+        }
+	/* Get the firmware version */ 
+	return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, 
+		sizeof(InquiryData_struct), 0, 0 ,0 );
+	if (return_code == IO_OK)
+	{
+		hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
+		hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33];
+		hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34];
+		hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35];
+	} else /* send command failed */
+	{
+		printk(KERN_WARNING "cciss: unable to determine firmware"
+			" version of controller\n");
+	}
+	/* Get the number of logical volumes */ 
+	return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, 
+			sizeof(ReportLunData_struct), 0, 0, 0 );
+
+	if( return_code == IO_OK)
+	{
+#ifdef CCISS_DEBUG
+		printk("LUN Data\n--------------------------\n");
+#endif /* CCISS_DEBUG */ 
+
+		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+		listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;	
+		listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+	} else /* reading number of logical volumes failed */
+	{
+		printk(KERN_WARNING "cciss: report logical volume"
+			" command failed\n");
+		listlength = 0;
+	}
+	hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
+	if (hba[cntl_num]->num_luns > CISS_MAX_LUN)
+	{
+		printk(KERN_ERR "ciss:  only %d number of logical volumes supported\n",
+			CISS_MAX_LUN);
+		hba[cntl_num]->num_luns = CISS_MAX_LUN;
+	}
+#ifdef CCISS_DEBUG
+	printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
+		ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
+		ld_buff->LUNListLength[3],  hba[cntl_num]->num_luns);
+#endif /* CCISS_DEBUG */
+	for(i=0; i<  hba[cntl_num]->num_luns ; i++)
+	{
+	  	lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24;
+        	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16;
+        	lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8;
+        	lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+		hba[cntl_num]->drv[i].LunID = lunid;
+
+#ifdef CCISS_DEBUG
+	  	printk(KERN_DEBUG "LUN[%d]:  %x %x %x %x = %x\n", i, 
+		ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], 
+		ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID);
+#endif /* CCISS_DEBUG */
+
+	  	memset(size_buff, 0, sizeof(ReadCapdata_struct));
+	  	return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, 
+				sizeof( ReadCapdata_struct), 1, i, 0 );
+	  	if (return_code == IO_OK)
+		{
+			total_size = (0xff & 
+				(unsigned int)(size_buff->total_size[0])) << 24;
+			total_size |= (0xff & 
+				(unsigned int)(size_buff->total_size[1])) << 16;
+			total_size |= (0xff & 
+				(unsigned int)(size_buff->total_size[2])) << 8;
+			total_size |= (0xff & (unsigned int)
+				(size_buff->total_size[3])); 
+			total_size++; // command returns highest block address
+
+			block_size = (0xff & 
+				(unsigned int)(size_buff->block_size[0])) << 24;
+                	block_size |= (0xff & 
+				(unsigned int)(size_buff->block_size[1])) << 16;
+                	block_size |= (0xff & 
+				(unsigned int)(size_buff->block_size[2])) << 8;
+                	block_size |= (0xff & 
+				(unsigned int)(size_buff->block_size[3]));
+		} else /* read capacity command failed */ 
+		{
+			printk(KERN_WARNING "cciss: read capacity failed\n");
+			total_size = block_size = 0; 
+		}	
+		printk("      blocks= %d block_size= %d\n", total_size,
+					block_size);
+
+		/* Execute the command to read the disk geometry */
+		memset(inq_buff, 0, sizeof(InquiryData_struct));
+		return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
+                	sizeof(InquiryData_struct), 1, i ,0xC1 );
+	  	if (return_code == IO_OK)
+		{
+			if(inq_buff->data_byte[8] == 0xFF)
+			{
+			   printk(KERN_WARNING "cciss: reading geometry failed, volume does not support reading geometry\n");
+
+                           hba[cntl_num]->drv[i].block_size = block_size;
+                           hba[cntl_num]->drv[i].nr_blocks = total_size;
+                           hba[cntl_num]->drv[i].heads = 255;
+                           hba[cntl_num]->drv[i].sectors = 32; // Sectors per track
+                           hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;                	} else
+			{
+
+		 	   hba[cntl_num]->drv[i].block_size = block_size;
+                           hba[cntl_num]->drv[i].nr_blocks = total_size;
+                           hba[cntl_num]->drv[i].heads = 
+					inq_buff->data_byte[6]; 
+                           hba[cntl_num]->drv[i].sectors = 
+					inq_buff->data_byte[7]; 
+			   hba[cntl_num]->drv[i].cylinders = 
+					(inq_buff->data_byte[4] & 0xff) << 8;
+			   hba[cntl_num]->drv[i].cylinders += 
+                                        inq_buff->data_byte[5];
+			}
+		}
+		else /* Get geometry failed */
+		{
+			printk(KERN_WARNING "cciss: reading geometry failed, continuing with default geometry\n"); 
+
+			hba[cntl_num]->drv[i].block_size = block_size;
+			hba[cntl_num]->drv[i].nr_blocks = total_size;
+			hba[cntl_num]->drv[i].heads = 255;
+			hba[cntl_num]->drv[i].sectors = 32; // Sectors per track 
+			hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32;
+		}
+		printk(KERN_INFO "      heads= %d, sectors= %d, cylinders= %d\n\n",
+			hba[cntl_num]->drv[i].heads, 
+			hba[cntl_num]->drv[i].sectors,
+			hba[cntl_num]->drv[i].cylinders);
+
+	}
+	kfree(ld_buff);
+	kfree(size_buff);
+}	
+
+/*
+ *  This is it.  Find all the controllers and register them.  I really hate
+ *  stealing all these major device numbers.
+ *  returns the number of block devices registered.
+ */
+int cciss_init(void)
+{
+	int num_cntlrs_reg = 0;
+	int i;
+
+	void (*request_fns[MAX_CTLR])(void) = {
+                do_cciss_request0, do_cciss_request1,
+                do_cciss_request2, do_cciss_request3,
+                do_cciss_request4, do_cciss_request5,
+                do_cciss_request6, do_cciss_request7,
+        };
+
+	/* detect controllers */
+	cciss_pci_detect();
+
+	if (nr_ctlr == 0)
+		return(num_cntlrs_reg);
+
+	printk(KERN_INFO DRIVER_NAME "\n");
+	printk(KERN_INFO "Found %d controller(s)\n", nr_ctlr);
+	for(i=0;i<nr_ctlr;i++)
+	{
+		if( register_blkdev(MAJOR_NR+i, hba[i]->devname, &cciss_fops))
+		{
+			printk(KERN_ERR "cciss:  Unable to get major number "
+				"%d for %s\n", MAJOR_NR+i, hba[i]->devname);
+			continue;
+		}
+		/* make sure the board interrupts are off */
+		hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
+		if( request_irq(hba[i]->intr, do_cciss_intr, SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i]))
+		{
+			printk(KERN_ERR "ciss: Unable to get irq %d for %s\n",
+				hba[i]->intr, hba[i]->devname);
+			unregister_blkdev( MAJOR_NR+i, hba[i]->devname);
+			continue;
+		}
+		num_cntlrs_reg++;
+		hba[i]->cmd_pool_bits = (__u32*)kmalloc(
+                                ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
+		hba[i]->cmd_pool = (CommandList_struct *)kmalloc(
+                                NR_CMDS * sizeof(CommandList_struct), 
+					GFP_KERNEL);
+		hba[i]->errinfo_pool = (ErrorInfo_struct *)kmalloc(
+                                NR_CMDS * sizeof( ErrorInfo_struct), 
+					GFP_KERNEL);
+		if((hba[i]->cmd_pool_bits == NULL) 
+			|| (hba[i]->cmd_pool == NULL)
+			|| (hba[i]->errinfo_pool == NULL))
+                {
+                        nr_ctlr = i;
+			if(hba[i]->cmd_pool_bits)
+                                kfree(hba[i]->cmd_pool_bits);
+                        if(hba[i]->cmd_pool)
+                                kfree(hba[i]->cmd_pool);
+			if(hba[i]->errinfo_pool)
+				kfree(hba[i]->errinfo_pool);
+                        free_irq(hba[i]->intr, hba[i]);
+                        unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+                        num_cntlrs_reg--;
+                        printk( KERN_ERR "cciss: out of memory");
+			return(num_cntlrs_reg);
+		}
+
+		/* command and error info recs zeroed out before 
+			they are used */
+                memset(hba[i]->cmd_pool_bits, 0, 
+			((NR_CMDS+31)/32)*sizeof(__u32));
+
+#ifdef CCISS_DEBUG	
+		printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i);
+#endif /* CCISS_DEBUG */
+
+		cciss_getgeometry(i);
+
+		/* Turn the interrupts on so we can service requests */
+		hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON);
+
+		cciss_procinit(i);
+		/* Fill in the gendisk data */ 	
+		hba[i]->gendisk.major = MAJOR_NR + i;
+		hba[i]->gendisk.major_name = "cciss";
+		hba[i]->gendisk.minor_shift = NWD_SHIFT;
+		hba[i]->gendisk.max_p = MAX_PART;
+		hba[i]->gendisk.max_nr = NWD;
+		hba[i]->gendisk.init = cciss_geninit;
+		hba[i]->gendisk.part = hba[i]->hd;
+		hba[i]->gendisk.sizes = hba[i]->sizes;
+		hba[i]->gendisk.nr_real = hba[i]->num_luns;
+
+		/* fill in the other Kernel structs */ 
+		blk_dev[MAJOR_NR+i].request_fn = request_fns[i];
+		blksize_size[MAJOR_NR+i] = hba[i]->blocksizes;
+		hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes;
+		read_ahead[MAJOR_NR+i] = READ_AHEAD;
+
+		/* Get on the disk list */ 
+		hba[i]->gendisk.next = gendisk_head;
+		gendisk_head = &(hba[i]->gendisk); 
+	}
+	return(nr_ctlr);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+
+/* This is a bit of a hack... */
+int init_module(void)
+{
+	int i,j;
+
+	if (cciss_init() == 0) /* all the block dev numbers already used */
+		return -EIO;	  /* or no controllers were found */
+	for(i=0; i<nr_ctlr; i++)
+	{
+		cciss_geninit(&(hba[i]->gendisk));
+		for(j=0; j<NWD; j++)
+		{
+			if(hba[i]->sizes[j<<NWD_SHIFT])
+				resetup_one_dev(&(hba[i]->gendisk), j);
+		}
+	}
+	return 0;
+}
+void cleanup_module(void)
+{
+	int i;
+	struct gendisk *g;
+
+	for(i=0; i<nr_ctlr; i++)
+	{
+		/* Turn board interrupts off */ 
+		hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
+		free_irq(hba[i]->intr, hba[i]);
+		iounmap((void*)hba[i]->vaddr);
+		unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
+		remove_proc_entry(hba[i]->devname, proc_cciss);	
+
+		/* remove it from the disk list */ 
+		if (gendisk_head == &(hba[i]->gendisk))
+		{
+			gendisk_head = hba[i]->gendisk.next;
+		} else 
+		{
+			for(g=gendisk_head; g ; g=g->next)
+			{
+				if(g->next == &(hba[i]->gendisk))
+				{
+					g->next = hba[i]->gendisk.next;
+				}
+			}
+		}
+		remove_proc_entry("cciss", &proc_root);
+		kfree(hba[i]->cmd_pool);
+		kfree(hba[i]->errinfo_pool);
+                kfree(hba[i]->cmd_pool_bits);
+		kfree(hba[i]);
+	}
+}
+
+#endif /* MODULE */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/cciss.h linux.18p8/drivers/block/cciss.h
--- linux.vanilla/drivers/block/cciss.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/block/cciss.h	Sun Sep  3 00:10:45 2000
@@ -0,0 +1,201 @@
+#ifndef CCISS_H
+#define CCISS_H
+
+#include <linux/genhd.h>
+
+#include "cciss_cmd.h"
+
+
+#define NWD		16
+#define NWD_SHIFT	4
+#define MAX_PART	16
+
+#define IO_OK		0
+#define IO_ERROR	1
+
+#define MAJOR_NR COMPAQ_CISS_MAJOR 
+
+struct ctlr_info;
+typedef struct ctlr_info ctlr_info_t;
+
+struct access_method {
+	void (*submit_command)(ctlr_info_t *h, CommandList_struct *c);
+	void (*set_intr_mask)(ctlr_info_t *h, unsigned long val);
+	unsigned long (*fifo_full)(ctlr_info_t *h);
+	unsigned long (*intr_pending)(ctlr_info_t *h);
+	unsigned long (*command_completed)(ctlr_info_t *h);
+};
+typedef struct _drive_info_struct
+{
+ 	__u32   LunID;	
+	int 	usage_count;
+	int 	nr_blocks;
+	int	block_size;
+	int 	heads;
+	int	sectors;
+	int 	cylinders;
+} drive_info_struct;
+
+struct ctlr_info 
+{
+	int	ctlr;
+	char	devname[8];
+	char    *product_name;
+	char	firm_ver[4]; // Firmware version 
+	unchar  pci_bus;
+        unchar  pci_dev_fn;
+	__u32	board_id;
+	__u32	vaddr;
+	__u32	paddr;	
+	CfgTable_struct *cfgtable;
+	int	intr;
+
+	int 	max_commands;
+	int	commands_outstanding;
+	int 	max_outstanding; /* Debug */ 
+	int	num_luns;
+	int	usage_count;  /* number of opens all all minor devices */
+
+	// information about each logical volume
+	drive_info_struct drv[CISS_MAX_LUN];
+
+	struct access_method access;
+
+	/* queue and queue Info */ 
+	CommandList_struct *reqQ;
+	CommandList_struct  *cmpQ;
+	unsigned int Qdepth;
+	unsigned int maxQsinceinit;
+	unsigned int maxSG;
+
+	//* pointers to command and error info pool */ 
+	CommandList_struct 	*cmd_pool;
+	ErrorInfo_struct 	*errinfo_pool;
+        __u32   		*cmd_pool_bits;
+	int			nr_allocs;
+	int			nr_frees; 
+
+	// Disk structures we need to pass back
+	struct gendisk   gendisk;
+	   // indexed by minor numbers
+	struct hd_struct hd[256];
+	int              sizes[256];
+	int              blocksizes[256];
+	int              hardsizes[256];
+};
+
+/*  Defining the diffent access_menthods */
+/*
+ * Memory mapped FIFO interface (SMART 53xx cards)
+ */
+#define SA5_DOORBELL	0x20
+#define SA5_REQUEST_PORT_OFFSET	0x40
+#define SA5_REPLY_INTR_MASK_OFFSET	0x34
+#define SA5_REPLY_PORT_OFFSET		0x44
+#define SA5_INTR_STATUS		0x30
+
+#define SA5_INTR_OFF		0x08
+#define SA5_INTR_PENDING	0x08
+#define FIFO_EMPTY		0xffffffff	
+
+#define  CISS_ERROR_BIT		0x02
+
+#define CCISS_INTR_ON 	1 
+#define CCISS_INTR_OFF	0
+/* 
+	Send the command to the hardware 
+*/
+static void SA5_submit_command( ctlr_info_t *h, CommandList_struct *c) 
+{
+#ifdef CCISS_DEBUG
+	 printk("Sending %x - down to controller\n", c->busaddr );
+#endif /* CCISS_DEBUG */ 
+         writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
+	 h->commands_outstanding++;
+	 if ( h->commands_outstanding > h->max_outstanding)
+		h->max_outstanding = h->commands_outstanding;
+}
+
+/*  
+ *  This card is the oposite of the other cards.  
+ *   0 turns interrupts on... 
+ *   0x08 turns them off... 
+ */
+static void SA5_intr_mask(ctlr_info_t *h, unsigned long val)
+{
+	if (val) 
+	{ /* Turn interrupts on */
+		writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+	} else /* Turn them off */
+	{
+        	writel( SA5_INTR_OFF, 
+			h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+	}
+}
+/*
+ *  Returns true if fifo is full.  
+ * 
+ */ 
+static unsigned long SA5_fifo_full(ctlr_info_t *h)
+{
+	if( h->commands_outstanding >= h->max_commands)
+		return(1);
+	else 
+		return(0);
+
+}
+/* 
+ *   returns value read from hardware. 
+ *     returns FIFO_EMPTY if there is nothing to read 
+ */ 
+static unsigned long SA5_completed(ctlr_info_t *h)
+{
+	unsigned long register_value 
+		= readl(h->vaddr + SA5_REPLY_PORT_OFFSET);
+	if(register_value != FIFO_EMPTY)
+	{
+		h->commands_outstanding--;
+#ifdef CCISS_DEBUG
+		printk("cciss:  Read %lx back from board\n", register_value);
+#endif /* CCISS_DEBUG */ 
+	} 
+#ifdef CCISS_DEBUG
+	else
+	{
+		printk("cciss:  FIFO Empty read\n");
+	}
+#endif 
+	return ( register_value); 
+
+}
+/*
+ *	Returns true if an interrupt is pending.. 
+ */
+static unsigned long SA5_intr_pending(ctlr_info_t *h)
+{
+	unsigned long register_value  = 
+		readl(h->vaddr + SA5_INTR_STATUS);
+#ifdef CCISS_DEBUG
+	printk("cciss: intr_pending %lx\n", register_value);
+#endif  /* CCISS_DEBUG */
+	if( register_value &  SA5_INTR_PENDING) 
+		return  1;	
+	return 0 ;
+}
+
+
+static struct access_method SA5_access = {
+	SA5_submit_command,
+	SA5_intr_mask,
+	SA5_fifo_full,
+	SA5_intr_pending,
+	SA5_completed,
+};
+
+struct board_type {
+	__u32	board_id;
+	char	*product_name;
+	struct access_method *access;
+};
+#endif /* CCISS_H */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/cciss_cmd.h linux.18p8/drivers/block/cciss_cmd.h
--- linux.vanilla/drivers/block/cciss_cmd.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/block/cciss_cmd.h	Fri Sep  1 13:32:19 2000
@@ -0,0 +1,254 @@
+#ifndef CCISS_CMD_H
+#define CCISS_CMD_H
+//###########################################################################
+//DEFINES
+//###########################################################################
+#define CISS_VERSION "1.00"
+
+//general boundary defintions
+#define SENSEINFOBYTES          32//note that this value may vary between host implementations
+#define MAXSGENTRIES            31
+#define MAXREPLYQS              256
+
+//Command Status value
+#define CMD_SUCCESS             0x0000
+#define CMD_TARGET_STATUS       0x0001
+#define CMD_DATA_UNDERRUN       0x0002
+#define CMD_DATA_OVERRUN        0x0003
+#define CMD_INVALID             0x0004
+#define CMD_PROTOCOL_ERR        0x0005
+#define CMD_HARDWARE_ERR        0x0006
+#define CMD_CONNECTION_LOST     0x0007
+#define CMD_ABORTED             0x0008
+#define CMD_ABORT_FAILED        0x0009
+#define CMD_UNSOLICITED_ABORT   0x000A
+#define CMD_TIMEOUT             0x000B
+#define CMD_UNABORTABLE		0x000C
+
+//transfer direction
+#define XFER_NONE               0x00
+#define XFER_WRITE              0x01
+#define XFER_READ               0x02
+#define XFER_RSVD               0x03
+
+//task attribute
+#define ATTR_UNTAGGED           0x00
+#define ATTR_SIMPLE             0x04
+#define ATTR_HEADOFQUEUE        0x05
+#define ATTR_ORDERED            0x06
+#define ATTR_ACA                0x07
+
+//cdb type
+#define TYPE_CMD				0x00
+#define TYPE_MSG				0x01
+
+//config space register offsets
+#define CFG_VENDORID            0x00
+#define CFG_DEVICEID            0x02
+#define CFG_I2OBAR              0x10
+#define CFG_MEM1BAR             0x14
+
+//i2o space register offsets
+#define I2O_IBDB_SET            0x20
+#define I2O_IBDB_CLEAR          0x70
+#define I2O_INT_STATUS          0x30
+#define I2O_INT_MASK            0x34
+#define I2O_IBPOST_Q            0x40
+#define I2O_OBPOST_Q            0x44
+
+//Configuration Table
+#define CFGTBL_ChangeReq        0x00000001l
+#define CFGTBL_AccCmds          0x00000001l
+
+#define CFGTBL_Trans_Simple     0x00000002l
+
+#define CFGTBL_BusType_Ultra2   0x00000001l
+#define CFGTBL_BusType_Ultra3   0x00000002l
+#define CFGTBL_BusType_Fibre1G  0x00000100l
+#define CFGTBL_BusType_Fibre2G  0x00000200l
+typedef struct _vals32
+{
+        __u32   lower;
+        __u32   upper;
+} vals32;
+
+typedef union _u64bit
+{
+   vals32	val32;
+   __u64	val;
+} u64bit;
+
+// Type defs used in the following structs
+#define BYTE __u8
+#define WORD __u16
+#define HWORD __u16
+#define DWORD __u32
+#define QWORD vals32 
+
+//###########################################################################
+//STRUCTURES
+//###########################################################################
+#define CISS_MAX_LUN	16	
+// SCSI-3 Cmmands 
+
+#pragma pack(1)	
+
+#define CISS_INQUIRY 0x12
+//Date returned
+typedef struct _InquiryData_struct
+{
+  BYTE data_byte[36];
+} InquiryData_struct;
+
+#define CISS_REPORT_LOG 0xc2    /* Report Logical LUNs */
+// Data returned
+typedef struct _ReportLUNdata_struct
+{
+  BYTE LUNListLength[4];
+  DWORD reserved;
+  BYTE LUN[CISS_MAX_LUN][8];
+} ReportLunData_struct;
+
+#define CCISS_READ_CAPACITY 0x25 /* Read Capacity */ 
+typedef struct _ReadCapdata_struct
+{
+  BYTE total_size[4];	// Total size in blocks
+  BYTE block_size[4];	// Size of blocks in bytes
+} ReadCapdata_struct;
+
+// 12 byte commands not implemented in firmware yet. 
+// #define CCISS_READ 	0xa8	// Read(12)
+// #define CCISS_WRITE	0xaa	// Write(12)
+ #define CCISS_READ   0x28    // Read(10)
+ #define CCISS_WRITE  0x2a    // Write(10)
+
+//Command List Structure
+typedef union _SCSI3Addr_struct {
+   struct {
+    BYTE Bus:6;
+    BYTE Mode:2;        // b00
+    BYTE Dev;
+  } PeripDev;
+   struct {
+    BYTE DevMSB:6;
+    BYTE Mode:2;        // b01
+    BYTE DevLSB;
+  } LogDev;
+   struct {
+    BYTE Targ:6;
+    BYTE Mode:2;        // b10
+    BYTE Dev:5;
+    BYTE Bus:3;
+  } LogUnit;
+} SCSI3Addr_struct;
+
+typedef struct _PhysDevAddr_struct {
+  DWORD             TargetId:24;
+  DWORD             Bus:6;
+  DWORD             Mode:2;
+  SCSI3Addr_struct  Target[2]; //2 level target device addr
+} PhysDevAddr_struct;
+  
+typedef struct _LogDevAddr_struct {
+  DWORD            VolId:30;
+  DWORD            Mode:2;
+  BYTE             reserved[4];
+} LogDevAddr_struct;
+
+typedef union _LUNAddr_struct {
+  BYTE               LunAddrBytes[8];
+  SCSI3Addr_struct   SCSI3Lun[4];
+  PhysDevAddr_struct PhysDev;
+  LogDevAddr_struct  LogDev;
+} LUNAddr_struct;
+
+typedef struct _CommandListHeader_struct {
+  BYTE              ReplyQueue;
+  BYTE              SGList;
+  HWORD             SGTotal;
+  QWORD             Tag;
+  LUNAddr_struct    LUN;
+} CommandListHeader_struct;
+typedef struct _RequestBlock_struct {
+  BYTE   CDBLen;
+  struct {
+    BYTE Type:3;
+    BYTE Attribute:3;
+    BYTE Direction:2;
+  } Type;
+  HWORD  Timeout;
+  BYTE   CDB[16];
+} RequestBlock_struct;
+typedef struct _ErrDescriptor_struct {
+  QWORD  Addr;
+  DWORD  Len;
+} ErrDescriptor_struct;
+typedef struct _SGDescriptor_struct {
+  QWORD  Addr;
+  DWORD  Len;
+  DWORD  Ext;
+} SGDescriptor_struct;
+
+typedef union _MoreErrInfo_struct{
+  struct {
+    BYTE  Reserved[3];
+    BYTE  Type;
+    DWORD ErrorInfo;
+  }Common_Info;
+  struct{
+    BYTE  Reserved[2];
+    BYTE  offense_size;//size of offending entry
+    BYTE  offense_num; //byte # of offense 0-base
+    DWORD offense_value;
+  }Invalid_Cmd;
+}MoreErrInfo_struct;
+typedef struct _ErrorInfo_struct {
+  BYTE               ScsiStatus;
+  BYTE               SenseLen;
+  HWORD              CommandStatus;
+  DWORD              ResidualCnt;
+  MoreErrInfo_struct MoreErrInfo;
+  BYTE               SenseInfo[SENSEINFOBYTES];
+} ErrorInfo_struct;
+
+/* Command types */
+#define CMD_RWREQ       0x00
+#define CMD_IOCTL_PEND  0x01
+#define CMD_IOCTL_DONE  0x02
+
+typedef struct _CommandList_struct {
+  CommandListHeader_struct Header;
+  RequestBlock_struct      Request;
+  ErrDescriptor_struct     ErrDesc;
+  SGDescriptor_struct      SG[MAXSGENTRIES];
+	/* information associated with the command */ 
+  __u32			   busaddr; /* physical addres of this record */
+  ErrorInfo_struct * 	   err_info; /* pointer to the allocated mem */ 
+  int			   cmd_type; 
+  struct _CommandList_struct *prev;
+  struct _CommandList_struct *next;
+  struct buffer_head *	   bh;
+} CommandList_struct;
+
+//Configuration Table Structure
+typedef struct _HostWrite_struct {
+  DWORD TransportRequest;
+  DWORD Reserved;
+  DWORD CoalIntDelay;
+  DWORD CoalIntCount;
+} HostWrite_struct;
+
+typedef struct _CfgTable_struct {
+  BYTE             Signature[4];
+  DWORD            SpecValence;
+  DWORD            TransportSupport;
+  DWORD            TransportActive;
+  HostWrite_struct HostWrite;
+  DWORD            CmdsOutMax;
+  DWORD            BusTypes;
+  DWORD            Reserved; 
+  BYTE             ServerName[16];
+  DWORD            HeartBeat;
+} CfgTable_struct;
+#pragma pack()	 
+#endif // CCISS_CMD_H
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/cpqarray.c linux.18p8/drivers/block/cpqarray.c
--- linux.vanilla/drivers/block/cpqarray.c	Sat Sep  9 18:42:34 2000
+++ linux.18p8/drivers/block/cpqarray.c	Wed Sep 13 16:20:43 2000
@@ -41,8 +41,14 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.9)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,9)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.10)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,10)
+
+/* Embedded module documentation macros - see modules.h */
+/* Original author Chris Frantz - Compaq Computer Corporation */
+MODULE_AUTHOR("Compaq Computer Corporation");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers");
+
 #define MAJOR_NR COMPAQ_SMART2_MAJOR
 #include <linux/blk.h>
 #include <linux/blkdev.h>
@@ -617,6 +623,8 @@
 
 	int i;
 
+	c->pci_bus = bus;
+	c->pci_dev_fn = device_fn;
 	pdev = pci_find_slot(bus, device_fn);
 	vendor_id = pdev->vendor;
 	device_id = pdev->device;
@@ -663,6 +671,7 @@
 	c->vaddr = remap_pci_mem(c->paddr, 128);
 	c->board_id = board_id;
 
+	
 	for(i=0; i<NR_PRODUCTS; i++) {
 		if (board_id == products[i].board_id) {
 			c->product_name = products[i].product_name;
@@ -752,6 +761,8 @@
 		hba[nr_ctlr]->access = *(products[j].access);
 		hba[nr_ctlr]->ctlr = nr_ctlr;
 		hba[nr_ctlr]->board_id = board_id;
+		hba[nr_ctlr]->pci_bus = 0;  /* not PCI */
+		hba[nr_ctlr]->pci_dev_fn = 0; /* not PCI */
 
 DBGINFO(
 	printk("i = %d, j = %d\n", i, j);
@@ -1174,7 +1185,20 @@
 		if (!arg) return -EINVAL;
 		put_user(DRIVER_VERSION, (unsigned long*)arg);
 		return 0;
+	case IDAGETPCIINFO:
+	{
+		
+		ida_pci_info_struct pciinfo;
 
+		if (!arg) return -EINVAL;
+		pciinfo.bus = hba[ctlr]->pci_bus;
+		pciinfo.dev_fn = hba[ctlr]->pci_dev_fn;
+		pciinfo.board_id = hba[ctlr]->board_id;
+		copy_to_user_ret((void *) arg, &pciinfo,  
+			sizeof( ida_pci_info_struct),  -EFAULT);
+		return(0);
+	}	
+	
 	RO_IOCTLS(inode->i_rdev, arg);
 
 	default:
@@ -1358,6 +1382,8 @@
 	ctlr_info_t *info_p = hba[ctlr];
 
 	c = cmd_alloc(info_p);
+	if (!c)
+		return IO_ERROR;
 	c->ctlr = ctlr;
 	c->hdr.unit = log_unit;
 	c->hdr.prio = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/cpqarray.h linux.18p8/drivers/block/cpqarray.h
--- linux.vanilla/drivers/block/cpqarray.h	Fri Apr 21 23:13:37 2000
+++ linux.18p8/drivers/block/cpqarray.h	Fri Sep 15 15:04:34 2000
@@ -87,6 +87,8 @@
 	int	log_drives;
 	int	phys_drives;
 
+	unsigned char  pci_bus;     /* 0 if EISA */
+        unsigned char  pci_dev_fn;  /* 0 if EISA */
 	__u32	board_id;
 	char	*product_name;	
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/floppy.c linux.18p8/drivers/block/floppy.c
--- linux.vanilla/drivers/block/floppy.c	Fri Apr 21 12:45:50 2000
+++ linux.18p8/drivers/block/floppy.c	Thu Aug 31 14:46:22 2000
@@ -2314,6 +2314,13 @@
 {
 	int nr_sectors, ssize, eoc, heads;
 
+	if (R_HEAD >= 2) {
+	    /* some Toshiba floppy controllers occasionnally seem to
+	     * return bogus interrupts after read/write operations, which
+	     * can be recognized by a bad head number (>= 2) */
+	     return;
+	}  
+
 	if (!DRS->first_read_date)
 		DRS->first_read_date = jiffies;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/genhd.c linux.18p8/drivers/block/genhd.c
--- linux.vanilla/drivers/block/genhd.c	Sat Sep  9 18:42:34 2000
+++ linux.18p8/drivers/block/genhd.c	Fri Sep  1 13:32:19 2000
@@ -131,6 +131,10 @@
 			return buf;
 		}
 	}
+	if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <=
+            COMPAQ_CISS_MAJOR+7) {
+          return raid_name (hd, minor, COMPAQ_CISS_MAJOR, buf);
+        }
 	if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <=
             COMPAQ_SMART2_MAJOR+7) {
           return raid_name (hd, minor, COMPAQ_SMART2_MAJOR, buf);
@@ -1622,6 +1626,9 @@
 {
 	extern void console_map_init(void);
 	extern void cpqarray_init(void);
+#ifdef CONFIG_BLK_CPQ_CISS_DA
+	extern int  cciss_init(void);
+#endif 
 #ifdef CONFIG_PARPORT
 	extern int parport_init(void);
 #endif
@@ -1654,6 +1661,9 @@
 #endif
 #ifdef CONFIG_BLK_CPQ_DA
 	cpqarray_init();
+#endif
+#ifdef CONFIG_BLK_CPQ_CISS_DA
+        cciss_init();
 #endif
 #ifdef CONFIG_NET
 	net_dev_init();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/ida_ioctl.h linux.18p8/drivers/block/ida_ioctl.h
--- linux.vanilla/drivers/block/ida_ioctl.h	Fri Apr 21 23:13:37 2000
+++ linux.18p8/drivers/block/ida_ioctl.h	Fri Sep 15 15:04:34 2000
@@ -33,7 +33,14 @@
 #define IDAGETCTLRSIG		0x29293030
 #define IDAREVALIDATEVOLS	0x30303131
 #define IDADRIVERVERSION	0x31313232
+#define IDAGETPCIINFO		0x32323333
 
+typedef struct _ida_pci_info_struct
+{
+	unsigned char 	bus;
+	unsigned char 	dev_fn;
+	__u32 		board_id;
+} ida_pci_info_struct;
 /*
  * Normally, the ioctl determines the logical unit for this command by
  * the major,minor number of the fd passed to ioctl.  If you need to send
@@ -60,7 +67,7 @@
 
 	union ctlr_cmds {
 		drv_info_t		drv;
-		unsigned char		buf[512];
+		unsigned char		buf[1024];
 
 		id_ctlr_t		id_ctlr;
 		drv_param_t		drv_param;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/ide-cd.c linux.18p8/drivers/block/ide-cd.c
--- linux.vanilla/drivers/block/ide-cd.c	Sat Sep  9 18:42:34 2000
+++ linux.18p8/drivers/block/ide-cd.c	Fri Sep 15 12:47:12 2000
@@ -1827,6 +1827,20 @@
 	return cdrom_queue_packet_command(drive, &pc);
 }
 
+static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end)
+{
+	struct request_sense sense;
+	struct packet_command pc;
+
+	memset(&pc, 0, sizeof (pc));
+	pc.sense = &sense;
+
+	pc.c[0] = GPCMD_PLAY_AUDIO_10;
+	put_unaligned(cpu_to_be32(lba_start), (unsigned int *) &pc.c[2]);
+	put_unaligned(cpu_to_be16(lba_end - lba_start), (unsigned int *) &pc.c[7]);
+
+	return cdrom_queue_packet_command(drive, &pc);
+}
 
 static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
 				struct atapi_toc_entry **ent)
@@ -1932,6 +1946,34 @@
 	struct cdrom_info *info = drive->driver_data;
 
 	switch (cmd) {
+	/*
+	 * emulate PLAY_AUDIO_TI command with PLAY_AUDIO_10, since
+	 * atapi doesn't support it
+	 */
+	case CDROMPLAYTRKIND: {
+		int stat, lba_start, lba_end;
+		struct cdrom_ti *ti = (struct cdrom_ti *)arg;
+		struct atapi_toc_entry *first_toc, *last_toc;
+
+		stat = cdrom_get_toc_entry(drive, ti->cdti_trk0, &first_toc);
+		if (stat)
+			return stat;
+
+		stat = cdrom_get_toc_entry(drive, ti->cdti_trk1, &last_toc);
+		if (stat)
+			return stat;
+
+		if (ti->cdti_trk1 != CDROM_LEADOUT)
+			++last_toc;
+		lba_start = first_toc->addr.lba;
+		lba_end   = last_toc->addr.lba;
+
+		if (lba_end <= lba_start)
+			return -EINVAL;
+
+		return cdrom_play_audio(drive, lba_start, lba_end);
+	}
+
 	case CDROMREADTOCHDR: {
 		int stat;
 		struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
@@ -2275,7 +2317,7 @@
 		CDROM_CONFIG_FLAGS (drive)->dvd_ram = 1;
 	if (cap.audio_play)
 		CDROM_CONFIG_FLAGS (drive)->audio_play = 1;
-	if (cap.mechtype == 0)
+	if (cap.mechtype == mechtype_caddy || cap.mechtype == mechtype_popup)
 		CDROM_CONFIG_FLAGS (drive)->close_tray = 0;
 
 #if ! STANDARD_ATAPI
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/ide-dma.c linux.18p8/drivers/block/ide-dma.c
--- linux.vanilla/drivers/block/ide-dma.c	Sun Jun 11 21:44:12 2000
+++ linux.18p8/drivers/block/ide-dma.c	Mon Sep 11 18:06:33 2000
@@ -433,6 +433,12 @@
 			request_region(dma_base+16, extra, name);
 		dma_base += hwif->channel ? 8 : 0;
 		hwif->dma_extra = extra;
+		
+		/* ====== ALI M5229 ================================*/
+		if( hwif->pci_dev->device == PCI_DEVICE_ID_AL_M5229)
+			outb(inb(dma_base+2) & 0x60, dma_base+2);           
+		/* =================================================*/
+		
 		if (inb(dma_base+2) & 0x80) {
 			printk("%s: simplex device:  DMA disabled\n", name);
 			dma_base = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/ide-pci.c linux.18p8/drivers/block/ide-pci.c
--- linux.vanilla/drivers/block/ide-pci.c	Sun Jun 11 21:44:12 2000
+++ linux.18p8/drivers/block/ide-pci.c	Mon Sep 11 23:03:25 2000
@@ -30,6 +30,7 @@
 #define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
 #define DEVID_PIIX4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
 #define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
+#define DEVID_VP_OLDIDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_0})
 #define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
 #define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
 #define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
@@ -39,6 +40,7 @@
 #define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
 #define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
 #define DEVID_OPTI621X	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    0xd568})  /* from datasheets */
+#define DEVID_ALI15X3   ((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
 #define DEVID_TRM290	((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM,  PCI_DEVICE_ID_TEKRAM_DC290})
 #define DEVID_NS87410	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87410})
 #define DEVID_NS87415	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
@@ -52,6 +54,13 @@
 
 #define IDE_IGNORE	((void *)-1)
 
+#ifdef CONFIG_BLK_DEV_ALI15X3
+extern void ide_init_ali15x3(ide_hwif_t *);
+#define INIT_ALI15X3  &ide_init_ali15x3
+#else
+#define INIT_ALI15X3  NULL
+#endif
+
 #ifdef CONFIG_BLK_DEV_TRM290
 extern void ide_init_trm290(ide_hwif_t *);
 #define INIT_TRM290	&ide_init_trm290
@@ -145,6 +154,7 @@
 	{DEVID_HT6565,	"HT6565",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_OPTI621,	"OPTI621",	INIT_OPTI621,	{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_OPTI621X,"OPTI621X",	INIT_OPTI621,	{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
+	{DEVID_ALI15X3, "ALI15X3",  INIT_ALI15X3,   {{0x00,0x00,0x00}, {0x00,0x00,0x00}},   ON_BOARD,   0 },
 	{DEVID_TRM290,	"TRM290",	INIT_TRM290,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_NS87415,	"NS87415",	INIT_NS87415,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_AEC6210,	"AEC6210",	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	OFF_BOARD,	0 },
@@ -451,6 +461,19 @@
 		devid.vid = dev->vendor;
 		devid.did = dev->device;
 		if (IDE_PCI_DEVID_EQ(devid, DEVID_450NX)) {
+			autodma_default = 0;
+			break;
+		}
+		/*
+		 *	Don't try and tune a VIA 82C586 or 586A
+		 */
+		if (IDE_PCI_DEVID_EQ(devid, DEVID_VP_IDE))
+		{
+			autodma_default = 0;
+			break;
+		}
+		if (IDE_PCI_DEVID_EQ(devid, DEVID_VP_OLDIDE))
+		{
 			autodma_default = 0;
 			break;
 		}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/ll_rw_blk.c linux.18p8/drivers/block/ll_rw_blk.c
--- linux.vanilla/drivers/block/ll_rw_blk.c	Sun Jun 11 21:44:12 2000
+++ linux.18p8/drivers/block/ll_rw_blk.c	Fri Sep  1 13:32:19 2000
@@ -421,7 +421,15 @@
 	     case COMPAQ_SMART2_MAJOR+4:	\
 	     case COMPAQ_SMART2_MAJOR+5:	\
 	     case COMPAQ_SMART2_MAJOR+6:	\
-	     case COMPAQ_SMART2_MAJOR+7:
+	     case COMPAQ_SMART2_MAJOR+7:	\
+	     case COMPAQ_CISS_MAJOR+0:        \
+             case COMPAQ_CISS_MAJOR+1:        \
+             case COMPAQ_CISS_MAJOR+2:        \
+             case COMPAQ_CISS_MAJOR+3:        \
+             case COMPAQ_CISS_MAJOR+4:        \
+             case COMPAQ_CISS_MAJOR+5:        \
+             case COMPAQ_CISS_MAJOR+6:        \
+             case COMPAQ_CISS_MAJOR+7:
 
 #define elevator_starve_rest_of_queue(req)			\
 do {								\
@@ -568,7 +576,9 @@
 	if (scsi_blk_major(major) ||
             (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) ||
             (major >= COMPAQ_SMART2_MAJOR+0 &&
-             major <= COMPAQ_SMART2_MAJOR+7))
+             major <= COMPAQ_SMART2_MAJOR+7) ||
+	     (major >= COMPAQ_CISS_MAJOR+0 &&
+             major <= COMPAQ_CISS_MAJOR+7))
 		queue_new_request = 1;
 
 out:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/cdrom/cdrom.c linux.18p8/drivers/cdrom/cdrom.c
--- linux.vanilla/drivers/cdrom/cdrom.c	Sat Sep  9 18:42:34 2000
+++ linux.18p8/drivers/cdrom/cdrom.c	Fri Sep 15 12:47:12 2000
@@ -1604,7 +1604,7 @@
 			return -EDRIVE_CANT_DO_THIS;
 		keeplocked = arg ? 1 : 0;
 		/* don't unlock the door on multiple opens */
-		if ((cdi->use_count != 1) && !arg)
+		if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN))
 			return -EBUSY;
 		return cdo->lock_door(cdi, arg);
 		}
@@ -1965,19 +1965,6 @@
 		IOCTL_OUT(arg, struct cdrom_subchnl, q);
 		/* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 
 		return 0;
-		}
-	case CDROMPLAYTRKIND: {
-		struct cdrom_ti ti;
-
-		cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
-		IOCTL_IN(arg, struct cdrom_ti, ti);
-
-		cgc.cmd[0] = GPCMD_PLAY_AUDIO_TI;
-		cgc.cmd[4] = ti.cdti_trk0;
-		cgc.cmd[5] = ti.cdti_ind0;
-		cgc.cmd[7] = ti.cdti_trk1;
-		cgc.cmd[8] = ti.cdti_ind1;
-		return cdo->generic_packet(cdi, &cgc);
 		}
 	case CDROMPLAYMSF: {
 		struct cdrom_msf msf;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/Config.in linux.18p8/drivers/char/Config.in
--- linux.vanilla/drivers/char/Config.in	Sun Jun 11 21:44:12 2000
+++ linux.18p8/drivers/char/Config.in	Wed Sep 13 16:30:38 2000
@@ -66,7 +66,7 @@
     bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
   fi
 fi
-
+     
 bool 'Mouse Support (not serial mice)' CONFIG_MOUSE
 if [ "$CONFIG_MOUSE" = "y" ]; then
 	mainmenu_option next_comment
@@ -106,6 +106,7 @@
          bool '       Fan Tachometer' CONFIG_WDT_501_FAN
      fi
   fi
+  tristate '   WDT PCI Watchdog timer' CONFIG_WDTPCI
   tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
   tristate '   Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
@@ -120,7 +121,23 @@
 if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
   bool 'Tadpole ANA H8 Support'  CONFIG_H8
 fi
+if [ "$CONFIG_PCI" = "y" ]; then
+  tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG
+fi
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   tristate '/dev/agpgart (AGP Support) (EXPERIMENTAL)' CONFIG_AGP n
+   if [ "$CONFIG_AGP" != "n" ]; then
+      bool '   Intel 440LX/BX/GX support' CONFIG_AGP_INTEL
+      bool '   Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810
+      bool '   VIA VP3/MVP3/Apollo Pro support' CONFIG_AGP_VIA
+      bool '   AMD Irongate support' CONFIG_AGP_AMD
+      bool '   Generic SiS support' CONFIG_AGP_SIS
+      bool '   ALI M1541 support' CONFIG_AGP_ALI
+   fi
+   source drivers/char/drm/Config.in
+fi
+      
 mainmenu_option next_comment
 comment 'Video For Linux'
 
@@ -139,11 +156,12 @@
     hex '  Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
   fi
   dep_tristate 'ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
-  dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
   dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
   if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
     hex '  GemTek i/o port (0x20c, 0x24c, 0x248, 0x30c, or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
   fi
+  dep_tristate 'Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
+  dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
   dep_tristate 'Trust FM Radio' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV
   if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
     hex '  Trust FM Radio I/O port (0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350
@@ -160,13 +178,13 @@
     dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    dep_tristate 'CPiA Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
+    dep_tristate 'CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
     if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then
-      if [ "$CONFIG_PARPORT" != "n" ]; then
-        dep_tristate 'CPiA Parallel Port Lowlevel Support (EXPERIMENTAL)' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT
-        if [ "$CONFIG_VIDEO_CPIA_PP" != "n" ]; then
-          bool 'CPiA Parallel Port DMA Support (EXPERIMENTAL)' CONFIG_VIDEO_CPIA_PP_DMA
-        fi
+      if [ "CONFIG_PARPORT_1284" != "n" ]; then
+        dep_tristate '  CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT
+      fi
+      if [ "$CONFIG_USB" != "n" ]; then
+        dep_tristate '  CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB
       fi
     fi
   fi
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/Makefile linux.18p8/drivers/char/Makefile
--- linux.vanilla/drivers/char/Makefile	Sat Sep  9 18:42:34 2000
+++ linux.18p8/drivers/char/Makefile	Wed Sep 13 16:31:01 2000
@@ -11,21 +11,23 @@
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) rio ftape joystick
+ALL_SUB_DIRS := $(SUB_DIRS) rio ftape joystick drm agp
 
 #
 # This file contains the font map for the default (hardware) font
 #
 FONTMAPFILE = cp437.uni
 
-L_TARGET := char.a
+O_TARGET := char.o
 M_OBJS   :=
-L_OBJS   := tty_io.o n_tty.o tty_ioctl.o mem.o random.o
-LX_OBJS  := pty.o misc.o
+O_OBJS   := tty_io.o n_tty.o tty_ioctl.o mem.o random.o
+OX_OBJS  := pty.o misc.o
+obj-y 	 :=
+obj-m	 :=
 
 ifdef CONFIG_VT
-L_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o
-LX_OBJS += console.o selection.o
+O_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o
+OX_OBJS += console.o selection.o
 endif
 
 ifeq ($(CONFIG_SERIAL),y)
@@ -33,7 +35,7 @@
     ifeq ($(CONFIG_SGI_SERIAL),)
       ifeq ($(CONFIG_DECSTATION),)
 	ifeq ($(CONFIG_BAGET_MIPS),)
-      LX_OBJS += serial.o
+      OX_OBJS += serial.o
     endif
   endif
     endif
@@ -56,28 +58,28 @@
 ifndef CONFIG_BAGET_MIPS
 ifndef CONFIG_SUN_KEYBOARD
 ifdef CONFIG_VT
-LX_OBJS += keyboard.o
-endif
+OX_OBJS += keyboard.o
  ifneq ($(ARCH),m68k)
   ifneq ($(ARCH),s390)
-   L_OBJS += pc_keyb.o defkeymap.o
+   O_OBJS += pc_keyb.o defkeymap.o
  endif
  endif
+endif
 else
 ifdef CONFIG_PCI
-L_OBJS += defkeymap.o
-LX_OBJS += keyboard.o
+O_OBJS += defkeymap.o
+OX_OBJS += keyboard.o
 endif
 endif
 
 ifdef CONFIG_MAGIC_SYSRQ
-LX_OBJS += sysrq.o
+OX_OBJS += sysrq.o
 endif
 endif
 endif
 
 ifeq ($(CONFIG_ATARI_DSP56K),y)
-L_OBJS += dsp56k.o
+O_OBJS += dsp56k.o
 S = y
 else
   ifeq ($(CONFIG_ATARI_DSP56K),m)
@@ -87,7 +89,7 @@
 endif
 
 ifeq ($(CONFIG_ROCKETPORT),y)
-L_OBJS += rocket.o
+O_OBJS += rocket.o
 else
   ifeq ($(CONFIG_ROCKETPORT),m)
   M_OBJS += rocket.o
@@ -95,7 +97,7 @@
 endif
 
 ifeq ($(CONFIG_MOXA_SMARTIO),y)
-L_OBJS += mxser.o
+O_OBJS += mxser.o
 else
   ifeq ($(CONFIG_MOXA_SMARTIO),m)
   M_OBJS += mxser.o
@@ -103,7 +105,7 @@
 endif
 
 ifeq ($(CONFIG_MOXA_INTELLIO),y)
-L_OBJS += moxa.o
+O_OBJS += moxa.o
 else
   ifeq ($(CONFIG_MOXA_INTELLIO),m)
   M_OBJS += moxa.o
@@ -111,7 +113,7 @@
 endif
 
 ifeq ($(CONFIG_DIGI),y)
-L_OBJS += pcxx.o
+O_OBJS += pcxx.o
 else
   ifeq ($(CONFIG_DIGI),m)
   M_OBJS += pcxx.o
@@ -119,7 +121,7 @@
 endif
 
 ifeq ($(CONFIG_DIGIEPCA),y)
-L_OBJS += epca.o
+O_OBJS += epca.o
 else
   ifeq ($(CONFIG_DIGIEPCA),m)
   M_OBJS += epca.o
@@ -127,7 +129,7 @@
 endif
 
 ifeq ($(CONFIG_CYCLADES),y)
-L_OBJS += cyclades.o
+O_OBJS += cyclades.o
 else
   ifeq ($(CONFIG_CYCLADES),m)
   M_OBJS += cyclades.o
@@ -135,7 +137,7 @@
 endif
 
 ifeq ($(CONFIG_STALLION),y)
-L_OBJS += stallion.o
+O_OBJS += stallion.o
 else
   ifeq ($(CONFIG_STALLION),m)
   M_OBJS += stallion.o
@@ -143,7 +145,7 @@
 endif
 
 ifeq ($(CONFIG_ISTALLION),y)
-L_OBJS += istallion.o
+O_OBJS += istallion.o
 else
   ifeq ($(CONFIG_ISTALLION),m)
   M_OBJS += istallion.o
@@ -151,7 +153,7 @@
 endif
 
 ifeq ($(CONFIG_COMPUTONE),y)
-L_OBJS += ip2.o ip2main.o
+O_OBJS += ip2.o ip2main.o
 else
   ifeq ($(CONFIG_COMPUTONE),m)
   M_OBJS += ip2.o ip2main.o
@@ -159,7 +161,7 @@
 endif
 
 ifeq ($(CONFIG_RISCOM8),y)
-L_OBJS += riscom8.o
+O_OBJS += riscom8.o
 else
   ifeq ($(CONFIG_RISCOM8),m)
   M_OBJS += riscom8.o
@@ -167,7 +169,7 @@
 endif
 
 ifeq ($(CONFIG_ISI),y)
-L_OBJS += isicom.o
+O_OBJS += isicom.o
 else
   ifeq ($(CONFIG_ISI),m)
   M_OBJS += isicom.o
@@ -175,7 +177,7 @@
 endif
 
 ifeq ($(CONFIG_ESPSERIAL),y)
-L_OBJS += esp.o
+O_OBJS += esp.o
 else
   ifeq ($(CONFIG_ESPSERIAL),m)
   M_OBJS += esp.o
@@ -191,34 +193,27 @@
 endif
 
 ifeq ($(CONFIG_SPECIALIX),y)
-L_OBJS += specialix.o
+O_OBJS += specialix.o
 else
   ifeq ($(CONFIG_SPECIALIX),m)
   M_OBJS += specialix.o
   endif
 endif
 
-ifeq ($(CONFIG_SX),y)
-L_OBJS += sx.o generic_serial.o
-else
-  ifeq ($(CONFIG_SX),m)
-  M_OBJS += sx.o  generic_serial.o
-  endif
-endif
+obj-$(CONFIG_SX) += sx.o generic_serial.o
+obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o
 
 ifeq ($(CONFIG_RIO),y)
-L_OBJS += rio/rio.o  generic_serial.o
 SUB_DIRS += rio
 MOD_SUB_DIRS += rio
 else
   ifeq ($(CONFIG_RIO),m)
-  M_OBJS += generic_serial.o
   MOD_SUB_DIRS += rio
   endif
 endif
 
 ifeq ($(CONFIG_ATIXL_BUSMOUSE),y)
-L_OBJS += atixlmouse.o
+O_OBJS += atixlmouse.o
 else
   ifeq ($(CONFIG_ATIXL_BUSMOUSE),m)
   M_OBJS += atixlmouse.o
@@ -226,7 +221,7 @@
 endif
 
 ifeq ($(CONFIG_BUSMOUSE),y)
-L_OBJS += busmouse.o
+O_OBJS += busmouse.o
 else
   ifeq ($(CONFIG_BUSMOUSE),m)
   M_OBJS += busmouse.o
@@ -234,7 +229,7 @@
 endif
 
 ifeq ($(CONFIG_PRINTER),y)
-L_OBJS += lp.o
+O_OBJS += lp.o
 else
   ifeq ($(CONFIG_PRINTER),m)
   M_OBJS += lp.o
@@ -242,7 +237,7 @@
 endif
 
 ifeq ($(CONFIG_JOYSTICK),y)
-L_OBJS += joystick/js.o
+O_OBJS += joystick/js.o
 SUB_DIRS += joystick
 MOD_SUB_DIRS += joystick
 else
@@ -252,7 +247,7 @@
 endif
 
 ifeq ($(CONFIG_DTLK),y)
-L_OBJS += dtlk.o
+O_OBJS += dtlk.o
 else
   ifeq ($(CONFIG_DTLK),m)
   M_OBJS += dtlk.o
@@ -260,7 +255,7 @@
 endif
 
 ifeq ($(CONFIG_MS_BUSMOUSE),y)
-L_OBJS += msbusmouse.o
+O_OBJS += msbusmouse.o
 else
   ifeq ($(CONFIG_MS_BUSMOUSE),m)
   M_OBJS += msbusmouse.o
@@ -268,7 +263,7 @@
 endif
 
 ifeq ($(CONFIG_82C710_MOUSE),y)
-L_OBJS += qpmouse.o
+O_OBJS += qpmouse.o
 else
   ifeq ($(CONFIG_82C710_MOUSE),m)
   M_OBJS += qpmouse.o
@@ -276,7 +271,7 @@
 endif
 
 ifeq ($(CONFIG_SOFT_WATCHDOG),y)
-L_OBJS += softdog.o
+O_OBJS += softdog.o
 else
   ifeq ($(CONFIG_SOFT_WATCHDOG),m)
   M_OBJS += softdog.o
@@ -284,7 +279,7 @@
 endif
 
 ifeq ($(CONFIG_PCWATCHDOG),y)
-L_OBJS += pcwd.o
+O_OBJS += pcwd.o
 else
   ifeq ($(CONFIG_PCWATCHDOG),m)
   M_OBJS += pcwd.o
@@ -292,7 +287,7 @@
 endif
 
 ifeq ($(CONFIG_ACQUIRE_WDT),y)
-L_OBJS += acquirewdt.o
+O_OBJS += acquirewdt.o
 else
   ifeq ($(CONFIG_ACQUIRE_WDT),m)
   M_OBJS += acquirewdt.o
@@ -300,7 +295,7 @@
 endif
 
 ifeq ($(CONFIG_60XX_WDT),y)
-L_OBJS += sbc60xxwdt.o
+O_OBJS += sbc60xxwdt.o
 else
   ifeq ($(CONFIG_60XX_WDT),m)
   M_OBJS += sbc60xxwdt.o
@@ -308,7 +303,7 @@
 endif
 
 ifeq ($(CONFIG_MIXCOMWD),y)
-L_OBJS += mixcomwd.o
+O_OBJS += mixcomwd.o
 else
   ifeq ($(CONFIG_MIXCOMWD),m)
   M_OBJS += mixcomwd.o
@@ -316,7 +311,7 @@
 endif
 
 ifeq ($(CONFIG_AMIGAMOUSE),y)
-L_OBJS += amigamouse.o
+O_OBJS += amigamouse.o
 else
   ifeq ($(CONFIG_AMIGAMOUSE),m)
     M_OBJS += amigamouse.o
@@ -324,7 +319,7 @@
 endif
 
 ifeq ($(CONFIG_ATARIMOUSE),y)
-L_OBJS += atarimouse.o
+O_OBJS += atarimouse.o
 else
   ifeq ($(CONFIG_ATARIMOUSE),m)
     M_OBJS += atarimouse.o
@@ -332,7 +327,7 @@
 endif
 
 ifeq ($(CONFIG_ADBMOUSE),y)
-L_OBJS += adbmouse.o
+O_OBJS += adbmouse.o
 else
   ifeq ($(CONFIG_ADBMOUSE),m)
     M_OBJS += adbmouse.o
@@ -340,7 +335,7 @@
 endif
 
 ifeq ($(CONFIG_PC110_PAD),y)
-L_OBJS += pc110pad.o
+O_OBJS += pc110pad.o
 else
   ifeq ($(CONFIG_PC110_PAD),m)
     M_OBJS += pc110pad.o
@@ -348,20 +343,28 @@
 endif
 
 ifeq ($(CONFIG_WDT),y)
-L_OBJS += wdt.o
+O_OBJS += wdt.o
 else
   ifeq ($(CONFIG_WDT),m)
     M_OBJS += wdt.o
   endif
 endif
 
+ifeq ($(CONFIG_WDTPCI),y)
+O_OBJS += wdt_pci.o
+else
+  ifeq ($(CONFIG_WDTPCI),m)
+    M_OBJS += wdt_pci.o
+  endif
+endif
+
 ifeq ($(CONFIG_RTC),y)
-L_OBJS += rtc.o
+O_OBJS += rtc.o
 endif
 
 ifeq ($(CONFIG_NVRAM),y)
   ifeq ($(CONFIG_PPC),)
-  L_OBJS += nvram.o
+  O_OBJS += nvram.o
   endif
 else
   ifeq ($(CONFIG_NVRAM),m)
@@ -371,8 +374,27 @@
   endif
 endif
 
+ifeq ($(CONFIG_AGP),y)
+O_OBJS += agp/agp.o
+ALL_SUB_DIRS += agp
+SUB_DIRS += agp
+else
+  ifeq ($(CONFIG_AGP),m)
+  ALL_SUB_DIRS += agp
+  MOD_SUB_DIRS += agp
+  endif
+endif
+
+ifeq ($(CONFIG_INTEL_RNG),y)
+O_OBJS += i810_rng.o
+else
+  ifeq ($(CONFIG_INTEL_RNG),m)
+  M_OBJS += i810_rng.o
+  endif
+endif
+    
 ifeq ($(CONFIG_VIDEO_DEV),y)
-LX_OBJS += videodev.o
+OX_OBJS += videodev.o
 else
   ifeq ($(CONFIG_VIDEO_DEV),m)
     MX_OBJS += videodev.o
@@ -388,7 +410,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_BT848),y)
-L_OBJS += bttv.o tuner.o
+O_OBJS += bttv.o tuner.o
 L_I2C=y
 else
   ifeq ($(CONFIG_VIDEO_BT848),m)
@@ -398,7 +420,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_MSP3400),y)
-L_OBJS += msp3400.o 
+O_OBJS += msp3400.o 
 L_I2C=y
 else
   ifeq ($(CONFIG_VIDEO_MSP3400),m)
@@ -408,7 +430,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_SAA5249),y)
-L_OBJS += saa5249.o
+O_OBJS += saa5249.o
 L_I2C=y
 else
   ifeq ($(CONFIG_VIDEO_SAA5249),m)
@@ -418,7 +440,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_BWQCAM),y)
-L_OBJS += bw-qcam.o
+O_OBJS += bw-qcam.o
 else
   ifeq ($(CONFIG_VIDEO_BWQCAM),m)
     M_OBJS += bw-qcam.o
@@ -426,7 +448,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_CQCAM),y)
-L_OBJS += c-qcam.o
+O_OBJS += c-qcam.o
 else
   ifeq ($(CONFIG_VIDEO_CQCAM),m)
     M_OBJS += c-qcam.o
@@ -434,7 +456,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_ZORAN),y)
-L_OBJS += buz.o
+O_OBJS += buz.o
 L_I2C=y
 else
   ifeq ($(CONFIG_VIDEO_ZORAN),m)
@@ -444,7 +466,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_LML33),y)
-L_OBJS += bt856.o bt819.o
+O_OBJS += bt856.o bt819.o
 else
   ifeq ($(CONFIG_VIDEO_LML33),m)
     M_OBJS += bt856.o bt819.o
@@ -452,7 +474,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_BUZ),y)
-L_OBJS += saa7111.o saa7185.o
+O_OBJS += saa7111.o saa7185.o
 else
   ifeq ($(CONFIG_VIDEO_BUZ),m)
     M_OBJS += saa7111.o saa7185.o
@@ -460,7 +482,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_PMS),y)
-L_OBJS += pms.o
+O_OBJS += pms.o
 else
   ifeq ($(CONFIG_VIDEO_PMS),m)
   M_OBJS += pms.o
@@ -468,7 +490,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_PLANB),y)
-L_OBJS += planb.o
+O_OBJS += planb.o
 else
   ifeq ($(CONFIG_VIDEO_PLANB),m)
   M_OBJS += planb.o
@@ -476,7 +498,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_VINO),y)
-L_OBJS += vino.o
+O_OBJS += vino.o
 else
   ifeq ($(CONFIG_VIDEO_VINO),m)
   M_OBJS += vino.o
@@ -484,7 +506,7 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_CPIA),y)
-LX_OBJS += cpia.o
+OX_OBJS += cpia.o
 else
   ifeq ($(CONFIG_VIDEO_CPIA),m)
     MX_OBJS += cpia.o
@@ -492,15 +514,23 @@
 endif
 
 ifeq ($(CONFIG_VIDEO_CPIA_PP),y)
-L_OBJS += cpia_pp.o
+O_OBJS += cpia_pp.o
 else
   ifeq ($(CONFIG_VIDEO_CPIA_PP),m)
     M_OBJS += cpia_pp.o
   endif
 endif
 
+ifeq ($(CONFIG_VIDEO_CPIA_USB),y)
+O_OBJS += cpia_usb.o
+else
+  ifeq ($(CONFIG_VIDEO_CPIA_USB),m)
+    M_OBJS += cpia_usb.o
+  endif
+endif
+
 ifeq ($(CONFIG_RADIO_AZTECH),y)
-L_OBJS += radio-aztech.o
+O_OBJS += radio-aztech.o
 else
   ifeq ($(CONFIG_RADIO_AZTECH),m)
   M_OBJS += radio-aztech.o
@@ -508,7 +538,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_SF16FMI),y)
-L_OBJS += radio-sf16fmi.o
+O_OBJS += radio-sf16fmi.o
 else
   ifeq ($(CONFIG_RADIO_SF16FMI),m)
   M_OBJS += radio-sf16fmi.o
@@ -516,7 +546,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_RTRACK),y)
-L_OBJS += radio-aimslab.o
+O_OBJS += radio-aimslab.o
 else
   ifeq ($(CONFIG_RADIO_RTRACK),m)
   M_OBJS += radio-aimslab.o
@@ -524,7 +554,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_RTRACK2),y)
-L_OBJS += radio-rtrack2.o
+O_OBJS += radio-rtrack2.o
 else
   ifeq ($(CONFIG_RADIO_RTRACK2),m)
   M_OBJS += radio-rtrack2.o
@@ -532,7 +562,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_TYPHOON),y)
-L_OBJS += radio-typhoon.o
+O_OBJS += radio-typhoon.o
 else
   ifeq ($(CONFIG_RADIO_TYPHOON),m)
   M_OBJS += radio-typhoon.o
@@ -540,7 +570,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_ZOLTRIX),y)
-L_OBJS += radio-zoltrix.o
+O_OBJS += radio-zoltrix.o
 else
   ifeq ($(CONFIG_RADIO_ZOLTRIX),m)
   M_OBJS += radio-zoltrix.o
@@ -548,7 +578,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_CADET),y)
-L_OBJS += radio-cadet.o
+O_OBJS += radio-cadet.o
 else
   ifeq ($(CONFIG_RADIO_CADET),m)
   M_OBJS += radio-cadet.o
@@ -556,15 +586,23 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_MIROPCM20),y)
-L_OBJS += radio-miropcm20.o
+O_OBJS += radio-miropcm20.o
 else
   ifeq ($(CONFIG_RADIO_MIROPCM20),m)
   M_OBJS += radio-miropcm20.o
   endif
 endif
 
+ifeq ($(CONFIG_RADIO_MAESTRO),y)
+O_OBJS += radio-maestro.o
+else
+  ifeq ($(CONFIG_RADIO_MAESTRO),m)
+  M_OBJS += radio-maestro.o
+  endif
+endif
+
 ifeq ($(CONFIG_RADIO_GEMTEK),y)
-L_OBJS += radio-gemtek.o
+O_OBJS += radio-gemtek.o
 else
   ifeq ($(CONFIG_RADIO_GEMTEK),m)
   M_OBJS += radio-gemtek.o
@@ -572,7 +610,7 @@
 endif                                             
 
 ifeq ($(CONFIG_RADIO_TRUST),y)
-L_OBJS += radio-trust.o
+O_OBJS += radio-trust.o
 else
   ifeq ($(CONFIG_RADIO_TRUST),m)
   M_OBJS += radio-trust.o
@@ -580,7 +618,7 @@
 endif                                             
 
 ifeq ($(CONFIG_QIC02_TAPE),y)
-L_OBJS += tpqic02.o
+O_OBJS += tpqic02.o
 else
   ifeq ($(CONFIG_QIC02_TAPE),m)
   M_OBJS += tpqic02.o
@@ -588,7 +626,7 @@
 endif
 
 ifeq ($(CONFIG_FTAPE),y)
-L_OBJS       += ftape/ftape.o
+O_OBJS       += ftape/ftape.o
 SUB_DIRS     += ftape
 ifneq ($(CONFIG_ZFTAPE),n)
 MOD_SUB_DIRS += ftape
@@ -600,11 +638,23 @@
 endif
 
 ifdef CONFIG_H8
-LX_OBJS += h8.o
+OX_OBJS += h8.o
+endif
+
+
+ifeq ($(CONFIG_DRM),y)
+SUB_DIRS += drm
+O_OBJS += drm/drm.o
+MOD_SUB_DIRS += drm
+else
+  ifeq ($(CONFIG_DRM),m)
+  MOD_SUB_DIRS += drm
+  endif
 endif
 
+
 ifeq ($(L_I2C),y)
-LX_OBJS += i2c.o
+OX_OBJS += i2c.o
 else
   ifeq ($(M_I2C),y)
   MX_OBJS += i2c.o
@@ -615,7 +665,7 @@
 ifeq ($(CONFIG_HFMODEM),y)
 ALL_SUB_DIRS += hfmodem
 SUB_DIRS += hfmodem
-L_OBJS += hfmodem/hfmodem.o
+O_OBJS += hfmodem/hfmodem.o
 else
   ifeq ($(CONFIG_HFMODEM),m)
   ALL_SUB_DIRS += hfmodem
@@ -625,17 +675,26 @@
 endif
 
 ifeq ($(CONFIG_DZ),y)
-  L_OBJS += dz.o
+  O_OBJS += dz.o
 endif
 
 
 ifeq ($(CONFIG_TOSHIBA),y)
-L_OBJS += toshiba.o
+O_OBJS += toshiba.o
 else
   ifeq ($(CONFIG_TOSHIBA),m)
   M_OBJS += toshiba.o
   endif
 endif
+
+# remove objects from modular that are also built in
+obj-m           := $(filter-out $(obj-y), $(obj-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS          += $(filter-out $(export-objs), $(obj-y))
+OX_OBJS         += $(filter     $(export-objs), $(obj-y))
+M_OBJS          += $(sort $(filter     $(module-list), $(obj-m)))
 
 
 include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/Makefile linux.18p8/drivers/char/agp/Makefile
--- linux.vanilla/drivers/char/agp/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/agp/Makefile	Fri Sep  1 14:06:07 2000
@@ -0,0 +1,22 @@
+#
+# Makefile for the agpgart device driver.  This driver adds a user
+# space ioctl interface to use agp memory.  It also adds a kernel interface
+# that other drivers could use to manipulate agp memory.
+
+O_TARGET	:= agp.o
+
+ifeq ($(CONFIG_AGP),y)
+  O_OBJS += agpgart_fe.o
+  OX_OBJS += agpgart_be.o
+else
+  ifeq ($(CONFIG_AGP), m)
+    MI_OBJS += agpgart_fe.o
+    MIX_OBJS += agpgart_be.o
+    M_OBJS += agpgart.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+agpgart.o: agpgart_be.o agpgart_fe.o
+	$(LD) $(LD_RFLAG) -r -o $@ agpgart_be.o agpgart_fe.o
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agp.h linux.18p8/drivers/char/agp/agp.h
--- linux.vanilla/drivers/char/agp/agp.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/agp/agp.h	Fri Sep  1 14:06:37 2000
@@ -0,0 +1,279 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _AGP_BACKEND_PRIV_H
+#define _AGP_BACKEND_PRIV_H 1
+
+enum aper_size_type {
+	U8_APER_SIZE,
+	U16_APER_SIZE,
+	U32_APER_SIZE,
+	LVL2_APER_SIZE,
+	FIXED_APER_SIZE
+};
+
+typedef struct _gatt_mask {
+	unsigned long mask;
+	u32 type;
+	/* totally device specific, for integrated chipsets that 
+	 * might have different types of memory masks.  For other
+	 * devices this will probably be ignored */
+} gatt_mask;
+
+typedef struct _aper_size_info_8 {
+	int size;
+	int num_entries;
+	int page_order;
+	u8 size_value;
+} aper_size_info_8;
+
+typedef struct _aper_size_info_16 {
+	int size;
+	int num_entries;
+	int page_order;
+	u16 size_value;
+} aper_size_info_16;
+
+typedef struct _aper_size_info_32 {
+	int size;
+	int num_entries;
+	int page_order;
+	u32 size_value;
+} aper_size_info_32;
+
+typedef struct _aper_size_info_lvl2 {
+	int size;
+	int num_entries;
+	u32 size_value;
+} aper_size_info_lvl2;
+
+typedef struct _aper_size_info_fixed {
+	int size;
+	int num_entries;
+	int page_order;
+} aper_size_info_fixed;
+
+struct agp_bridge_data {
+	agp_version *version;
+	void *aperture_sizes;
+	void *previous_size;
+	void *current_size;
+	void *dev_private_data;
+	struct pci_dev *dev;
+	gatt_mask *masks;
+	unsigned long *gatt_table;
+	unsigned long *gatt_table_real;
+	unsigned long scratch_page;
+	unsigned long gart_bus_addr;
+	unsigned long gatt_bus_addr;
+	u32 mode;
+	enum chipset_type type;
+	enum aper_size_type size_type;
+	u32 *key_list;
+	atomic_t current_memory_agp;
+	atomic_t agp_in_use;
+	int max_memory_agp;	/* in number of pages */
+	int needs_scratch_page;
+	int aperture_size_idx;
+	int num_aperture_sizes;
+	int num_of_masks;
+	int capndx;
+
+	/* Links to driver specific functions */
+
+	int (*fetch_size) (void);
+	int (*configure) (void);
+	void (*agp_enable) (u32);
+	void (*cleanup) (void);
+	void (*tlb_flush) (agp_memory *);
+	unsigned long (*mask_memory) (unsigned long, int);
+	void (*cache_flush) (void);
+	int (*create_gatt_table) (void);
+	int (*free_gatt_table) (void);
+	int (*insert_memory) (agp_memory *, off_t, int);
+	int (*remove_memory) (agp_memory *, off_t, int);
+	agp_memory *(*alloc_by_type) (size_t, int);
+	void (*free_by_type) (agp_memory *);
+};
+
+#define OUTREG32(mmap, addr, val)   *(volatile u32 *)(mmap + (addr)) = (val)
+#define OUTREG16(mmap, addr, val)   *(volatile u16 *)(mmap + (addr)) = (val)
+#define OUTREG8 (mmap, addr, val)   *(volatile u8 *) (mmap + (addr)) = (val)
+
+#define INREG32(mmap, addr)         *(volatile u32 *)(mmap + (addr))
+#define INREG16(mmap, addr)         *(volatile u16 *)(mmap + (addr))
+#define INREG8 (mmap, addr)         *(volatile u8 *) (mmap + (addr))
+
+#define CACHE_FLUSH	agp_bridge.cache_flush
+#define A_SIZE_8(x)	((aper_size_info_8 *) x)
+#define A_SIZE_16(x)	((aper_size_info_16 *) x)
+#define A_SIZE_32(x)	((aper_size_info_32 *) x)
+#define A_SIZE_LVL2(x)  ((aper_size_info_lvl2 *) x)
+#define A_SIZE_FIX(x)	((aper_size_info_fixed *) x)
+#define A_IDX8()	(A_SIZE_8(agp_bridge.aperture_sizes) + i)
+#define A_IDX16()	(A_SIZE_16(agp_bridge.aperture_sizes) + i)
+#define A_IDX32()	(A_SIZE_32(agp_bridge.aperture_sizes) + i)
+#define A_IDXLVL2()	(A_SIZE_LVL2(agp_bridge.aperture_sizes) + i)
+#define A_IDXFIX()	(A_SIZE_FIX(agp_bridge.aperture_sizes) + i)
+#define MAXKEY		(4096 * 32)
+
+#ifndef min
+#define min(a,b)	(((a)<(b))?(a):(b))
+#endif
+
+#define arraysize(x)            (sizeof(x)/sizeof(*(x)))
+
+#define AGPGART_MODULE_NAME	"agpgart"
+#define PFX			AGPGART_MODULE_NAME ": "
+
+#define PGE_EMPTY(p) (!(p) || (p) == (unsigned long) agp_bridge.scratch_page)
+
+#ifndef PCI_DEVICE_ID_VIA_82C691_0
+#define PCI_DEVICE_ID_VIA_82C691_0      0x0691
+#endif
+#ifndef PCI_DEVICE_ID_VIA_82C691_1
+#define PCI_DEVICE_ID_VIA_82C691_1      0x8691
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_810_0
+#define PCI_DEVICE_ID_INTEL_810_0       0x7120
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_840_0
+#define PCI_DEVICE_ID_INTEL_840_0		0x1a21
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_810_DC100_0
+#define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_810_E_0
+#define PCI_DEVICE_ID_INTEL_810_E_0     0x7124
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82443GX_0
+#define PCI_DEVICE_ID_INTEL_82443GX_0   0x71a0
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_810_1
+#define PCI_DEVICE_ID_INTEL_810_1       0x7121
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_810_DC100_1
+#define PCI_DEVICE_ID_INTEL_810_DC100_1 0x7123
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_810_E_1
+#define PCI_DEVICE_ID_INTEL_810_E_1     0x7125
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_815_0
+#define PCI_DEVICE_ID_INTEL_815_0       0x1130
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_815_1
+#define PCI_DEVICE_ID_INTEL_815_1       0x1132
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82443GX_1
+#define PCI_DEVICE_ID_INTEL_82443GX_1   0x71a1
+#endif
+#ifndef PCI_DEVICE_ID_AMD_IRONGATE_0
+#define PCI_DEVICE_ID_AMD_IRONGATE_0    0x7006
+#endif
+#ifndef PCI_VENDOR_ID_AL
+#define PCI_VENDOR_ID_AL		0x10b9
+#endif
+#ifndef PCI_DEVICE_ID_AL_M1541_0
+#define PCI_DEVICE_ID_AL_M1541_0	0x1541
+#endif
+#ifndef PCI_DEVICE_ID_SI_630
+#define PCI_DEVICE_ID_SI_630		0x0630
+#endif
+#ifndef PCI_DEVICE_ID_SI_540
+#define PCI_DEVICE_ID_SI_540		0x0540
+#endif
+#ifndef PCI_DEVICE_ID_SI_620
+#define PCI_DEVICE_ID_SI_620		0x0620
+#endif
+#ifndef PCI_DEVICE_ID_SI_530
+#define PCI_DEVICE_ID_SI_530		0x0530
+#endif
+#ifndef PCI_DEVICE_ID_VIA_8501_0
+#define PCI_DEVICE_ID_VIA_8501_0	0x0501
+#endif
+
+
+/* intel register */
+#define INTEL_APBASE    0x10
+#define INTEL_APSIZE    0xb4
+#define INTEL_ATTBASE   0xb8
+#define INTEL_AGPCTRL   0xb0
+#define INTEL_NBXCFG    0x50
+#define INTEL_ERRSTS    0x91
+
+/* intel i840 registers */
+#define INTEL_I840_MCHCFG   0x50
+#define INTEL_I840_ERRSTS	0xc8
+
+/* intel i810 registers */
+#define I810_GMADDR 0x10
+#define I810_MMADDR 0x14
+#define I810_PTE_BASE          0x10000
+#define I810_PTE_MAIN_UNCACHED 0x00000000
+#define I810_PTE_LOCAL         0x00000002
+#define I810_PTE_VALID         0x00000001
+#define I810_SMRAM_MISCC       0x70
+#define I810_GFX_MEM_WIN_SIZE  0x00010000
+#define I810_GFX_MEM_WIN_32M   0x00010000
+#define I810_GMS               0x000000c0
+#define I810_GMS_DISABLE       0x00000000
+#define I810_PGETBL_CTL        0x2020
+#define I810_PGETBL_ENABLED    0x00000001
+#define I810_DRAM_CTL          0x3000
+#define I810_DRAM_ROW_0        0x00000001
+#define I810_DRAM_ROW_0_SDRAM  0x00000001
+
+/* VIA register */
+#define VIA_APBASE      0x10
+#define VIA_GARTCTRL    0x80
+#define VIA_APSIZE      0x84
+#define VIA_ATTBASE     0x88
+
+/* SiS registers */
+#define SIS_APBASE      0x10
+#define SIS_ATTBASE     0x90
+#define SIS_APSIZE      0x94
+#define SIS_TLBCNTRL    0x97
+#define SIS_TLBFLUSH    0x98
+
+/* AMD registers */
+#define AMD_APBASE      0x10
+#define AMD_MMBASE      0x14
+#define AMD_APSIZE      0xac
+#define AMD_MODECNTL    0xb0
+#define AMD_MODECNTL2   0xb2
+#define AMD_GARTENABLE  0x02	/* In mmio region (16-bit register) */
+#define AMD_ATTBASE     0x04	/* In mmio region (32-bit register) */
+#define AMD_TLBFLUSH    0x0c	/* In mmio region (32-bit register) */
+#define AMD_CACHEENTRY  0x10	/* In mmio region (32-bit register) */
+
+/* ALi registers */
+#define ALI_APBASE	0x10
+#define ALI_AGPCTRL	0xb8
+#define ALI_ATTBASE	0xbc
+#define ALI_TLBCTRL	0xc0
+
+#endif				/* _AGP_BACKEND_PRIV_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agp_backend.h linux.18p8/drivers/char/agp/agp_backend.h
--- linux.vanilla/drivers/char/agp/agp_backend.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/agp/agp_backend.h	Fri Sep  1 14:14:15 2000
@@ -0,0 +1,231 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _AGP_BACKEND_H
+#define _AGP_BACKEND_H 1
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define AGPGART_VERSION_MAJOR 0
+#define AGPGART_VERSION_MINOR 99
+
+enum chipset_type {
+	NOT_SUPPORTED,
+	INTEL_GENERIC,
+	INTEL_LX,
+	INTEL_BX,
+	INTEL_GX,
+	INTEL_I810,
+	INTEL_I840,
+	VIA_GENERIC,
+	VIA_VP3,
+	VIA_MVP3,
+	VIA_MVP4,
+	VIA_APOLLO_SUPER,
+	VIA_APOLLO_PRO,
+	SIS_GENERIC,
+	AMD_GENERIC,
+	AMD_IRONGATE,
+	ALI_M1541,
+	ALI_GENERIC
+};
+
+typedef struct _agp_version {
+	u16 major;
+	u16 minor;
+} agp_version;
+
+typedef struct _agp_kern_info {
+	agp_version version;
+	struct pci_dev *device;
+	enum chipset_type chipset;
+	unsigned long mode;
+	off_t aper_base;
+	size_t aper_size;
+	int max_memory;		/* In pages */
+	int current_memory;
+} agp_kern_info;
+
+/* 
+ * The agp_memory structure has information
+ * about the block of agp memory allocated.
+ * A caller may manipulate the next and prev
+ * pointers to link each allocated item into
+ * a list.  These pointers are ignored by the 
+ * backend.  Everything else should never be
+ * written to, but the caller may read any of
+ * the items to detrimine the status of this
+ * block of agp memory.
+ * 
+ */
+
+typedef struct _agp_memory {
+	int key;
+	struct _agp_memory *next;
+	struct _agp_memory *prev;
+	size_t page_count;
+	int num_scratch_pages;
+	unsigned long *memory;
+	off_t pg_start;
+	u32 type;
+	u32 physical;
+	u8 is_bound;
+	u8 is_flushed;
+} agp_memory;
+
+#define AGP_NORMAL_MEMORY 0
+
+extern void agp_free_memory(agp_memory *);
+
+/*
+ * agp_free_memory :
+ * 
+ * This function frees memory associated with
+ * an agp_memory pointer.  It is the only function
+ * that can be called when the backend is not owned
+ * by the caller.  (So it can free memory on client
+ * death.)
+ * 
+ * It takes an agp_memory pointer as an argument.
+ * 
+ */
+
+extern agp_memory *agp_allocate_memory(size_t, u32);
+
+/*
+ * agp_allocate_memory :
+ * 
+ * This function allocates a group of pages of
+ * a certain type.
+ * 
+ * It takes a size_t argument of the number of pages, and
+ * an u32 argument of the type of memory to be allocated.  
+ * Every agp bridge device will allow you to allocate 
+ * AGP_NORMAL_MEMORY which maps to physical ram.  Any other
+ * type is device dependant.
+ * 
+ * It returns NULL whenever memory is unavailable.
+ * 
+ */
+
+extern void agp_copy_info(agp_kern_info *);
+
+/*
+ * agp_copy_info :
+ * 
+ * This function copies information about the
+ * agp bridge device and the state of the agp
+ * backend into an agp_kern_info pointer.
+ * 
+ * It takes an agp_kern_info pointer as an
+ * argument.  The caller should insure that
+ * this pointer is valid.
+ * 
+ */
+
+extern int agp_bind_memory(agp_memory *, off_t);
+
+/*
+ * agp_bind_memory :
+ * 
+ * This function binds an agp_memory structure
+ * into the graphics aperture translation table.
+ * 
+ * It takes an agp_memory pointer and an offset into
+ * the graphics aperture translation table as arguments
+ * 
+ * It returns -EINVAL if the pointer == NULL.
+ * It returns -EBUSY if the area of the table
+ * requested is already in use.
+ * 
+ */
+
+extern int agp_unbind_memory(agp_memory *);
+
+/* 
+ * agp_unbind_memory :
+ * 
+ * This function removes an agp_memory structure
+ * from the graphics aperture translation table.
+ * 
+ * It takes an agp_memory pointer as an argument.
+ * 
+ * It returns -EINVAL if this piece of agp_memory
+ * is not currently bound to the graphics aperture
+ * translation table or if the agp_memory 
+ * pointer == NULL
+ * 
+ */
+
+extern void agp_enable(u32);
+
+/* 
+ * agp_enable :
+ * 
+ * This function initializes the agp point-to-point
+ * connection.
+ * 
+ * It takes an agp mode register as an argument
+ * 
+ */
+
+extern int agp_backend_acquire(void);
+
+/*
+ * agp_backend_acquire :
+ * 
+ * This Function attempts to acquire the agp
+ * backend.
+ * 
+ * returns -EBUSY if agp is in use,
+ * returns 0 if the caller owns the agp backend
+ */
+
+extern void agp_backend_release(void);
+
+/*
+ * agp_backend_release :
+ * 
+ * This Function releases the lock on the agp
+ * backend.
+ * 
+ * The caller must insure that the graphics
+ * aperture translation table is read for use
+ * by another entity.  (Ensure that all memory
+ * it bound is unbound.)
+ * 
+ */
+
+/* Don't call this directly!! used in initialization */
+extern int agp_init(void);
+
+#endif				/* _AGP_BACKEND_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agpgart.h linux.18p8/drivers/char/agp/agpgart.h
--- linux.vanilla/drivers/char/agp/agpgart.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/agp/agpgart.h	Sun Sep  3 00:12:57 2000
@@ -0,0 +1,224 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _AGP_H
+#define _AGP_H 1
+
+#define AGPIOC_BASE       'A'
+#define AGPIOC_INFO       _IOR (AGPIOC_BASE, 0, agp_info*)
+#define AGPIOC_ACQUIRE    _IO  (AGPIOC_BASE, 1)
+#define AGPIOC_RELEASE    _IO  (AGPIOC_BASE, 2)
+#define AGPIOC_SETUP      _IOW (AGPIOC_BASE, 3, agp_setup*)
+#define AGPIOC_RESERVE    _IOW (AGPIOC_BASE, 4, agp_region*)
+#define AGPIOC_PROTECT    _IOW (AGPIOC_BASE, 5, agp_region*)
+#define AGPIOC_ALLOCATE   _IOWR(AGPIOC_BASE, 6, agp_allocate*)
+#define AGPIOC_DEALLOCATE _IOW (AGPIOC_BASE, 7, int)
+#define AGPIOC_BIND       _IOW (AGPIOC_BASE, 8, agp_bind*)
+#define AGPIOC_UNBIND     _IOW (AGPIOC_BASE, 9, agp_unbind*)
+
+#define AGP_DEVICE      "/dev/agpgart"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef __KERNEL__
+#include <linux/types.h>
+#include <asm/types.h>
+
+typedef struct _agp_version {
+	__u16 major;
+	__u16 minor;
+} agp_version;
+
+typedef struct _agp_info {
+	agp_version version;	/* version of the driver        */
+	__u32 bridge_id;	/* bridge vendor/device         */
+	__u32 agp_mode;		/* mode info of bridge          */
+	off_t aper_base;	/* base of aperture             */
+	size_t aper_size;	/* size of aperture             */
+	size_t pg_total;	/* max pages (swap + system)    */
+	size_t pg_system;	/* max pages (system)           */
+	size_t pg_used;		/* current pages used           */
+} agp_info;
+
+typedef struct _agp_setup {
+	__u32 agp_mode;		/* mode info of bridge          */
+} agp_setup;
+
+/*
+ * The "prot" down below needs still a "sleep" flag somehow ...
+ */
+typedef struct _agp_segment {
+	off_t pg_start;		/* starting page to populate    */
+	size_t pg_count;	/* number of pages              */
+	int prot;		/* prot flags for mmap          */
+} agp_segment;
+
+typedef struct _agp_region {
+	pid_t pid;		/* pid of process               */
+	size_t seg_count;	/* number of segments           */
+	struct _agp_segment *seg_list;
+} agp_region;
+
+typedef struct _agp_allocate {
+	int key;		/* tag of allocation            */
+	size_t pg_count;	/* number of pages              */
+	__u32 type;		/* 0 == normal, other devspec   */
+   	__u32 physical;         /* device specific (some devices  
+				 * need a phys address of the     
+				 * actual page behind the gatt    
+				 * table)                        */
+} agp_allocate;
+
+typedef struct _agp_bind {
+	int key;		/* tag of allocation            */
+	off_t pg_start;		/* starting page to populate    */
+} agp_bind;
+
+typedef struct _agp_unbind {
+	int key;		/* tag of allocation            */
+	__u32 priority;		/* priority for paging out      */
+} agp_unbind;
+
+#else				/* __KERNEL__ */
+
+#define AGPGART_MINOR 175
+
+#define AGP_UNLOCK()      	up(&(agp_fe.agp_mutex));
+#define AGP_LOCK()    		down(&(agp_fe.agp_mutex));
+#define AGP_LOCK_INIT() 	sema_init(&(agp_fe.agp_mutex), 1)
+
+#ifndef _AGP_BACKEND_H
+typedef struct _agp_version {
+	u16 major;
+	u16 minor;
+} agp_version;
+
+#endif
+
+typedef struct _agp_info {
+	agp_version version;	/* version of the driver        */
+	u32 bridge_id;		/* bridge vendor/device         */
+	u32 agp_mode;		/* mode info of bridge          */
+	off_t aper_base;	/* base of aperture             */
+	size_t aper_size;	/* size of aperture             */
+	size_t pg_total;	/* max pages (swap + system)    */
+	size_t pg_system;	/* max pages (system)           */
+	size_t pg_used;		/* current pages used           */
+} agp_info;
+
+typedef struct _agp_setup {
+	u32 agp_mode;		/* mode info of bridge          */
+} agp_setup;
+
+/*
+ * The "prot" down below needs still a "sleep" flag somehow ...
+ */
+typedef struct _agp_segment {
+	off_t pg_start;		/* starting page to populate    */
+	size_t pg_count;	/* number of pages              */
+	int prot;		/* prot flags for mmap          */
+} agp_segment;
+
+typedef struct _agp_segment_priv {
+	off_t pg_start;
+	size_t pg_count;
+	pgprot_t prot;
+} agp_segment_priv;
+
+typedef struct _agp_region {
+	pid_t pid;		/* pid of process               */
+	size_t seg_count;	/* number of segments           */
+	struct _agp_segment *seg_list;
+} agp_region;
+
+typedef struct _agp_allocate {
+	int key;		/* tag of allocation            */
+	size_t pg_count;	/* number of pages              */
+	u32 type;		/* 0 == normal, other devspec   */
+	u32 physical;           /* device specific (some devices  
+				 * need a phys address of the     
+				 * actual page behind the gatt    
+				 * table)                        */
+} agp_allocate;
+
+typedef struct _agp_bind {
+	int key;		/* tag of allocation            */
+	off_t pg_start;		/* starting page to populate    */
+} agp_bind;
+
+typedef struct _agp_unbind {
+	int key;		/* tag of allocation            */
+	u32 priority;		/* priority for paging out      */
+} agp_unbind;
+
+typedef struct _agp_client {
+	struct _agp_client *next;
+	struct _agp_client *prev;
+	pid_t pid;
+	int num_segments;
+	agp_segment_priv **segments;
+} agp_client;
+
+typedef struct _agp_controller {
+	struct _agp_controller *next;
+	struct _agp_controller *prev;
+	pid_t pid;
+	int num_clients;
+	agp_memory *pool;
+	agp_client *clients;
+} agp_controller;
+
+#define AGP_FF_ALLOW_CLIENT		0
+#define AGP_FF_ALLOW_CONTROLLER 	1
+#define AGP_FF_IS_CLIENT		2
+#define AGP_FF_IS_CONTROLLER		3
+#define AGP_FF_IS_VALID 		4
+
+typedef struct _agp_file_private {
+	struct _agp_file_private *next;
+	struct _agp_file_private *prev;
+	pid_t my_pid;
+	u32 access_flags;
+} agp_file_private;
+
+struct agp_front_data {
+	struct semaphore agp_mutex;
+	agp_controller *current_controller;
+	agp_controller *controllers;
+	agp_file_private *file_priv_list;
+	u8 used_by_controller;
+	u8 backend_acquired;
+};
+
+#endif				/* __KERNEL__ */
+
+#endif				/* _AGP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agpgart_be.c linux.18p8/drivers/char/agp/agpgart_be.c
--- linux.vanilla/drivers/char/agp/agpgart_be.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/agp/agpgart_be.c	Mon Sep 11 18:05:34 2000
@@ -0,0 +1,2487 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/miscdevice.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/page.h>
+
+#include "agp_backend.h"
+#include "agp.h"
+
+MODULE_AUTHOR("Jeff Hartmann <jhartmann@precisioninsight.com>");
+MODULE_PARM(agp_try_unsupported, "1i");
+EXPORT_SYMBOL(agp_free_memory);
+EXPORT_SYMBOL(agp_allocate_memory);
+EXPORT_SYMBOL(agp_copy_info);
+EXPORT_SYMBOL(agp_bind_memory);
+EXPORT_SYMBOL(agp_unbind_memory);
+EXPORT_SYMBOL(agp_enable);
+EXPORT_SYMBOL(agp_backend_acquire);
+EXPORT_SYMBOL(agp_backend_release);
+
+static void flush_cache(void);
+
+static struct agp_bridge_data agp_bridge;
+static int agp_try_unsupported __initdata = 0;
+
+
+static inline void flush_cache(void)
+{
+#if defined(__i386__)
+	asm volatile ("wbinvd":::"memory");
+#elif defined(__alpha__)
+	/* ??? I wonder if we'll really need to flush caches, or if the
+	   core logic can manage to keep the system coherent.  The ARM
+	   speaks only of using `cflush' to get things in memory in
+	   preparation for power failure.
+
+	   If we do need to call `cflush', we'll need a target page,
+	   as we can only flush one page at a time.  */
+	mb();
+#else
+#error "Please define flush_cache."
+#endif
+}
+
+#ifdef CONFIG_SMP
+static atomic_t cpus_waiting;
+
+static void ipi_handler(void *null)
+{
+	flush_cache();
+	atomic_dec(&cpus_waiting);
+	while (atomic_read(&cpus_waiting) > 0)
+		barrier();
+}
+
+static void smp_flush_cache(void)
+{
+	atomic_set(&cpus_waiting, smp_num_cpus - 1);
+	if (smp_call_function(ipi_handler, NULL, 1, 0) != 0)
+		panic(PFX "timed out waiting for the other CPUs!\n");
+	flush_cache();
+	while (atomic_read(&cpus_waiting) > 0)
+		barrier();
+}
+#define global_cache_flush smp_flush_cache
+#else				/* CONFIG_SMP */
+#define global_cache_flush flush_cache
+#endif				/* CONFIG_SMP */
+
+int agp_backend_acquire(void)
+{
+	atomic_inc(&agp_bridge.agp_in_use);
+
+	if (atomic_read(&agp_bridge.agp_in_use) != 1) {
+		atomic_dec(&agp_bridge.agp_in_use);
+		return -EBUSY;
+	}
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+void agp_backend_release(void)
+{
+	atomic_dec(&agp_bridge.agp_in_use);
+	MOD_DEC_USE_COUNT;
+}
+
+/* 
+ * Basic Page Allocation Routines -
+ * These routines handle page allocation
+ * and by default they reserve the allocated 
+ * memory.  They also handle incrementing the
+ * current_memory_agp value, Which is checked
+ * against a maximum value.
+ */
+
+static unsigned long agp_alloc_page(void)
+{
+	void *pt;
+
+	pt = (void *) __get_free_page(GFP_KERNEL);
+	if (pt == NULL) {
+		return 0;
+	}
+	atomic_inc(&mem_map[MAP_NR(pt)].count);
+	set_bit(PG_locked, &mem_map[MAP_NR(pt)].flags);
+	atomic_inc(&agp_bridge.current_memory_agp);
+	return (unsigned long) pt;
+}
+
+static void agp_destroy_page(unsigned long page)
+{
+	void *pt = (void *) page;
+
+	if (pt == NULL) {
+		return;
+	}
+	atomic_dec(&mem_map[MAP_NR(pt)].count);
+	clear_bit(PG_locked, &mem_map[MAP_NR(pt)].flags);
+#if 0
+   	wake_up(&mem_map[MAP_NR(pt)].wait);
+#endif
+	free_page((unsigned long) pt);
+	atomic_dec(&agp_bridge.current_memory_agp);
+}
+
+/* End Basic Page Allocation Routines */
+
+/* 
+ * Generic routines for handling agp_memory structures -
+ * They use the basic page allocation routines to do the
+ * brunt of the work.
+ */
+
+
+static void agp_free_key(int key)
+{
+
+	if (key < 0) {
+		return;
+	}
+	if (key < MAXKEY) {
+		clear_bit(key, agp_bridge.key_list);
+	}
+}
+
+static int agp_get_key(void)
+{
+	int bit;
+
+	bit = find_first_zero_bit(agp_bridge.key_list, MAXKEY);
+	if (bit < MAXKEY) {
+		set_bit(bit, agp_bridge.key_list);
+		return bit;
+	}
+	return -1;
+}
+
+static agp_memory *agp_create_memory(int scratch_pages)
+{
+	agp_memory *new;
+
+	new = kmalloc(sizeof(agp_memory), GFP_KERNEL);
+
+	if (new == NULL) {
+		return NULL;
+	}
+	memset(new, 0, sizeof(agp_memory));
+	new->key = agp_get_key();
+
+	if (new->key < 0) {
+		kfree(new);
+		return NULL;
+	}
+	new->memory = vmalloc(PAGE_SIZE * scratch_pages);
+
+	if (new->memory == NULL) {
+		agp_free_key(new->key);
+		kfree(new);
+		return NULL;
+	}
+	new->num_scratch_pages = scratch_pages;
+	return new;
+}
+
+void agp_free_memory(agp_memory * curr)
+{
+	int i;
+
+	if (curr == NULL) {
+		return;
+	}
+	if (curr->is_bound == TRUE) {
+		agp_unbind_memory(curr);
+	}
+	if (curr->type != 0) {
+		agp_bridge.free_by_type(curr);
+		return;
+	}
+	if (curr->page_count != 0) {
+		for (i = 0; i < curr->page_count; i++) {
+			curr->memory[i] &= ~(0x00000fff);
+			agp_destroy_page((unsigned long)
+					 phys_to_virt(curr->memory[i]));
+		}
+	}
+	agp_free_key(curr->key);
+	vfree(curr->memory);
+	kfree(curr);
+	MOD_DEC_USE_COUNT;
+}
+
+#define ENTRIES_PER_PAGE		(PAGE_SIZE / sizeof(unsigned long))
+
+agp_memory *agp_allocate_memory(size_t page_count, u32 type)
+{
+	int scratch_pages;
+	agp_memory *new;
+	int i;
+
+	if ((atomic_read(&agp_bridge.current_memory_agp) + page_count) >
+	    agp_bridge.max_memory_agp) {
+		return NULL;
+	}
+
+	if (type != 0) {
+		new = agp_bridge.alloc_by_type(page_count, type);
+		return new;
+	}
+      	/* We always increase the module count, since free auto-decrements
+	 * it
+	 */
+
+      	MOD_INC_USE_COUNT;
+
+	scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
+
+	new = agp_create_memory(scratch_pages);
+
+	if (new == NULL) {
+	      	MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+	for (i = 0; i < page_count; i++) {
+		new->memory[i] = agp_alloc_page();
+
+		if (new->memory[i] == 0) {
+			/* Free this structure */
+			agp_free_memory(new);
+			return NULL;
+		}
+		new->memory[i] =
+		    agp_bridge.mask_memory(
+				   virt_to_phys((void *) new->memory[i]),
+						  type);
+		new->page_count++;
+	}
+
+	return new;
+}
+
+/* End - Generic routines for handling agp_memory structures */
+
+static int agp_return_size(void)
+{
+	int current_size;
+	void *temp;
+
+	temp = agp_bridge.current_size;
+
+	switch (agp_bridge.size_type) {
+	case U8_APER_SIZE:
+		current_size = A_SIZE_8(temp)->size;
+		break;
+	case U16_APER_SIZE:
+		current_size = A_SIZE_16(temp)->size;
+		break;
+	case U32_APER_SIZE:
+		current_size = A_SIZE_32(temp)->size;
+		break;
+	case LVL2_APER_SIZE:
+		current_size = A_SIZE_LVL2(temp)->size;
+		break;
+	case FIXED_APER_SIZE:
+		current_size = A_SIZE_FIX(temp)->size;
+		break;
+	default:
+		current_size = 0;
+		break;
+	}
+
+	return current_size;
+}
+
+/* Routine to copy over information structure */
+
+void agp_copy_info(agp_kern_info * info)
+{
+	memset(info, 0, sizeof(agp_kern_info));
+	info->version.major = agp_bridge.version->major;
+	info->version.minor = agp_bridge.version->minor;
+	info->device = agp_bridge.dev;
+	info->chipset = agp_bridge.type;
+	info->mode = agp_bridge.mode;
+	info->aper_base = agp_bridge.gart_bus_addr;
+	info->aper_size = agp_return_size();
+	info->max_memory = agp_bridge.max_memory_agp;
+	info->current_memory = atomic_read(&agp_bridge.current_memory_agp);
+}
+
+/* End - Routine to copy over information structure */
+
+/*
+ * Routines for handling swapping of agp_memory into the GATT -
+ * These routines take agp_memory and insert them into the GATT.
+ * They call device specific routines to actually write to the GATT.
+ */
+
+int agp_bind_memory(agp_memory * curr, off_t pg_start)
+{
+	int ret_val;
+
+	if ((curr == NULL) || (curr->is_bound == TRUE)) {
+		return -EINVAL;
+	}
+	ret_val = agp_bridge.insert_memory(curr, pg_start, curr->type);
+
+	if (ret_val != 0) {
+		return ret_val;
+	}
+	curr->is_bound = TRUE;
+	curr->pg_start = pg_start;
+	return 0;
+}
+
+int agp_unbind_memory(agp_memory * curr)
+{
+	int ret_val;
+
+	if (curr == NULL) {
+		return -EINVAL;
+	}
+	if (curr->is_bound != TRUE) {
+		return -EINVAL;
+	}
+	ret_val = agp_bridge.remove_memory(curr, curr->pg_start, curr->type);
+
+	if (ret_val != 0) {
+		return ret_val;
+	}
+	curr->is_bound = FALSE;
+	curr->pg_start = 0;
+	return 0;
+}
+
+/* End - Routines for handling swapping of agp_memory into the GATT */
+
+/* 
+ * Driver routines - start
+ * Currently this module supports the 
+ * i810, 440lx, 440bx, 440gx, via vp3, via mvp3,
+ * amd irongate, ALi M1541 and generic support for the
+ * SiS chipsets.
+ */
+
+/* Generic Agp routines - Start */
+
+static void agp_generic_agp_enable(u32 mode)
+{
+	struct pci_dev *device = NULL;
+	u32 command, scratch, cap_id;
+	u8 cap_ptr;
+
+	pci_read_config_dword(agp_bridge.dev,
+			      agp_bridge.capndx + 4,
+			      &command);
+
+	/*
+	 * PASS1: go throu all devices that claim to be
+	 *        AGP devices and collect their data.
+	 */
+
+	while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
+					device)) != NULL) {
+		pci_read_config_dword(device, 0x04, &scratch);
+
+		if (!(scratch & 0x00100000))
+			continue;
+
+		pci_read_config_byte(device, 0x34, &cap_ptr);
+
+		if (cap_ptr != 0x00) {
+			do {
+				pci_read_config_dword(device,
+						      cap_ptr, &cap_id);
+
+				if ((cap_id & 0xff) != 0x02)
+					cap_ptr = (cap_id >> 8) & 0xff;
+			}
+			while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
+		}
+		if (cap_ptr != 0x00) {
+			/*
+			 * Ok, here we have a AGP device. Disable impossible 
+			 * settings, and adjust the readqueue to the minimum.
+			 */
+
+			pci_read_config_dword(device, cap_ptr + 4, &scratch);
+
+			/* adjust RQ depth */
+			command =
+			    ((command & ~0xff000000) |
+			     min((mode & 0xff000000),
+				 min((command & 0xff000000),
+				     (scratch & 0xff000000))));
+
+			/* disable SBA if it's not supported */
+			if (!((command & 0x00000200) &&
+			      (scratch & 0x00000200) &&
+			      (mode & 0x00000200)))
+				command &= ~0x00000200;
+
+			/* disable FW if it's not supported */
+			if (!((command & 0x00000010) &&
+			      (scratch & 0x00000010) &&
+			      (mode & 0x00000010)))
+				command &= ~0x00000010;
+
+			if (!((command & 4) &&
+			      (scratch & 4) &&
+			      (mode & 4)))
+				command &= ~0x00000004;
+
+			if (!((command & 2) &&
+			      (scratch & 2) &&
+			      (mode & 2)))
+				command &= ~0x00000002;
+
+			if (!((command & 1) &&
+			      (scratch & 1) &&
+			      (mode & 1)))
+				command &= ~0x00000001;
+		}
+	}
+	/*
+	 * PASS2: Figure out the 4X/2X/1X setting and enable the
+	 *        target (our motherboard chipset).
+	 */
+
+	if (command & 4) {
+		command &= ~3;	/* 4X */
+	}
+	if (command & 2) {
+		command &= ~5;	/* 2X */
+	}
+	if (command & 1) {
+		command &= ~6;	/* 1X */
+	}
+	command |= 0x00000100;
+
+	pci_write_config_dword(agp_bridge.dev,
+			       agp_bridge.capndx + 8,
+			       command);
+
+	/*
+	 * PASS3: Go throu all AGP devices and update the
+	 *        command registers.
+	 */
+
+	while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
+					device)) != NULL) {
+		pci_read_config_dword(device, 0x04, &scratch);
+
+		if (!(scratch & 0x00100000))
+			continue;
+
+		pci_read_config_byte(device, 0x34, &cap_ptr);
+
+		if (cap_ptr != 0x00) {
+			do {
+				pci_read_config_dword(device,
+						      cap_ptr, &cap_id);
+
+				if ((cap_id & 0xff) != 0x02)
+					cap_ptr = (cap_id >> 8) & 0xff;
+			}
+			while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
+		}
+		if (cap_ptr != 0x00)
+			pci_write_config_dword(device, cap_ptr + 8, command);
+	}
+}
+
+static int agp_generic_create_gatt_table(void)
+{
+	char *table;
+	char *table_end;
+	int size;
+	int page_order;
+	int num_entries;
+	int i;
+	void *temp;
+
+	/* The generic routines can't handle 2 level gatt's */
+	if (agp_bridge.size_type == LVL2_APER_SIZE) {
+		return -EINVAL;
+	}
+
+	table = NULL;
+	i = agp_bridge.aperture_size_idx;
+	temp = agp_bridge.current_size;
+	size = page_order = num_entries = 0;
+
+	if (agp_bridge.size_type != FIXED_APER_SIZE) {
+		do {
+			switch (agp_bridge.size_type) {
+			case U8_APER_SIZE:
+				size = A_SIZE_8(temp)->size;
+				page_order =
+				    A_SIZE_8(temp)->page_order;
+				num_entries =
+				    A_SIZE_8(temp)->num_entries;
+				break;
+			case U16_APER_SIZE:
+				size = A_SIZE_16(temp)->size;
+				page_order = A_SIZE_16(temp)->page_order;
+				num_entries = A_SIZE_16(temp)->num_entries;
+				break;
+			case U32_APER_SIZE:
+				size = A_SIZE_32(temp)->size;
+				page_order = A_SIZE_32(temp)->page_order;
+				num_entries = A_SIZE_32(temp)->num_entries;
+				break;
+				/* This case will never really happen. */
+			case FIXED_APER_SIZE:
+			case LVL2_APER_SIZE:
+			default:
+				size = page_order = num_entries = 0;
+				break;
+			}
+
+			table = (char *) __get_free_pages(GFP_KERNEL,
+							  page_order);
+
+			if (table == NULL) {
+				i++;
+				switch (agp_bridge.size_type) {
+				case U8_APER_SIZE:
+					agp_bridge.current_size = A_IDX8();
+					break;
+				case U16_APER_SIZE:
+					agp_bridge.current_size = A_IDX16();
+					break;
+				case U32_APER_SIZE:
+					agp_bridge.current_size = A_IDX32();
+					break;
+					/* This case will never really 
+					 * happen. 
+					 */
+				case FIXED_APER_SIZE:
+				case LVL2_APER_SIZE:
+				default:
+					agp_bridge.current_size =
+					    agp_bridge.current_size;
+					break;
+				}
+			} else {
+				agp_bridge.aperture_size_idx = i;
+			}
+		} while ((table == NULL) &&
+			 (i < agp_bridge.num_aperture_sizes));
+	} else {
+		size = ((aper_size_info_fixed *) temp)->size;
+		page_order = ((aper_size_info_fixed *) temp)->page_order;
+		num_entries = ((aper_size_info_fixed *) temp)->num_entries;
+		table = (char *) __get_free_pages(GFP_KERNEL, page_order);
+	}
+
+	if (table == NULL) {
+		return -ENOMEM;
+	}
+	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
+
+	for (i = MAP_NR(table); i <= MAP_NR(table_end); i++) {
+		set_bit(PG_reserved, &mem_map[i].flags);
+	}
+
+   	agp_bridge.gatt_table = (unsigned long *) table;
+	agp_bridge.gatt_table_real = (unsigned long *) table;
+	CACHE_FLUSH();
+
+	if (agp_bridge.gatt_table == NULL) {
+		for (i = MAP_NR(table); i <= MAP_NR(table_end); i++) {
+			clear_bit(PG_reserved, &mem_map[i].flags);
+		}
+
+		free_pages((unsigned long) table, page_order);
+
+		return -ENOMEM;
+	}
+	agp_bridge.gatt_bus_addr = virt_to_phys(agp_bridge.gatt_table_real);
+
+	for (i = 0; i < num_entries; i++) {
+		agp_bridge.gatt_table[i] =
+		    (unsigned long) agp_bridge.scratch_page;
+	}
+
+	return 0;
+}
+
+static int agp_generic_free_gatt_table(void)
+{
+	int i;
+	int page_order;
+	char *table, *table_end;
+	void *temp;
+
+	temp = agp_bridge.current_size;
+
+	switch (agp_bridge.size_type) {
+	case U8_APER_SIZE:
+		page_order = A_SIZE_8(temp)->page_order;
+		break;
+	case U16_APER_SIZE:
+		page_order = A_SIZE_16(temp)->page_order;
+		break;
+	case U32_APER_SIZE:
+		page_order = A_SIZE_32(temp)->page_order;
+		break;
+	case FIXED_APER_SIZE:
+		page_order = A_SIZE_FIX(temp)->page_order;
+		break;
+	case LVL2_APER_SIZE:
+		/* The generic routines can't deal with 2 level gatt's */
+		return -EINVAL;
+		break;
+	default:
+		page_order = 0;
+		break;
+	}
+
+	/* Do not worry about freeing memory, because if this is
+	 * called, then all agp memory is deallocated and removed
+	 * from the table.
+	 */
+
+	table = (char *) agp_bridge.gatt_table_real;
+	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
+
+	for (i = MAP_NR(table); i <= MAP_NR(table_end); i++) {
+		clear_bit(PG_reserved, &mem_map[i].flags);
+	}
+
+	free_pages((unsigned long) agp_bridge.gatt_table_real, page_order);
+	return 0;
+}
+
+static int agp_generic_insert_memory(agp_memory * mem,
+				     off_t pg_start, int type)
+{
+	int i, j, num_entries;
+	void *temp;
+
+	temp = agp_bridge.current_size;
+
+	switch (agp_bridge.size_type) {
+	case U8_APER_SIZE:
+		num_entries = A_SIZE_8(temp)->num_entries;
+		break;
+	case U16_APER_SIZE:
+		num_entries = A_SIZE_16(temp)->num_entries;
+		break;
+	case U32_APER_SIZE:
+		num_entries = A_SIZE_32(temp)->num_entries;
+		break;
+	case FIXED_APER_SIZE:
+		num_entries = A_SIZE_FIX(temp)->num_entries;
+		break;
+	case LVL2_APER_SIZE:
+		/* The generic routines can't deal with 2 level gatt's */
+		return -EINVAL;
+		break;
+	default:
+		num_entries = 0;
+		break;
+	}
+
+	if (type != 0 || mem->type != 0) {
+		/* The generic routines know nothing of memory types */
+		return -EINVAL;
+	}
+	if ((pg_start + mem->page_count) > num_entries) {
+		return -EINVAL;
+	}
+	j = pg_start;
+
+	while (j < (pg_start + mem->page_count)) {
+		if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
+			return -EBUSY;
+		}
+		j++;
+	}
+
+	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+		agp_bridge.gatt_table[j] = mem->memory[i];
+	}
+	/* Do cache flush all the time since the table is not 
+	 * mapped uncached */
+   	CACHE_FLUSH();
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static int agp_generic_remove_memory(agp_memory * mem, off_t pg_start,
+				     int type)
+{
+	int i;
+
+	if (type != 0 || mem->type != 0) {
+		/* The generic routines know nothing of memory types */
+		return -EINVAL;
+	}
+	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+		agp_bridge.gatt_table[i] =
+		    (unsigned long) agp_bridge.scratch_page;
+	}
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static agp_memory *agp_generic_alloc_by_type(size_t page_count, int type)
+{
+	return NULL;
+}
+
+static void agp_generic_free_by_type(agp_memory * curr)
+{
+	if (curr->memory != NULL) {
+		vfree(curr->memory);
+	}
+	agp_free_key(curr->key);
+	kfree(curr);
+}
+
+void agp_enable(u32 mode)
+{
+	agp_bridge.agp_enable(mode);
+}
+
+/* End - Generic Agp routines */
+
+#ifdef CONFIG_AGP_I810
+
+static aper_size_info_fixed intel_i810_sizes[] =
+{
+	{64, 16384, 4},
+     /* The 32M mode still requires a 64k gatt */
+	{32, 8192, 4}
+};
+
+#define AGP_DCACHE_MEMORY 1
+#define AGP_PHYS_MEMORY   2
+
+static gatt_mask intel_i810_masks[] =
+{
+	{I810_PTE_VALID, 0},
+	{(I810_PTE_VALID | I810_PTE_LOCAL), AGP_DCACHE_MEMORY},
+	{I810_PTE_VALID, 0}
+};
+
+static struct _intel_i810_private {
+	struct pci_dev *i810_dev;	/* device one */
+	volatile u8 *registers;
+	int num_dcache_entries;
+} intel_i810_private;
+
+static int intel_i810_fetch_size(void)
+{
+	u32 smram_miscc;
+	aper_size_info_fixed *values;
+
+	pci_read_config_dword(agp_bridge.dev, I810_SMRAM_MISCC, &smram_miscc);
+	values = A_SIZE_FIX(agp_bridge.aperture_sizes);
+
+	if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
+		printk(KERN_WARNING PFX "i810 is disabled\n");
+		return 0;
+	}
+	if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
+		agp_bridge.previous_size =
+		    agp_bridge.current_size = (void *) (values + 1);
+		agp_bridge.aperture_size_idx = 1;
+		return values[1].size;
+	} else {
+		agp_bridge.previous_size =
+		    agp_bridge.current_size = (void *) (values);
+		agp_bridge.aperture_size_idx = 0;
+		return values[0].size;
+	}
+
+	return 0;
+}
+
+static int intel_i810_configure(void)
+{
+	aper_size_info_fixed *current_size;
+	u32 temp;
+	int i;
+
+	current_size = A_SIZE_FIX(agp_bridge.current_size);
+
+	pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
+	temp &= 0xfff80000;
+
+	intel_i810_private.registers =
+	    (volatile u8 *) ioremap(temp, 128 * 4096);
+
+	if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL)
+	     & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
+		/* This will need to be dynamically assigned */
+		printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n");
+		intel_i810_private.num_dcache_entries = 1024;
+	}
+	pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp);
+	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+	OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL,
+		 agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
+	CACHE_FLUSH();
+
+	if (agp_bridge.needs_scratch_page == TRUE) {
+		for (i = 0; i < current_size->num_entries; i++) {
+			OUTREG32(intel_i810_private.registers,
+				 I810_PTE_BASE + (i * 4),
+				 agp_bridge.scratch_page);
+		}
+	}
+	return 0;
+}
+
+static void intel_i810_cleanup(void)
+{
+	OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0);
+	iounmap((void *) intel_i810_private.registers);
+}
+
+static void intel_i810_tlbflush(agp_memory * mem)
+{
+	return;
+}
+
+static void intel_i810_agp_enable(u32 mode)
+{
+	return;
+}
+
+static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start,
+				     int type)
+{
+	int i, j, num_entries;
+	void *temp;
+
+	temp = agp_bridge.current_size;
+	num_entries = A_SIZE_FIX(temp)->num_entries;
+
+	if ((pg_start + mem->page_count) > num_entries) {
+		return -EINVAL;
+	}
+	for (j = pg_start; j < (pg_start + mem->page_count); j++) {
+		if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
+			return -EBUSY;
+		}
+	}
+
+	if (type != 0 || mem->type != 0) {
+		if ((type == AGP_DCACHE_MEMORY) &&
+		    (mem->type == AGP_DCACHE_MEMORY)) {
+			/* special insert */
+			CACHE_FLUSH();
+			for (i = pg_start;
+			     i < (pg_start + mem->page_count); i++) {
+				OUTREG32(intel_i810_private.registers,
+					 I810_PTE_BASE + (i * 4),
+					 (i * 4096) | I810_PTE_LOCAL |
+					 I810_PTE_VALID);
+			}
+			CACHE_FLUSH();
+			agp_bridge.tlb_flush(mem);
+			return 0;
+		}
+	        if((type == AGP_PHYS_MEMORY) &&
+		   (mem->type == AGP_PHYS_MEMORY)) {
+		   goto insert;
+		}
+		return -EINVAL;
+	}
+
+insert:
+   	CACHE_FLUSH();
+	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+		OUTREG32(intel_i810_private.registers,
+			 I810_PTE_BASE + (j * 4), mem->memory[i]);
+	}
+	CACHE_FLUSH();
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start,
+				     int type)
+{
+	int i;
+
+   	CACHE_FLUSH();
+	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+		OUTREG32(intel_i810_private.registers,
+			 I810_PTE_BASE + (i * 4),
+			 agp_bridge.scratch_page);
+	}
+   	CACHE_FLUSH();
+
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
+{
+	agp_memory *new;
+
+	if (type == AGP_DCACHE_MEMORY) {
+		if (pg_count != intel_i810_private.num_dcache_entries) {
+			return NULL;
+		}
+		new = agp_create_memory(1);
+
+		if (new == NULL) {
+			return NULL;
+		}
+		new->type = AGP_DCACHE_MEMORY;
+		new->page_count = pg_count;
+		new->num_scratch_pages = 0;
+		vfree(new->memory);
+	   	MOD_INC_USE_COUNT;
+		return new;
+	}
+	if(type == AGP_PHYS_MEMORY) {
+		/* The I810 requires a physical address to program
+		 * it's mouse pointer into hardware.  However the
+		 * Xserver still writes to it through the agp
+		 * aperture
+		 */
+	   	if (pg_count != 1) {
+		   	return NULL;
+		}
+	   	new = agp_create_memory(1);
+
+		if (new == NULL) {
+			return NULL;
+		}
+	   	MOD_INC_USE_COUNT;
+		new->memory[0] = agp_alloc_page();
+
+		if (new->memory[0] == 0) {
+			/* Free this structure */
+			agp_free_memory(new);
+			return NULL;
+		}
+		new->memory[0] =
+		    agp_bridge.mask_memory(
+				   virt_to_phys((void *) new->memory[0]),
+						  type);
+		new->page_count = 1;
+	   	new->num_scratch_pages = 1;
+	   	new->type = AGP_PHYS_MEMORY;
+	        new->physical = virt_to_phys((void *) new->memory[0]);
+	   	return new;
+	}
+   
+	return NULL;
+}
+
+static void intel_i810_free_by_type(agp_memory * curr)
+{
+	agp_free_key(curr->key);
+   	if(curr->type == AGP_PHYS_MEMORY) {
+	   	agp_destroy_page((unsigned long)
+				 phys_to_virt(curr->memory[0]));
+		vfree(curr->memory);
+	}
+	kfree(curr);
+   	MOD_DEC_USE_COUNT;
+}
+
+static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
+{
+	/* Type checking must be done elsewhere */
+	return addr | agp_bridge.masks[type].mask;
+}
+
+static int __init intel_i810_setup(struct pci_dev *i810_dev)
+{
+	intel_i810_private.i810_dev = i810_dev;
+
+	agp_bridge.masks = intel_i810_masks;
+	agp_bridge.num_of_masks = 2;
+	agp_bridge.aperture_sizes = (void *) intel_i810_sizes;
+	agp_bridge.size_type = FIXED_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 2;
+	agp_bridge.dev_private_data = (void *) &intel_i810_private;
+	agp_bridge.needs_scratch_page = TRUE;
+	agp_bridge.configure = intel_i810_configure;
+	agp_bridge.fetch_size = intel_i810_fetch_size;
+	agp_bridge.cleanup = intel_i810_cleanup;
+	agp_bridge.tlb_flush = intel_i810_tlbflush;
+	agp_bridge.mask_memory = intel_i810_mask_memory;
+	agp_bridge.agp_enable = intel_i810_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+	agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+	agp_bridge.insert_memory = intel_i810_insert_entries;
+	agp_bridge.remove_memory = intel_i810_remove_entries;
+	agp_bridge.alloc_by_type = intel_i810_alloc_by_type;
+	agp_bridge.free_by_type = intel_i810_free_by_type;
+
+	return 0;
+}
+
+#endif /* CONFIG_AGP_I810 */
+
+#ifdef CONFIG_AGP_INTEL
+
+static int intel_fetch_size(void)
+{
+	int i;
+	u16 temp;
+	aper_size_info_16 *values;
+
+	pci_read_config_word(agp_bridge.dev, INTEL_APSIZE, &temp);
+	values = A_SIZE_16(agp_bridge.aperture_sizes);
+
+	for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+		if (temp == values[i].size_value) {
+			agp_bridge.previous_size =
+			    agp_bridge.current_size = (void *) (values + i);
+			agp_bridge.aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+
+	return 0;
+}
+
+static void intel_tlbflush(agp_memory * mem)
+{
+	pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2200);
+	pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280);
+}
+
+static void intel_cleanup(void)
+{
+	u16 temp;
+	aper_size_info_16 *previous_size;
+
+	previous_size = A_SIZE_16(agp_bridge.previous_size);
+	pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp);
+	pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9));
+	pci_write_config_word(agp_bridge.dev, INTEL_APSIZE,
+			      previous_size->size_value);
+}
+
+static int intel_configure(void)
+{
+	u32 temp;
+	u16 temp2;
+	aper_size_info_16 *current_size;
+
+	current_size = A_SIZE_16(agp_bridge.current_size);
+
+	/* aperture size */
+	pci_write_config_word(agp_bridge.dev, INTEL_APSIZE,
+			      current_size->size_value);
+
+	/* address to map to */
+	pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+	/* attbase - aperture base */
+	pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+			       agp_bridge.gatt_bus_addr);
+
+	/* agpctrl */
+	pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280);
+
+	/* paccfg/nbxcfg */
+	pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2);
+	pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG,
+			      (temp2 & ~(1 << 10)) | (1 << 9));
+	/* clear any possible error conditions */
+	pci_write_config_byte(agp_bridge.dev, INTEL_ERRSTS + 1, 7);
+	return 0;
+}
+
+static int intel_840_configure(void)
+{
+	u32 temp;
+	u16 temp2;
+	aper_size_info_16 *current_size;
+
+	current_size = A_SIZE_16(agp_bridge.current_size);
+
+	/* aperture size */
+	pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+			      (char)current_size->size_value); 
+
+	/* address to map to */
+	pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+	/* attbase - aperture base */
+	pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+			       agp_bridge.gatt_bus_addr); 
+
+	/* agpctrl */
+	pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); 
+
+	/* mcgcfg */
+	pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2);
+	pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG,
+			      temp2 | (1 << 9));
+	/* clear any possible error conditions */
+	pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000); 
+	return 0;
+}
+
+static unsigned long intel_mask_memory(unsigned long addr, int type)
+{
+	/* Memory type is ignored */
+
+	return addr | agp_bridge.masks[0].mask;
+}
+
+
+/* Setup function */
+static gatt_mask intel_generic_masks[] =
+{
+	{0x00000017, 0}
+};
+
+static aper_size_info_16 intel_generic_sizes[7] =
+{
+	{256, 65536, 6, 0},
+	{128, 32768, 5, 32},
+	{64, 16384, 4, 48},
+	{32, 8192, 3, 56},
+	{16, 4096, 2, 60},
+	{8, 2048, 1, 62},
+	{4, 1024, 0, 63}
+};
+
+static int __init intel_generic_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = intel_generic_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.aperture_sizes = (void *) intel_generic_sizes;
+	agp_bridge.size_type = U16_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 7;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = intel_configure;
+	agp_bridge.fetch_size = intel_fetch_size;
+	agp_bridge.cleanup = intel_cleanup;
+	agp_bridge.tlb_flush = intel_tlbflush;
+	agp_bridge.mask_memory = intel_mask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+	agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+	agp_bridge.insert_memory = agp_generic_insert_memory;
+	agp_bridge.remove_memory = agp_generic_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+
+	return 0;
+	
+	(void) pdev; /* unused */
+}
+
+static int __init intel_840_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = intel_generic_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.aperture_sizes = (void *) intel_generic_sizes;
+	agp_bridge.size_type = U16_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 7;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = intel_840_configure;
+	agp_bridge.fetch_size = intel_fetch_size;
+	agp_bridge.cleanup = intel_cleanup;
+	agp_bridge.tlb_flush = intel_tlbflush;
+	agp_bridge.mask_memory = intel_mask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+	agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+	agp_bridge.insert_memory = agp_generic_insert_memory;
+	agp_bridge.remove_memory = agp_generic_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+
+	return 0;
+	
+	(void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_INTEL */
+
+#ifdef CONFIG_AGP_VIA
+
+static int via_fetch_size(void)
+{
+	int i;
+	u8 temp;
+	aper_size_info_8 *values;
+
+	values = A_SIZE_8(agp_bridge.aperture_sizes);
+	pci_read_config_byte(agp_bridge.dev, VIA_APSIZE, &temp);
+	for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+		if (temp == values[i].size_value) {
+			agp_bridge.previous_size =
+			    agp_bridge.current_size = (void *) (values + i);
+			agp_bridge.aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+
+	return 0;
+}
+
+static int via_configure(void)
+{
+	u32 temp;
+	aper_size_info_8 *current_size;
+
+	current_size = A_SIZE_8(agp_bridge.current_size);
+	/* aperture size */
+	pci_write_config_byte(agp_bridge.dev, VIA_APSIZE,
+			      current_size->size_value);
+	/* address to map too */
+	pci_read_config_dword(agp_bridge.dev, VIA_APBASE, &temp);
+	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+	/* GART control register */
+	pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f);
+
+	/* attbase - aperture GATT base */
+	pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE,
+			    (agp_bridge.gatt_bus_addr & 0xfffff000) | 3);
+	return 0;
+}
+
+static void via_cleanup(void)
+{
+	aper_size_info_8 *previous_size;
+
+	previous_size = A_SIZE_8(agp_bridge.previous_size);
+	pci_write_config_dword(agp_bridge.dev, VIA_ATTBASE, 0);
+	pci_write_config_byte(agp_bridge.dev, VIA_APSIZE,
+			      previous_size->size_value);
+}
+
+static void via_tlbflush(agp_memory * mem)
+{
+	pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000008f);
+	pci_write_config_dword(agp_bridge.dev, VIA_GARTCTRL, 0x0000000f);
+}
+
+static unsigned long via_mask_memory(unsigned long addr, int type)
+{
+	/* Memory type is ignored */
+
+	return addr | agp_bridge.masks[0].mask;
+}
+
+static aper_size_info_8 via_generic_sizes[7] =
+{
+	{256, 65536, 6, 0},
+	{128, 32768, 5, 128},
+	{64, 16384, 4, 192},
+	{32, 8192, 3, 224},
+	{16, 4096, 2, 240},
+	{8, 2048, 1, 248},
+	{4, 1024, 0, 252}
+};
+
+static gatt_mask via_generic_masks[] =
+{
+	{0x00000000, 0}
+};
+
+static int __init via_generic_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = via_generic_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.aperture_sizes = (void *) via_generic_sizes;
+	agp_bridge.size_type = U8_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 7;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = via_configure;
+	agp_bridge.fetch_size = via_fetch_size;
+	agp_bridge.cleanup = via_cleanup;
+	agp_bridge.tlb_flush = via_tlbflush;
+	agp_bridge.mask_memory = via_mask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+	agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+	agp_bridge.insert_memory = agp_generic_insert_memory;
+	agp_bridge.remove_memory = agp_generic_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+
+	return 0;
+	
+	(void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_VIA */
+
+#ifdef CONFIG_AGP_SIS
+
+static int sis_fetch_size(void)
+{
+	u8 temp_size;
+	int i;
+	aper_size_info_8 *values;
+
+	pci_read_config_byte(agp_bridge.dev, SIS_APSIZE, &temp_size);
+	values = A_SIZE_8(agp_bridge.aperture_sizes);
+	for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+		if ((temp_size == values[i].size_value) ||
+		    ((temp_size & ~(0x03)) ==
+		     (values[i].size_value & ~(0x03)))) {
+			agp_bridge.previous_size =
+			    agp_bridge.current_size = (void *) (values + i);
+
+			agp_bridge.aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+
+	return 0;
+}
+
+
+static void sis_tlbflush(agp_memory * mem)
+{
+	pci_write_config_byte(agp_bridge.dev, SIS_TLBFLUSH, 0x02);
+}
+
+static int sis_configure(void)
+{
+	u32 temp;
+	aper_size_info_8 *current_size;
+
+	current_size = A_SIZE_8(agp_bridge.current_size);
+	pci_write_config_byte(agp_bridge.dev, SIS_TLBCNTRL, 0x05);
+	pci_read_config_dword(agp_bridge.dev, SIS_APBASE, &temp);
+	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+	pci_write_config_dword(agp_bridge.dev, SIS_ATTBASE,
+			       agp_bridge.gatt_bus_addr);
+	pci_write_config_byte(agp_bridge.dev, SIS_APSIZE,
+			      current_size->size_value);
+	return 0;
+}
+
+static void sis_cleanup(void)
+{
+	aper_size_info_8 *previous_size;
+
+	previous_size = A_SIZE_8(agp_bridge.previous_size);
+	pci_write_config_byte(agp_bridge.dev, SIS_APSIZE,
+			      (previous_size->size_value & ~(0x03)));
+}
+
+static unsigned long sis_mask_memory(unsigned long addr, int type)
+{
+	/* Memory type is ignored */
+
+	return addr | agp_bridge.masks[0].mask;
+}
+
+static aper_size_info_8 sis_generic_sizes[7] =
+{
+	{256, 65536, 6, 99},
+	{128, 32768, 5, 83},
+	{64, 16384, 4, 67},
+	{32, 8192, 3, 51},
+	{16, 4096, 2, 35},
+	{8, 2048, 1, 19},
+	{4, 1024, 0, 3}
+};
+
+static gatt_mask sis_generic_masks[] =
+{
+	{0x00000000, 0}
+};
+
+static int __init sis_generic_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = sis_generic_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.aperture_sizes = (void *) sis_generic_sizes;
+	agp_bridge.size_type = U8_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 7;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = sis_configure;
+	agp_bridge.fetch_size = sis_fetch_size;
+	agp_bridge.cleanup = sis_cleanup;
+	agp_bridge.tlb_flush = sis_tlbflush;
+	agp_bridge.mask_memory = sis_mask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+	agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+	agp_bridge.insert_memory = agp_generic_insert_memory;
+	agp_bridge.remove_memory = agp_generic_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+
+	return 0;
+}
+
+#endif /* CONFIG_AGP_SIS */
+
+#ifdef CONFIG_AGP_AMD
+
+typedef struct _amd_page_map {
+	unsigned long *real;
+	unsigned long *remapped;
+} amd_page_map;
+
+static struct _amd_irongate_private {
+	volatile u8 *registers;
+	amd_page_map **gatt_pages;
+	int num_tables;
+} amd_irongate_private;
+
+static int amd_create_page_map(amd_page_map *page_map)
+{
+	int i;
+
+	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
+	if (page_map->real == NULL) {
+		return -ENOMEM;
+	}
+	set_bit(PG_reserved, &mem_map[MAP_NR(page_map->real)].flags);
+	page_map->remapped = page_map->real;
+
+	for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
+		page_map->remapped[i] = agp_bridge.scratch_page;
+	}
+	CACHE_FLUSH();
+
+	return 0;
+}
+
+static void amd_free_page_map(amd_page_map *page_map)
+{
+	clear_bit(PG_reserved, 
+		  &mem_map[MAP_NR(page_map->real)].flags);
+	free_page((unsigned long) page_map->real);
+}
+
+static void amd_free_gatt_pages(void)
+{
+	int i;
+	amd_page_map **tables;
+	amd_page_map *entry;
+
+	tables = amd_irongate_private.gatt_pages;
+	for(i = 0; i < amd_irongate_private.num_tables; i++) {
+		entry = tables[i];
+		if (entry != NULL) {
+			if (entry->real != NULL) {
+				amd_free_page_map(entry);
+			}
+			kfree(entry);
+		}
+	}
+	kfree(tables);
+}
+
+static int amd_create_gatt_pages(int nr_tables)
+{
+	amd_page_map **tables;
+	amd_page_map *entry;
+	int retval = 0;
+	int i;
+
+	tables = kmalloc((nr_tables + 1) * sizeof(amd_page_map *), 
+			 GFP_KERNEL);
+	if (tables == NULL) {
+		return -ENOMEM;
+	}
+	memset(tables, 0, sizeof(amd_page_map *) * (nr_tables + 1));
+	for (i = 0; i < nr_tables; i++) {
+		entry = kmalloc(sizeof(amd_page_map), GFP_KERNEL);
+		if (entry == NULL) {
+			retval = -ENOMEM;
+			break;
+		}
+		memset(entry, 0, sizeof(amd_page_map));
+		tables[i] = entry;
+		retval = amd_create_page_map(entry);
+		if (retval != 0) break;
+	}
+	amd_irongate_private.num_tables = nr_tables;
+	amd_irongate_private.gatt_pages = tables;
+
+	if (retval != 0) amd_free_gatt_pages();
+
+	return retval;
+}
+
+/* Since we don't need contigious memory we just try
+ * to get the gatt table once
+ */
+
+#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
+#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
+	GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr))
+#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) 
+#define GET_GATT(addr) (amd_irongate_private.gatt_pages[\
+	GET_PAGE_DIR_IDX(addr)]->remapped)
+
+static int amd_create_gatt_table(void)
+{
+	aper_size_info_lvl2 *value;
+	amd_page_map page_dir;
+	unsigned long addr;
+	int retval;
+	u32 temp;
+	int i;
+
+	value = A_SIZE_LVL2(agp_bridge.current_size);
+	retval = amd_create_page_map(&page_dir);
+	if (retval != 0) {
+		return retval;
+	}
+
+	retval = amd_create_gatt_pages(value->num_entries / 1024);
+	if (retval != 0) {
+		amd_free_page_map(&page_dir);
+		return retval;
+	}
+
+	agp_bridge.gatt_table_real = page_dir.real;
+	agp_bridge.gatt_table = page_dir.remapped;
+	agp_bridge.gatt_bus_addr = virt_to_bus(page_dir.real);
+
+	/* Get the address for the gart region.
+	 * This is a bus address even on the alpha, b/c its
+	 * used to program the agp master not the cpu
+	 */
+
+	pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp);
+	addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+	agp_bridge.gart_bus_addr = addr;
+
+	/* Calculate the agp offset */
+	for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
+		page_dir.remapped[GET_PAGE_DIR_OFF(addr)] =
+			virt_to_bus(amd_irongate_private.gatt_pages[i]->real);
+		page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001;
+	}
+
+	return 0;
+}
+
+static int amd_free_gatt_table(void)
+{
+	amd_page_map page_dir;
+   
+	page_dir.real = agp_bridge.gatt_table_real;
+	page_dir.remapped = agp_bridge.gatt_table;
+
+	amd_free_gatt_pages();
+	amd_free_page_map(&page_dir);
+	return 0;
+}
+
+static int amd_irongate_fetch_size(void)
+{
+	int i;
+	u32 temp;
+	aper_size_info_lvl2 *values;
+
+	pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
+	temp = (temp & 0x0000000e);
+	values = A_SIZE_LVL2(agp_bridge.aperture_sizes);
+	for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+		if (temp == values[i].size_value) {
+			agp_bridge.previous_size =
+			    agp_bridge.current_size = (void *) (values + i);
+
+			agp_bridge.aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+
+	return 0;
+}
+
+static int amd_irongate_configure(void)
+{
+	aper_size_info_lvl2 *current_size;
+	u32 temp;
+	u16 enable_reg;
+
+	current_size = A_SIZE_LVL2(agp_bridge.current_size);
+
+	/* Get the memory mapped registers */
+	pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp);
+	temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+	amd_irongate_private.registers = (volatile u8 *) ioremap(temp, 4096);
+
+	/* Write out the address of the gatt table */
+	OUTREG32(amd_irongate_private.registers, AMD_ATTBASE,
+		 agp_bridge.gatt_bus_addr);
+
+	/* Write the Sync register */
+	pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80);
+   
+   	/* Set indexing mode */
+   	pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x00);
+
+	/* Write the enable register */
+	enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
+	enable_reg = (enable_reg | 0x0004);
+	OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg);
+
+	/* Write out the size register */
+	pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
+	temp = (((temp & ~(0x0000000e)) | current_size->size_value)
+		| 0x00000001);
+	pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp);
+
+	/* Flush the tlb */
+	OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001);
+
+	return 0;
+}
+
+static void amd_irongate_cleanup(void)
+{
+	aper_size_info_lvl2 *previous_size;
+	u32 temp;
+	u16 enable_reg;
+
+	previous_size = A_SIZE_LVL2(agp_bridge.previous_size);
+
+	enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
+	enable_reg = (enable_reg & ~(0x0004));
+	OUTREG16(amd_irongate_private.registers, AMD_GARTENABLE, enable_reg);
+
+	/* Write back the previous size and disable gart translation */
+	pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
+	temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
+	pci_write_config_dword(agp_bridge.dev, AMD_APSIZE, temp);
+	iounmap((void *) amd_irongate_private.registers);
+}
+
+/*
+ * This routine could be implemented by taking the addresses
+ * written to the GATT, and flushing them individually.  However
+ * currently it just flushes the whole table.  Which is probably
+ * more efficent, since agp_memory blocks can be a large number of
+ * entries.
+ */
+
+static void amd_irongate_tlbflush(agp_memory * temp)
+{
+	OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001);
+}
+
+static unsigned long amd_irongate_mask_memory(unsigned long addr, int type)
+{
+	/* Only type 0 is supported by the irongate */
+
+	return addr | agp_bridge.masks[0].mask;
+}
+
+static int amd_insert_memory(agp_memory * mem,
+			     off_t pg_start, int type)
+{
+	int i, j, num_entries;
+	unsigned long *cur_gatt;
+	unsigned long addr;
+
+	num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+	if ((pg_start + mem->page_count) > num_entries) {
+		return -EINVAL;
+	}
+
+	j = pg_start;
+	while (j < (pg_start + mem->page_count)) {
+		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+		cur_gatt = GET_GATT(addr);
+		if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) {
+			return -EBUSY;
+		}
+		j++;
+	}
+
+	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+		addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+		cur_gatt = GET_GATT(addr);
+		cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+	}
+
+	CACHE_FLUSH();
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static int amd_remove_memory(agp_memory * mem, off_t pg_start,
+			     int type)
+{
+	int i;
+	unsigned long *cur_gatt;
+	unsigned long addr;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+		addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+		cur_gatt = GET_GATT(addr);
+		cur_gatt[GET_GATT_OFF(addr)] = 
+			(unsigned long) agp_bridge.scratch_page;
+	}
+
+	CACHE_FLUSH();
+	agp_bridge.tlb_flush(mem);
+	return 0;
+}
+
+static aper_size_info_lvl2 amd_irongate_sizes[7] =
+{
+	{2048, 524288, 0x0000000c},
+	{1024, 262144, 0x0000000a},
+	{512, 131072, 0x00000008},
+	{256, 65536, 0x00000006},
+	{128, 32768, 0x00000004},
+	{64, 16384, 0x00000002},
+	{32, 8192, 0x00000000}
+};
+
+static gatt_mask amd_irongate_masks[] =
+{
+	{0x00000001, 0}
+};
+
+static int __init amd_irongate_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = amd_irongate_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.aperture_sizes = (void *) amd_irongate_sizes;
+	agp_bridge.size_type = LVL2_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 7;
+	agp_bridge.dev_private_data = (void *) &amd_irongate_private;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = amd_irongate_configure;
+	agp_bridge.fetch_size = amd_irongate_fetch_size;
+	agp_bridge.cleanup = amd_irongate_cleanup;
+	agp_bridge.tlb_flush = amd_irongate_tlbflush;
+	agp_bridge.mask_memory = amd_irongate_mask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = amd_create_gatt_table;
+	agp_bridge.free_gatt_table = amd_free_gatt_table;
+	agp_bridge.insert_memory = amd_insert_memory;
+	agp_bridge.remove_memory = amd_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+
+	return 0;
+	
+	(void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_AMD */
+
+#ifdef CONFIG_AGP_ALI
+
+static int ali_fetch_size(void)
+{
+	int i;
+	u32 temp;
+	aper_size_info_32 *values;
+
+	pci_read_config_dword(agp_bridge.dev, ALI_ATTBASE, &temp);
+	temp &= ~(0xfffffff0);
+	values = A_SIZE_32(agp_bridge.aperture_sizes);
+
+	for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
+		if (temp == values[i].size_value) {
+			agp_bridge.previous_size =
+			    agp_bridge.current_size = (void *) (values + i);
+			agp_bridge.aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+
+	return 0;
+}
+
+static void ali_tlbflush(agp_memory * mem)
+{
+	u32 temp;
+
+	pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
+	pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
+			       ((temp & 0xffffff00) | 0x00000090));
+	pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
+			       ((temp & 0xffffff00) | 0x00000010));
+}
+
+static void ali_cleanup(void)
+{
+	aper_size_info_32 *previous_size;
+	u32 temp;
+
+	previous_size = A_SIZE_32(agp_bridge.previous_size);
+
+	pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
+	pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
+			       ((temp & 0xffffff00) | 0x00000090));
+	pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE,
+			       previous_size->size_value);
+}
+
+static int ali_configure(void)
+{
+	u32 temp;
+	aper_size_info_32 *current_size;
+
+	current_size = A_SIZE_32(agp_bridge.current_size);
+
+	/* aperture size and gatt addr */
+	pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE,
+		    agp_bridge.gatt_bus_addr | current_size->size_value);
+
+	/* tlb control */
+	pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
+	pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
+			       ((temp & 0xffffff00) | 0x00000010));
+
+	/* address to map to */
+	pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp);
+	agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+	return 0;
+}
+
+static unsigned long ali_mask_memory(unsigned long addr, int type)
+{
+	/* Memory type is ignored */
+
+	return addr | agp_bridge.masks[0].mask;
+}
+
+
+/* Setup function */
+static gatt_mask ali_generic_masks[] =
+{
+	{0x00000000, 0}
+};
+
+static aper_size_info_32 ali_generic_sizes[7] =
+{
+	{256, 65536, 6, 10},
+	{128, 32768, 5, 9},
+	{64, 16384, 4, 8},
+	{32, 8192, 3, 7},
+	{16, 4096, 2, 6},
+	{8, 2048, 1, 4},
+	{4, 1024, 0, 3}
+};
+
+static int __init ali_generic_setup (struct pci_dev *pdev)
+{
+	agp_bridge.masks = ali_generic_masks;
+	agp_bridge.num_of_masks = 1;
+	agp_bridge.aperture_sizes = (void *) ali_generic_sizes;
+	agp_bridge.size_type = U32_APER_SIZE;
+	agp_bridge.num_aperture_sizes = 7;
+	agp_bridge.dev_private_data = NULL;
+	agp_bridge.needs_scratch_page = FALSE;
+	agp_bridge.configure = ali_configure;
+	agp_bridge.fetch_size = ali_fetch_size;
+	agp_bridge.cleanup = ali_cleanup;
+	agp_bridge.tlb_flush = ali_tlbflush;
+	agp_bridge.mask_memory = ali_mask_memory;
+	agp_bridge.agp_enable = agp_generic_agp_enable;
+	agp_bridge.cache_flush = global_cache_flush;
+	agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+	agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+	agp_bridge.insert_memory = agp_generic_insert_memory;
+	agp_bridge.remove_memory = agp_generic_remove_memory;
+	agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+	agp_bridge.free_by_type = agp_generic_free_by_type;
+
+	return 0;
+	
+	(void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_ALI */
+
+
+/* per-chipset initialization data.
+ * note -- all chipsets for a single vendor MUST be grouped together
+ */
+static struct {
+	unsigned short device_id; /* first, to make table easier to read */
+	unsigned short vendor_id;
+	enum chipset_type chipset;
+	const char *vendor_name;
+	const char *chipset_name;
+	int (*chipset_setup) (struct pci_dev *pdev);
+} agp_bridge_info[] __initdata = {
+
+#ifdef CONFIG_AGP_ALI
+	{ PCI_DEVICE_ID_AL_M1541_0,
+		PCI_VENDOR_ID_AL,
+		ALI_M1541,
+		"Ali",
+		"M1541",
+		ali_generic_setup },
+	{ 0,
+		PCI_VENDOR_ID_AL,
+		ALI_GENERIC,
+		"Ali",
+		"Generic",
+		ali_generic_setup },
+#endif /* CONFIG_AGP_ALI */
+
+#ifdef CONFIG_AGP_AMD
+	{ PCI_DEVICE_ID_AMD_IRONGATE_0,
+		PCI_VENDOR_ID_AMD,
+		AMD_IRONGATE,
+		"AMD",
+		"Irongate",
+		amd_irongate_setup },
+	{ 0,
+		PCI_VENDOR_ID_AMD,
+		AMD_GENERIC,
+		"AMD",
+		"Generic",
+		amd_irongate_setup },
+#endif /* CONFIG_AGP_AMD */
+
+#ifdef CONFIG_AGP_INTEL
+	{ PCI_DEVICE_ID_INTEL_82443LX_0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_LX,
+		"Intel",
+		"440LX",
+		intel_generic_setup },
+	{ PCI_DEVICE_ID_INTEL_82443BX_0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_BX,
+		"Intel",
+		"440BX",
+		intel_generic_setup },
+	{ PCI_DEVICE_ID_INTEL_82443GX_0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_GX,
+		"Intel",
+		"440GX",
+		intel_generic_setup },
+	{ PCI_DEVICE_ID_INTEL_840_0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_I840,
+		"Intel",
+		"i840",
+		intel_840_setup },
+	{ 0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_GENERIC,
+		"Intel",
+		"Generic",
+		intel_generic_setup },
+#endif /* CONFIG_AGP_INTEL */
+
+#ifdef CONFIG_AGP_SIS
+	{ PCI_DEVICE_ID_SI_630,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"630",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_540,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"540",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_620,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"620",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_530,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"530",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_630,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"Generic",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_540,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"Generic",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_620,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"Generic",
+		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_530,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"Generic",
+		sis_generic_setup },
+	{ 0,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"Generic",
+		sis_generic_setup },
+#endif /* CONFIG_AGP_SIS */
+
+#ifdef CONFIG_AGP_VIA
+	{ PCI_DEVICE_ID_VIA_8501_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_MVP4,
+		"Via",
+		"MVP4",
+		via_generic_setup },
+	{ PCI_DEVICE_ID_VIA_82C597_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_VP3,
+		"Via",
+		"VP3",
+		via_generic_setup },
+	{ PCI_DEVICE_ID_VIA_82C598_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_MVP3,
+		"Via",
+		"MVP3",
+		via_generic_setup },
+	{ PCI_DEVICE_ID_VIA_8371_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_SUPER,
+		"Via",
+		"Apollo Super",
+		via_generic_setup },
+	{ PCI_DEVICE_ID_VIA_82C691_0,
+		PCI_VENDOR_ID_VIA,
+		VIA_APOLLO_PRO,
+		"Via",
+		"Apollo Pro",
+		via_generic_setup },
+	{ 0,
+		PCI_VENDOR_ID_VIA,
+		VIA_GENERIC,
+		"Via",
+		"Generic",
+		via_generic_setup },
+#endif /* CONFIG_AGP_VIA */
+
+	{ 0, }, /* dummy final entry, always present */
+};
+
+
+/* scan table above for supported devices */
+static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
+{
+	int i;
+	
+	for (i = 0; i < arraysize (agp_bridge_info); i++)
+		if (pdev->vendor == agp_bridge_info[i].vendor_id)
+			break;
+
+	if (i >= arraysize (agp_bridge_info)) {
+		printk (KERN_DEBUG PFX "unsupported bridge\n");
+		return -ENODEV;
+	}
+
+	while ((i < arraysize (agp_bridge_info)) &&
+	       (agp_bridge_info[i].vendor_id == pdev->vendor)) {
+		if (pdev->device == agp_bridge_info[i].device_id) {
+			printk (KERN_INFO PFX "Detected %s %s chipset\n",
+				agp_bridge_info[i].vendor_name,
+				agp_bridge_info[i].chipset_name);
+			agp_bridge.type = agp_bridge_info[i].chipset;
+			return agp_bridge_info[i].chipset_setup (pdev);
+		}
+		
+		i++;
+	}
+
+	i--; /* point to vendor generic entry (device_id == 0) */
+
+	/* try init anyway, if user requests it AND
+	 * there is a 'generic' bridge entry for this vendor */
+	if (agp_try_unsupported && agp_bridge_info[i].device_id == 0) {
+		printk(KERN_WARNING PFX "Trying generic %s routines"
+		       " for device id: %x\n",
+		       agp_bridge_info[i].vendor_name, pdev->device);
+		agp_bridge.type = agp_bridge_info[i].chipset;
+		return agp_bridge_info[i].chipset_setup (pdev);
+	}
+
+	printk(KERN_ERR PFX "Unsupported %s chipset,"
+	       " you might want to try "
+	       "agp_try_unsupported=1.\n",
+	       agp_bridge_info[i].vendor_name);
+	return -ENODEV;
+}
+
+
+/* Supported Device Scanning routine */
+
+static int __init agp_find_supported_device(void)
+{
+	struct pci_dev *dev = NULL;
+	u8 cap_ptr = 0x00;
+	u32 cap_id, scratch;
+
+	if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL)
+		return -ENODEV;
+
+	agp_bridge.dev = dev;
+
+	/* Need to test for I810 here */
+#ifdef CONFIG_AGP_I810
+	if (dev->vendor == PCI_VENDOR_ID_INTEL) {
+		struct pci_dev *i810_dev;
+
+		switch (dev->device) {
+		case PCI_DEVICE_ID_INTEL_810_0:
+			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					       PCI_DEVICE_ID_INTEL_810_1,
+						   NULL);
+			if (i810_dev == NULL) {
+				printk(KERN_ERR PFX "Detected an Intel i810,"
+				       " but could not find the secondary"
+				       " device.\n");
+				return -ENODEV;
+			}
+			printk(KERN_INFO PFX "Detected an Intel "
+			       "i810 Chipset.\n");
+			agp_bridge.type = INTEL_I810;
+			return intel_i810_setup (i810_dev);
+
+		case PCI_DEVICE_ID_INTEL_810_DC100_0:
+			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					 PCI_DEVICE_ID_INTEL_810_DC100_1,
+						   NULL);
+			if (i810_dev == NULL) {
+				printk(KERN_ERR PFX "Detected an Intel i810 "
+				       "DC100, but could not find the "
+				       "secondary device.\n");
+				return -ENODEV;
+			}
+			printk(KERN_INFO PFX "Detected an Intel i810 "
+			       "DC100 Chipset.\n");
+			agp_bridge.type = INTEL_I810;
+			return intel_i810_setup(i810_dev);
+
+		case PCI_DEVICE_ID_INTEL_810_E_0:
+			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+					     PCI_DEVICE_ID_INTEL_810_E_1,
+						   NULL);
+			if (i810_dev == NULL) {
+				printk(KERN_ERR PFX "Detected an Intel i810 E"
+				    ", but could not find the secondary "
+				       "device.\n");
+				return -ENODEV;
+			}
+			printk(KERN_INFO PFX "Detected an Intel i810 E "
+			       "Chipset.\n");
+			agp_bridge.type = INTEL_I810;
+			return intel_i810_setup(i810_dev);
+		 case PCI_DEVICE_ID_INTEL_815_0:
+		   /* The i815 can operate either as an i810 style
+		    * integrated device, or as an AGP4X motherboard.
+		    *
+		    * This only addresses the first mode:
+		    */
+			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+						   PCI_DEVICE_ID_INTEL_815_1,
+						   NULL);
+			if (i810_dev == NULL) {
+				printk(KERN_ERR PFX "agpgart: Detected an "
+				       "Intel i815, but could not find the"
+				       " secondary device.\n");
+				agp_bridge.type = NOT_SUPPORTED;
+				return -ENODEV;
+			}
+			printk(KERN_INFO PFX "agpgart: Detected an Intel i815 "
+			       "Chipset.\n");
+			agp_bridge.type = INTEL_I810;
+			return intel_i810_setup(i810_dev);
+
+		 default:
+			break;
+		}
+	}
+#endif /* CONFIG_AGP_I810 */
+
+	/* find capndx */
+	pci_read_config_dword(dev, 0x04, &scratch);
+	if (!(scratch & 0x00100000))
+		return -ENODEV;
+
+	pci_read_config_byte(dev, 0x34, &cap_ptr);
+	if (cap_ptr != 0x00) {
+		do {
+			pci_read_config_dword(dev, cap_ptr, &cap_id);
+
+			if ((cap_id & 0xff) != 0x02)
+				cap_ptr = (cap_id >> 8) & 0xff;
+		}
+		while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
+	}
+	if (cap_ptr == 0x00)
+		return -ENODEV;
+	agp_bridge.capndx = cap_ptr;
+
+	/* Fill in the mode register */
+	pci_read_config_dword(agp_bridge.dev,
+			      agp_bridge.capndx + 4,
+			      &agp_bridge.mode);
+
+	/* probe for known chipsets */
+	return agp_lookup_host_bridge (dev);
+}
+
+struct agp_max_table {
+	int mem;
+	int agp;
+};
+
+static struct agp_max_table maxes_table[9] __initdata =
+{
+	{0, 0},
+	{32, 4},
+	{64, 28},
+	{128, 96},
+	{256, 204},
+	{512, 440},
+	{1024, 942},
+	{2048, 1920},
+	{4096, 3932}
+};
+
+static int __init agp_find_max (void)
+{
+	long memory, index, result;
+
+	memory = virt_to_phys(high_memory) >> 20;
+	index = 1;
+
+	while ((memory > maxes_table[index].mem) &&
+	       (index < 8)) {
+		index++;
+	}
+
+	result = maxes_table[index - 1].agp +
+	   ( (memory - maxes_table[index - 1].mem)  *
+	     (maxes_table[index].agp - maxes_table[index - 1].agp)) /
+	   (maxes_table[index].mem - maxes_table[index - 1].mem);
+
+	printk(KERN_INFO PFX "Maximum main memory to use "
+	       "for agp memory: %ldM\n", result);
+	result = result << (20 - PAGE_SHIFT);
+        return result;
+}
+
+#define AGPGART_VERSION_MAJOR 0
+#define AGPGART_VERSION_MINOR 99
+
+static agp_version agp_current_version =
+{
+	AGPGART_VERSION_MAJOR,
+	AGPGART_VERSION_MINOR
+};
+
+static int __init agp_backend_initialize(void)
+{
+	int size_value, rc, got_gatt=0, got_keylist=0;
+
+	memset(&agp_bridge, 0, sizeof(struct agp_bridge_data));
+	agp_bridge.type = NOT_SUPPORTED;
+	agp_bridge.max_memory_agp = agp_find_max();
+	agp_bridge.version = &agp_current_version;
+
+	rc = agp_find_supported_device();
+	if (rc) {
+		/* not KERN_ERR because error msg should have already printed */
+		printk(KERN_DEBUG PFX "no supported devices found.\n");
+		return rc;
+	}
+
+	if (agp_bridge.needs_scratch_page == TRUE) {
+		agp_bridge.scratch_page = agp_alloc_page();
+
+		if (agp_bridge.scratch_page == 0) {
+			printk(KERN_ERR PFX "unable to get memory for "
+			       "scratch page.\n");
+			return -ENOMEM;
+		}
+		agp_bridge.scratch_page =
+		    virt_to_phys((void *) agp_bridge.scratch_page);
+		agp_bridge.scratch_page =
+		    agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
+	}
+
+	size_value = agp_bridge.fetch_size();
+
+	if (size_value == 0) {
+		printk(KERN_ERR PFX "unable to detrimine aperture size.\n");
+		rc = -EINVAL;
+		goto err_out;
+	}
+	if (agp_bridge.create_gatt_table()) {
+		printk(KERN_ERR PFX "unable to get memory for graphics "
+		       "translation table.\n");
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	got_gatt = 1;
+	
+	agp_bridge.key_list = vmalloc(PAGE_SIZE * 4);
+	if (agp_bridge.key_list == NULL) {
+		printk(KERN_ERR PFX "error allocating memory for key lists.\n");
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	got_keylist = 1;
+	
+	/* FIXME vmalloc'd memory not guaranteed contiguous */
+	memset(agp_bridge.key_list, 0, PAGE_SIZE * 4);
+
+	if (agp_bridge.configure()) {
+		printk(KERN_ERR PFX "error configuring host chipset.\n");
+		rc = -EINVAL;
+		goto err_out;
+	}
+
+	printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
+	       size_value, agp_bridge.gart_bus_addr);
+
+	return 0;
+
+err_out:
+	if (agp_bridge.needs_scratch_page == TRUE) {
+		agp_bridge.scratch_page &= ~(0x00000fff);
+		agp_destroy_page((unsigned long)
+				 phys_to_virt(agp_bridge.scratch_page));
+	}
+	if (got_gatt)
+		agp_bridge.free_gatt_table();
+	if (got_keylist)
+		vfree(agp_bridge.key_list);
+	return rc;
+}
+
+
+/* cannot be __exit b/c as it could be called from __init code */
+static void agp_backend_cleanup(void)
+{
+	agp_bridge.cleanup();
+	agp_bridge.free_gatt_table();
+	vfree(agp_bridge.key_list);
+
+	if (agp_bridge.needs_scratch_page == TRUE) {
+		agp_bridge.scratch_page &= ~(0x00000fff);
+		agp_destroy_page((unsigned long)
+				 phys_to_virt(agp_bridge.scratch_page));
+	}
+}
+
+extern int agp_frontend_initialize(void);
+extern void agp_frontend_cleanup(void);
+
+__initfunc(int agp_init(void))
+{
+	int ret_val;
+
+	printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Jeff Hartmann\n",
+	       AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
+
+	ret_val = agp_backend_initialize();
+	if (ret_val)
+		return ret_val;
+
+	ret_val = agp_frontend_initialize();
+	if (ret_val) {
+		agp_backend_cleanup();
+		return ret_val;
+	}
+
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return agp_init();
+}
+
+void cleanup_module(void)
+{
+   	agp_frontend_cleanup();
+	agp_backend_cleanup();
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agpgart_fe.c linux.18p8/drivers/char/agp/agpgart_fe.c
--- linux.vanilla/drivers/char/agp/agpgart_fe.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/agp/agpgart_fe.c	Fri Sep  1 14:06:37 2000
@@ -0,0 +1,1098 @@
+/*
+ * AGPGART module frontend version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/miscdevice.h>
+#include "agp_backend.h"
+#include "agpgart.h"
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/mman.h>
+
+#include "agp.h"
+
+static struct agp_front_data agp_fe;
+
+static agp_memory *agp_find_mem_by_key(int key)
+{
+	agp_memory *curr;
+
+	if (agp_fe.current_controller == NULL) {
+		return NULL;
+	}
+	curr = agp_fe.current_controller->pool;
+
+	while (curr != NULL) {
+		if (curr->key == key) {
+			return curr;
+		}
+		curr = curr->next;
+	}
+
+	return NULL;
+}
+
+static void agp_remove_from_pool(agp_memory * temp)
+{
+	agp_memory *prev;
+	agp_memory *next;
+
+	/* Check to see if this is even in the memory pool */
+
+	if (agp_find_mem_by_key(temp->key) != NULL) {
+		next = temp->next;
+		prev = temp->prev;
+
+		if (prev != NULL) {
+			prev->next = next;
+			if (next != NULL) {
+				next->prev = prev;
+			}
+		} else {
+			/* This is the first item on the list */
+			if (next != NULL) {
+				next->prev = NULL;
+			}
+			agp_fe.current_controller->pool = next;
+		}
+	}
+}
+
+/*
+ * Routines for managing each client's segment list -
+ * These routines handle adding and removing segments
+ * to each auth'ed client.
+ */
+
+static agp_segment_priv *agp_find_seg_in_client(const agp_client * client,
+						unsigned long offset,
+					    int size, pgprot_t page_prot)
+{
+	agp_segment_priv *seg;
+	int num_segments, pg_start, pg_count, i;
+
+	pg_start = offset / 4096;
+	pg_count = size / 4096;
+	seg = *(client->segments);
+	num_segments = client->num_segments;
+
+	for (i = 0; i < client->num_segments; i++) {
+		if ((seg[i].pg_start == pg_start) &&
+		    (seg[i].pg_count == pg_count) &&
+		    (pgprot_val(seg[i].prot) == pgprot_val(page_prot))) {
+			return seg + i;
+		}
+	}
+
+	return NULL;
+}
+
+static void agp_remove_seg_from_client(agp_client * client)
+{
+	if (client->segments != NULL) {
+		if (*(client->segments) != NULL) {
+			kfree(*(client->segments));
+		}
+		kfree(client->segments);
+	}
+}
+
+static void agp_add_seg_to_client(agp_client * client,
+			       agp_segment_priv ** seg, int num_segments)
+{
+	agp_segment_priv **prev_seg;
+
+	prev_seg = client->segments;
+
+	if (prev_seg != NULL) {
+		agp_remove_seg_from_client(client);
+	}
+	client->num_segments = num_segments;
+	client->segments = seg;
+}
+
+/* Originally taken from linux/mm/mmap.c from the array
+ * protection_map.
+ * The original really should be exported to modules, or 
+ * some routine which does the conversion for you 
+ */
+
+static const pgprot_t my_protect_map[16] =
+{
+	__P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
+	__S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
+};
+
+static pgprot_t agp_convert_mmap_flags(int prot)
+{
+#define _trans(x,bit1,bit2) \
+((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0)
+
+	unsigned long prot_bits;
+	pgprot_t temp;
+
+	prot_bits = _trans(prot, PROT_READ, VM_READ) |
+	    _trans(prot, PROT_WRITE, VM_WRITE) |
+	    _trans(prot, PROT_EXEC, VM_EXEC);
+
+	prot_bits |= VM_SHARED;
+
+	temp = my_protect_map[prot_bits & 0x0000000f];
+
+	return temp;
+}
+
+static int agp_create_segment(agp_client * client, agp_region * region)
+{
+	agp_segment_priv **ret_seg;
+	agp_segment_priv *seg;
+	agp_segment *user_seg;
+	int i;
+
+	seg = kmalloc((sizeof(agp_segment_priv) * region->seg_count),
+		      GFP_KERNEL);
+	if (seg == NULL) {
+		kfree(region->seg_list);
+		return -ENOMEM;
+	}
+	memset(seg, 0, (sizeof(agp_segment_priv) * region->seg_count));
+	user_seg = region->seg_list;
+
+	for (i = 0; i < region->seg_count; i++) {
+		seg[i].pg_start = user_seg[i].pg_start;
+		seg[i].pg_count = user_seg[i].pg_count;
+		seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot);
+	}
+	ret_seg = kmalloc(sizeof(void *), GFP_KERNEL);
+	if (ret_seg == NULL) {
+		kfree(region->seg_list);
+		kfree(seg);
+		return -ENOMEM;
+	}
+	*ret_seg = seg;
+	kfree(region->seg_list);
+	agp_add_seg_to_client(client, ret_seg, region->seg_count);
+	return 0;
+}
+
+/* End - Routines for managing each client's segment list */
+
+/* This function must only be called when current_controller != NULL */
+static void agp_insert_into_pool(agp_memory * temp)
+{
+	agp_memory *prev;
+
+	prev = agp_fe.current_controller->pool;
+
+	if (prev != NULL) {
+		prev->prev = temp;
+		temp->next = prev;
+	}
+	agp_fe.current_controller->pool = temp;
+}
+
+
+/* File private list routines */
+
+agp_file_private *agp_find_private(pid_t pid)
+{
+	agp_file_private *curr;
+
+	curr = agp_fe.file_priv_list;
+
+	while (curr != NULL) {
+		if (curr->my_pid == pid) {
+			return curr;
+		}
+		curr = curr->next;
+	}
+
+	return NULL;
+}
+
+void agp_insert_file_private(agp_file_private * priv)
+{
+	agp_file_private *prev;
+
+	prev = agp_fe.file_priv_list;
+
+	if (prev != NULL) {
+		prev->prev = priv;
+	}
+	priv->next = prev;
+	agp_fe.file_priv_list = priv;
+}
+
+void agp_remove_file_private(agp_file_private * priv)
+{
+	agp_file_private *next;
+	agp_file_private *prev;
+
+	next = priv->next;
+	prev = priv->prev;
+
+	if (prev != NULL) {
+		prev->next = next;
+
+		if (next != NULL) {
+			next->prev = prev;
+		}
+	} else {
+		if (next != NULL) {
+			next->prev = NULL;
+		}
+		agp_fe.file_priv_list = next;
+	}
+}
+
+/* End - File flag list routines */
+
+/* 
+ * Wrappers for agp_free_memory & agp_allocate_memory 
+ * These make sure that internal lists are kept updated.
+ */
+static void agp_free_memory_wrap(agp_memory * memory)
+{
+	agp_remove_from_pool(memory);
+	agp_free_memory(memory);
+}
+
+static agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type)
+{
+	agp_memory *memory;
+
+	memory = agp_allocate_memory(pg_count, type);
+   	printk(KERN_DEBUG "memory : %p\n", memory);
+	if (memory == NULL) {
+		return NULL;
+	}
+	agp_insert_into_pool(memory);
+	return memory;
+}
+
+/* Routines for managing the list of controllers -
+ * These routines manage the current controller, and the list of
+ * controllers
+ */
+
+static agp_controller *agp_find_controller_by_pid(pid_t id)
+{
+	agp_controller *controller;
+
+	controller = agp_fe.controllers;
+
+	while (controller != NULL) {
+		if (controller->pid == id) {
+			return controller;
+		}
+		controller = controller->next;
+	}
+
+	return NULL;
+}
+
+static agp_controller *agp_create_controller(pid_t id)
+{
+	agp_controller *controller;
+
+	controller = kmalloc(sizeof(agp_controller), GFP_KERNEL);
+
+	if (controller == NULL) {
+		return NULL;
+	}
+	memset(controller, 0, sizeof(agp_controller));
+	controller->pid = id;
+
+	return controller;
+}
+
+static int agp_insert_controller(agp_controller * controller)
+{
+	agp_controller *prev_controller;
+
+	prev_controller = agp_fe.controllers;
+	controller->next = prev_controller;
+
+	if (prev_controller != NULL) {
+		prev_controller->prev = controller;
+	}
+	agp_fe.controllers = controller;
+
+	return 0;
+}
+
+static void agp_remove_all_clients(agp_controller * controller)
+{
+	agp_client *client;
+	agp_client *temp;
+
+	client = controller->clients;
+
+	while (client) {
+		agp_file_private *priv;
+
+		temp = client;
+		agp_remove_seg_from_client(temp);
+		priv = agp_find_private(temp->pid);
+
+		if (priv != NULL) {
+			clear_bit(AGP_FF_IS_VALID, &priv->access_flags);
+			clear_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
+		}
+		client = client->next;
+		kfree(temp);
+	}
+}
+
+static void agp_remove_all_memory(agp_controller * controller)
+{
+	agp_memory *memory;
+	agp_memory *temp;
+
+	memory = controller->pool;
+
+	while (memory) {
+		temp = memory;
+		memory = memory->next;
+		agp_free_memory_wrap(temp);
+	}
+}
+
+static int agp_remove_controller(agp_controller * controller)
+{
+	agp_controller *prev_controller;
+	agp_controller *next_controller;
+
+	prev_controller = controller->prev;
+	next_controller = controller->next;
+
+	if (prev_controller != NULL) {
+		prev_controller->next = next_controller;
+		if (next_controller != NULL) {
+			next_controller->prev = prev_controller;
+		}
+	} else {
+		if (next_controller != NULL) {
+			next_controller->prev = NULL;
+		}
+		agp_fe.controllers = next_controller;
+	}
+
+	agp_remove_all_memory(controller);
+	agp_remove_all_clients(controller);
+
+	if (agp_fe.current_controller == controller) {
+		agp_fe.current_controller = NULL;
+		agp_fe.backend_acquired = FALSE;
+		agp_backend_release();
+	}
+	kfree(controller);
+	return 0;
+}
+
+static void agp_controller_make_current(agp_controller * controller)
+{
+	agp_client *clients;
+
+	clients = controller->clients;
+
+	while (clients != NULL) {
+		agp_file_private *priv;
+
+		priv = agp_find_private(clients->pid);
+
+		if (priv != NULL) {
+			set_bit(AGP_FF_IS_VALID, &priv->access_flags);
+			set_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
+		}
+		clients = clients->next;
+	}
+
+	agp_fe.current_controller = controller;
+}
+
+static void agp_controller_release_current(agp_controller * controller,
+				      agp_file_private * controller_priv)
+{
+	agp_client *clients;
+
+	clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags);
+	clients = controller->clients;
+
+	while (clients != NULL) {
+		agp_file_private *priv;
+
+		priv = agp_find_private(clients->pid);
+
+		if (priv != NULL) {
+			clear_bit(AGP_FF_IS_VALID, &priv->access_flags);
+		}
+		clients = clients->next;
+	}
+
+	agp_fe.current_controller = NULL;
+	agp_fe.used_by_controller = FALSE;
+	agp_backend_release();
+}
+
+/* 
+ * Routines for managing client lists -
+ * These routines are for managing the list of auth'ed clients.
+ */
+
+static agp_client *agp_find_client_in_controller(agp_controller * controller,
+						 pid_t id)
+{
+	agp_client *client;
+
+	if (controller == NULL) {
+		return NULL;
+	}
+	client = controller->clients;
+
+	while (client != NULL) {
+		if (client->pid == id) {
+			return client;
+		}
+		client = client->next;
+	}
+
+	return NULL;
+}
+
+static agp_controller *agp_find_controller_for_client(pid_t id)
+{
+	agp_controller *controller;
+
+	controller = agp_fe.controllers;
+
+	while (controller != NULL) {
+		if ((agp_find_client_in_controller(controller, id)) != NULL) {
+			return controller;
+		}
+		controller = controller->next;
+	}
+
+	return NULL;
+}
+
+static agp_client *agp_find_client_by_pid(pid_t id)
+{
+	agp_client *temp;
+
+	if (agp_fe.current_controller == NULL) {
+		return NULL;
+	}
+	temp = agp_find_client_in_controller(agp_fe.current_controller, id);
+	return temp;
+}
+
+static void agp_insert_client(agp_client * client)
+{
+	agp_client *prev_client;
+
+	prev_client = agp_fe.current_controller->clients;
+	client->next = prev_client;
+
+	if (prev_client != NULL) {
+		prev_client->prev = client;
+	}
+	agp_fe.current_controller->clients = client;
+	agp_fe.current_controller->num_clients++;
+}
+
+static agp_client *agp_create_client(pid_t id)
+{
+	agp_client *new_client;
+
+	new_client = kmalloc(sizeof(agp_client), GFP_KERNEL);
+
+	if (new_client == NULL) {
+		return NULL;
+	}
+	memset(new_client, 0, sizeof(agp_client));
+	new_client->pid = id;
+	agp_insert_client(new_client);
+	return new_client;
+}
+
+static int agp_remove_client(pid_t id)
+{
+	agp_client *client;
+	agp_client *prev_client;
+	agp_client *next_client;
+	agp_controller *controller;
+
+	controller = agp_find_controller_for_client(id);
+
+	if (controller == NULL) {
+		return -EINVAL;
+	}
+	client = agp_find_client_in_controller(controller, id);
+
+	if (client == NULL) {
+		return -EINVAL;
+	}
+	prev_client = client->prev;
+	next_client = client->next;
+
+	if (prev_client != NULL) {
+		prev_client->next = next_client;
+		if (next_client != NULL) {
+			next_client->prev = prev_client;
+		}
+	} else {
+		if (next_client != NULL) {
+			next_client->prev = NULL;
+		}
+		controller->clients = next_client;
+	}
+
+	controller->num_clients--;
+	agp_remove_seg_from_client(client);
+	kfree(client);
+	return 0;
+}
+
+/* End - Routines for managing client lists */
+
+/* File Operations */
+
+static int agp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	int size;
+	int current_size;
+	unsigned long offset;
+	agp_client *client;
+	agp_file_private *priv = (agp_file_private *) file->private_data;
+	agp_kern_info kerninfo;
+
+	AGP_LOCK();
+
+	if (agp_fe.backend_acquired != TRUE) {
+		AGP_UNLOCK();
+		return -EPERM;
+	}
+	if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags))) {
+		AGP_UNLOCK();
+		return -EPERM;
+	}
+	agp_copy_info(&kerninfo);
+	size = vma->vm_end - vma->vm_start;
+	current_size = kerninfo.aper_size;
+	current_size = current_size * 0x100000;
+	offset = vma->vm_offset;
+
+	if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) {
+		if ((size + offset) > current_size) {
+			AGP_UNLOCK();
+			return -EINVAL;
+		}
+		client = agp_find_client_by_pid(current->pid);
+
+		if (client == NULL) {
+			AGP_UNLOCK();
+			return -EPERM;
+		}
+		if (!agp_find_seg_in_client(client, offset,
+					    size, vma->vm_page_prot)) {
+			AGP_UNLOCK();
+			return -EINVAL;
+		}
+		if (remap_page_range(vma->vm_start,
+				     (kerninfo.aper_base + offset),
+				     size, vma->vm_page_prot)) {
+			AGP_UNLOCK();
+			return -EAGAIN;
+		}
+		AGP_UNLOCK();
+		return 0;
+	}
+	if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) {
+		if (size != current_size) {
+			AGP_UNLOCK();
+			return -EINVAL;
+		}
+		if (remap_page_range(vma->vm_start, kerninfo.aper_base,
+				     size, vma->vm_page_prot)) {
+			AGP_UNLOCK();
+			return -EAGAIN;
+		}
+		AGP_UNLOCK();
+		return 0;
+	}
+	AGP_UNLOCK();
+	return -EPERM;
+}
+
+static int agp_release(struct inode *inode, struct file *file)
+{
+	agp_file_private *priv = (agp_file_private *) file->private_data;
+
+	AGP_LOCK();
+
+	if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) {
+		agp_controller *controller;
+
+		controller = agp_find_controller_by_pid(priv->my_pid);
+
+		if (controller != NULL) {
+			if (controller == agp_fe.current_controller) {
+				agp_controller_release_current(controller,
+							       priv);
+			}
+			agp_remove_controller(controller);
+		}
+	}
+	if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) {
+		agp_remove_client(priv->my_pid);
+	}
+	agp_remove_file_private(priv);
+	kfree(priv);
+	MOD_DEC_USE_COUNT;
+	AGP_UNLOCK();
+	return 0;
+}
+
+static int agp_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	agp_file_private *priv;
+	agp_client *client;
+	int rc = -ENXIO;
+
+	AGP_LOCK();
+	MOD_INC_USE_COUNT;
+
+	if (minor != AGPGART_MINOR)
+		goto err_out;
+
+	priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL);
+	if (priv == NULL)
+		goto err_out_nomem;
+
+	memset(priv, 0, sizeof(agp_file_private));
+	set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags);
+	priv->my_pid = current->pid;
+
+	if ((current->uid == 0) || (current->suid == 0)) {
+		/* Root priv, can be controller */
+		set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags);
+	}
+	client = agp_find_client_by_pid(current->pid);
+
+	if (client != NULL) {
+		set_bit(AGP_FF_IS_CLIENT, &priv->access_flags);
+		set_bit(AGP_FF_IS_VALID, &priv->access_flags);
+	}
+	file->private_data = (void *) priv;
+	agp_insert_file_private(priv);
+	AGP_UNLOCK();
+	return 0;
+
+err_out_nomem:
+	rc = -ENOMEM;
+err_out:
+	MOD_DEC_USE_COUNT;
+	AGP_UNLOCK();
+	return rc;
+}
+
+
+static long long agp_lseek(struct file *file, long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static ssize_t agp_read(struct file *file, char *buf,
+			size_t count, loff_t * ppos)
+{
+	return -EINVAL;
+}
+
+static ssize_t agp_write(struct file *file, const char *buf,
+			 size_t count, loff_t * ppos)
+{
+	return -EINVAL;
+}
+
+static int agpioc_info_wrap(agp_file_private * priv, unsigned long arg)
+{
+	agp_info userinfo;
+	agp_kern_info kerninfo;
+
+	agp_copy_info(&kerninfo);
+
+	userinfo.version.major = kerninfo.version.major;
+	userinfo.version.minor = kerninfo.version.minor;
+	userinfo.bridge_id = kerninfo.device->vendor |
+	    (kerninfo.device->device << 16);
+	userinfo.agp_mode = kerninfo.mode;
+	userinfo.aper_base = kerninfo.aper_base;
+	userinfo.aper_size = kerninfo.aper_size;
+	userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory;
+	userinfo.pg_used = kerninfo.current_memory;
+
+	if (copy_to_user((void *) arg, &userinfo, sizeof(agp_info))) {
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int agpioc_acquire_wrap(agp_file_private * priv, unsigned long arg)
+{
+	agp_controller *controller;
+	if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags))) {
+		return -EPERM;
+	}
+	if (agp_fe.current_controller != NULL) {
+		return -EBUSY;
+	}
+	if ((agp_backend_acquire()) == 0) {
+		agp_fe.backend_acquired = TRUE;
+	} else {
+		return -EBUSY;
+	}
+
+	controller = agp_find_controller_by_pid(priv->my_pid);
+
+	if (controller != NULL) {
+		agp_controller_make_current(controller);
+	} else {
+		controller = agp_create_controller(priv->my_pid);
+
+		if (controller == NULL) {
+			agp_fe.backend_acquired = FALSE;
+			agp_backend_release();
+			return -ENOMEM;
+		}
+		agp_insert_controller(controller);
+		agp_controller_make_current(controller);
+	}
+
+	set_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags);
+	set_bit(AGP_FF_IS_VALID, &priv->access_flags);
+	return 0;
+}
+
+static int agpioc_release_wrap(agp_file_private * priv, unsigned long arg)
+{
+	agp_controller_release_current(agp_fe.current_controller, priv);
+	return 0;
+}
+
+static int agpioc_setup_wrap(agp_file_private * priv, unsigned long arg)
+{
+	agp_setup mode;
+
+	if (copy_from_user(&mode, (void *) arg, sizeof(agp_setup))) {
+		return -EFAULT;
+	}
+	agp_enable(mode.agp_mode);
+	return 0;
+}
+
+static int agpioc_reserve_wrap(agp_file_private * priv, unsigned long arg)
+{
+	agp_region reserve;
+	agp_client *client;
+	agp_file_private *client_priv;
+
+
+	if (copy_from_user(&reserve, (void *) arg, sizeof(agp_region))) {
+		return -EFAULT;
+	}
+	client = agp_find_client_by_pid(reserve.pid);
+
+	if (reserve.seg_count == 0) {
+		/* remove a client */
+		client_priv = agp_find_private(reserve.pid);
+
+		if (client_priv != NULL) {
+			set_bit(AGP_FF_IS_CLIENT,
+				&client_priv->access_flags);
+			set_bit(AGP_FF_IS_VALID,
+				&client_priv->access_flags);
+		}
+		if (client == NULL) {
+			/* client is already removed */
+			return 0;
+		}
+		return agp_remove_client(reserve.pid);
+	} else {
+		agp_segment *segment;
+
+		segment = kmalloc((sizeof(agp_segment) * reserve.seg_count),
+				  GFP_KERNEL);
+
+		if (segment == NULL) {
+			return -ENOMEM;
+		}
+		if (copy_from_user(segment, (void *) reserve.seg_list,
+				   GFP_KERNEL)) {
+			kfree(segment);
+			return -EFAULT;
+		}
+		reserve.seg_list = segment;
+
+		if (client == NULL) {
+			/* Create the client and add the segment */
+			client = agp_create_client(reserve.pid);
+
+			if (client == NULL) {
+				kfree(segment);
+				return -ENOMEM;
+			}
+			client_priv = agp_find_private(reserve.pid);
+
+			if (client_priv != NULL) {
+				set_bit(AGP_FF_IS_CLIENT,
+					&client_priv->access_flags);
+				set_bit(AGP_FF_IS_VALID,
+					&client_priv->access_flags);
+			}
+			return agp_create_segment(client, &reserve);
+		} else {
+			return agp_create_segment(client, &reserve);
+		}
+	}
+	/* Will never really happen */
+	return -EINVAL;
+}
+
+static int agpioc_protect_wrap(agp_file_private * priv, unsigned long arg)
+{
+	/* This function is not currently implemented */
+	return -EINVAL;
+}
+
+static int agpioc_allocate_wrap(agp_file_private * priv, unsigned long arg)
+{
+	agp_memory *memory;
+	agp_allocate alloc;
+
+	if (copy_from_user(&alloc, (void *) arg, sizeof(agp_allocate))) {
+		return -EFAULT;
+	}
+	memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type);
+
+	if (memory == NULL) {
+		return -ENOMEM;
+	}
+	alloc.key = memory->key;
+	alloc.physical = memory->physical;
+
+	if (copy_to_user((void *) arg, &alloc, sizeof(agp_allocate))) {
+		agp_free_memory_wrap(memory);
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static int agpioc_deallocate_wrap(agp_file_private * priv, unsigned long arg)
+{
+	agp_memory *memory;
+
+	memory = agp_find_mem_by_key((int) arg);
+
+	if (memory == NULL) {
+		return -EINVAL;
+	}
+	agp_free_memory_wrap(memory);
+	return 0;
+}
+
+static int agpioc_bind_wrap(agp_file_private * priv, unsigned long arg)
+{
+	agp_bind bind_info;
+	agp_memory *memory;
+
+	if (copy_from_user(&bind_info, (void *) arg, sizeof(agp_bind))) {
+		return -EFAULT;
+	}
+	memory = agp_find_mem_by_key(bind_info.key);
+
+	if (memory == NULL) {
+		return -EINVAL;
+	}
+	return agp_bind_memory(memory, bind_info.pg_start);
+}
+
+static int agpioc_unbind_wrap(agp_file_private * priv, unsigned long arg)
+{
+	agp_memory *memory;
+	agp_unbind unbind;
+
+	if (copy_from_user(&unbind, (void *) arg, sizeof(agp_unbind))) {
+		return -EFAULT;
+	}
+	memory = agp_find_mem_by_key(unbind.key);
+
+	if (memory == NULL) {
+		return -EINVAL;
+	}
+	return agp_unbind_memory(memory);
+}
+
+static int agp_ioctl(struct inode *inode, struct file *file,
+		     unsigned int cmd, unsigned long arg)
+{
+	agp_file_private *curr_priv = (agp_file_private *) file->private_data;
+	int ret_val = -ENOTTY;
+
+	AGP_LOCK();
+
+	if ((agp_fe.current_controller == NULL) &&
+	    (cmd != AGPIOC_ACQUIRE)) {
+		ret_val = -EINVAL;
+	   	goto ioctl_out;
+	}
+	if ((agp_fe.backend_acquired != TRUE) &&
+	    (cmd != AGPIOC_ACQUIRE)) {
+		ret_val = -EBUSY;
+	   	goto ioctl_out;
+	}
+	if (cmd != AGPIOC_ACQUIRE) {
+		if (!(test_bit(AGP_FF_IS_CONTROLLER,
+			       &curr_priv->access_flags))) {
+			ret_val = -EPERM;
+		   	goto ioctl_out;
+		}
+		/* Use the original pid of the controller,
+		 * in case it's threaded */
+
+		if (agp_fe.current_controller->pid != curr_priv->my_pid) {
+			ret_val = -EBUSY;
+		   	goto ioctl_out;
+		}
+	}
+	switch (cmd) {
+	case AGPIOC_INFO:
+		{
+			ret_val = agpioc_info_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	case AGPIOC_ACQUIRE:
+		{
+			ret_val = agpioc_acquire_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	case AGPIOC_RELEASE:
+		{
+			ret_val = agpioc_release_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	case AGPIOC_SETUP:
+		{
+			ret_val = agpioc_setup_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	case AGPIOC_RESERVE:
+		{
+			ret_val = agpioc_reserve_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	case AGPIOC_PROTECT:
+		{
+			ret_val = agpioc_protect_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	case AGPIOC_ALLOCATE:
+		{
+			ret_val = agpioc_allocate_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	case AGPIOC_DEALLOCATE:
+		{
+			ret_val = agpioc_deallocate_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	case AGPIOC_BIND:
+		{
+			ret_val = agpioc_bind_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	case AGPIOC_UNBIND:
+		{
+			ret_val = agpioc_unbind_wrap(curr_priv, arg);
+		   	goto ioctl_out;
+		}
+	}
+   
+ioctl_out:
+	AGP_UNLOCK();
+	return ret_val;
+}
+
+static struct file_operations agp_fops =
+{
+	llseek:		agp_lseek,
+	read:		agp_read,
+	write:		agp_write,
+	ioctl:		agp_ioctl,
+	mmap:		agp_mmap,
+	open:		agp_open,
+	release:	agp_release,
+};
+
+static struct miscdevice agp_miscdev =
+{
+	AGPGART_MINOR,
+	AGPGART_MODULE_NAME,
+	&agp_fops
+};
+
+int __init agp_frontend_initialize(void)
+{
+	memset(&agp_fe, 0, sizeof(struct agp_front_data));
+	AGP_LOCK_INIT();
+
+	if (misc_register(&agp_miscdev)) {
+		printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR);
+		return -EIO;
+	}
+	return 0;
+}
+
+void agp_frontend_cleanup(void)
+{
+	misc_deregister(&agp_miscdev);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/bttv.c linux.18p8/drivers/char/bttv.c
--- linux.vanilla/drivers/char/bttv.c	Sat Sep  9 18:42:34 2000
+++ linux.18p8/drivers/char/bttv.c	Thu Aug 31 15:13:28 2000
@@ -1196,6 +1196,7 @@
 		*(ro++)=cpu_to_le32(btv->bus_vbi_even);
 		*(re++)=cpu_to_le32(BT848_RISC_JUMP);
 		*(re++)=cpu_to_le32(btv->bus_vbi_odd);
+		return;
 	}
 	if (ncr < 0) {	/* bitmap was pased */
 		memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE);
@@ -1307,8 +1308,8 @@
 
 	tvn=&tvnorms[btv->win.norm];
 	
-        btv->win.cropheight=tvn->sheight;
-        btv->win.cropwidth=tvn->swidth;
+/*        btv->win.cropheight=tvn->sheight;
+          btv->win.cropwidth=tvn->swidth; set somewhere else now */
 
 /*
 	if (btv->win.cropwidth>tvn->cropwidth)
@@ -1413,6 +1414,62 @@
  *	Set TSA5522 synthesizer frequency in 1/16 Mhz steps
  */
 
+static void reset_cropwin(struct bttv * btv)
+{
+        btv->win.cropx=0;
+        btv->win.cropy=0;
+        btv->win.cropheight=tvnorms[btv->win.norm].sheight;
+        btv->win.cropwidth=tvnorms[btv->win.norm].swidth;
+}                       
+
+static void clip_cropwin(struct bttv * btv, u16 width, u16 height)
+{
+        /* don't allow values beyond max */
+
+        if (btv->win.cropwidth>tvnorms[btv->win.norm].swidth)
+                btv->win.cropwidth=tvnorms[btv->win.norm].swidth;
+
+	if (btv->win.cropheight>tvnorms[btv->win.norm].sheight)
+	        btv->win.cropheight=tvnorms[btv->win.norm].sheight;
+
+        /* horizontal: downscaling only (bt848 limitation)*/
+	if (width>btv->win.cropwidth)
+                btv->win.cropwidth=width;
+
+        /* horizontal scaling is kinda limited by the registers
+         probably irrelevant */
+        if (btv->win.cropwidth>((65535UL+4096UL)*width)/4096UL)
+                btv->win.cropwidth = ((65535UL+4096UL)*width)/4096UL;
+
+        /* vertical: downscaling only (not mentioned in the specs
+         but doesnt work anyways */
+        if (height>btv->win.cropheight)
+                btv->win.cropheight = height;
+
+        if (btv->win.interlace == 0)
+        {
+                if (btv->win.cropheight>127UL*height)
+                        btv->win.cropheight = 127UL*height;
+/*                if (((127UL*512UL-1023UL)*height)/512UL>btv->win.cropheight)
+                  btv->win.cropheight = (127UL*512UL-1023UL)*height/512UL;*/
+        } else
+        {
+                if (btv->win.cropheight>2UL*127UL*height)
+                        btv->win.cropheight = 2UL*127UL*height;
+                btv->win.cropheight = (btv->win.cropheight/2)*2;  /*even number */
+/*                if (((127UL*512UL-1023UL)*height)/256UL>btv->win.cropheight)
+                        btv->win.cropheight = (127UL*512UL-1023UL)*height/256UL;*/
+        }
+        
+        if (btv->win.cropx>tvnorms[btv->win.norm].swidth-btv->win.cropwidth)
+                btv->win.cropx = tvnorms[btv->win.norm].swidth-btv->win.cropwidth;
+
+        if (btv->win.cropy>tvnorms[btv->win.norm].sheight-btv->win.cropheight)
+                btv->win.cropy = tvnorms[btv->win.norm].sheight-btv->win.cropheight;
+
+        return;
+}
+
 static void set_freq(struct bttv *btv, unsigned short freq)
 {
 	int fixme = freq; /* XXX */
@@ -1496,6 +1553,10 @@
 	 *	like QCIF has meaning as a capture.
 	 */
 	 
+
+        clip_cropwin(btv, mp->width, mp->height);
+        bt848_set_geo(btv, mp->width, mp->height, mp->format, 1);
+
 	/*
 	 *	Ok load up the BT848
 	 */
@@ -1602,7 +1663,7 @@
         audio(btv, AUDIO_UNMUTE);
         for (i=users=0; i<bttv_num; i++)
                 users+=bttvs[i].user;
-        if (users==1)
+        if (users==0)
                 find_vga();
         btv->fbuffer=NULL;
         if (!btv->fbuffer)
@@ -1721,6 +1782,7 @@
 			b.type = VID_TYPE_CAPTURE|
 				VID_TYPE_TELETEXT|
 				VID_TYPE_OVERLAY|
+                                VID_TYPE_SUBCAPTURE|
 				VID_TYPE_CLIPPING|
 				VID_TYPE_FRAMERAM|
 				VID_TYPE_SCALES|
@@ -1780,7 +1842,8 @@
 			btv->win.norm = v.norm;
                         make_vbitab(btv);
 			bt848_set_winsize(btv);
-			btv->channel=v.channel;
+                        reset_cropwin(btv);
+ 			btv->channel=v.channel;
 			return 0;
 		}
 		case VIDIOCGTUNER:
@@ -1905,6 +1968,7 @@
 			on=(btv->cap&3);
 			
 			bt848_cap(btv,0);
+                        clip_cropwin(btv, vw.width, vw.height);
 			bt848_set_winsize(btv);
 
 			/*
@@ -2226,6 +2290,8 @@
 				return -EIO;
                         if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING)
                                 return -EBUSY;
+
+                     
 		        return vgrab(btv, &vm);
 		}
 		
@@ -2263,7 +2329,38 @@
 			return 0;
 		}
 		
-	        case BTTV_BURST_ON:
+                case VIDIOCGCAPTURE:
+                {
+                        struct video_capture vc;
+                        vc.x=btv->win.cropx;
+                        vc.y=btv->win.cropy;
+                        vc.width=btv->win.cropwidth;
+                        vc.height=btv->win.cropheight;
+                        vc.decimation=0; /* not implemented at the moment */
+                        vc.flags=0; /* dito */
+                        if(copy_to_user((void *)arg, (void *)&vc, sizeof(vc)))
+                                return -EFAULT;
+                        return 0;
+                }
+
+                case VIDIOCSCAPTURE:
+                {
+                        struct video_capture vc;
+                        if(copy_from_user((void *) &vc, (void *) arg, sizeof(vc)))
+                             return -EFAULT;
+                        if (vc.x>tvnorms[btv->win.norm].swidth||
+                            vc.y>tvnorms[btv->win.norm].sheight||
+                            vc.width>tvnorms[btv->win.norm].swidth||
+                            vc.height>tvnorms[btv->win.norm].sheight)
+                                return -EFAULT;
+                        btv->win.cropx=vc.x;
+                        btv->win.cropy=(vc.y>>1)<<1; // make even
+                        btv->win.cropwidth=vc.width;
+                        btv->win.cropheight=vc.height;                        
+                        return 0;
+                }
+
+                case BTTV_BURST_ON:
 		{
 			tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2;
 			tvnorms[0].hdelayx1=186-BURSTOFFSET;
@@ -3444,6 +3541,7 @@
 					btv->grf = btv->grf_next;
                                         btv->risc_jmp[5]=cpu_to_le32(btv->gro);
 					btv->risc_jmp[11]=cpu_to_le32(btv->gre);
+                                        clip_cropwin(btv, btv->gwidth, btv->gheight);
 					bt848_set_geo(btv, btv->gwidth,
 						      btv->gheight,
 						      btv->gfmt, 0);
@@ -3451,7 +3549,9 @@
 					bt848_set_risc_jmps(btv);
 					btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
 					btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
-                                        bt848_set_geo(btv, btv->win.width, 
+					clip_cropwin(btv, btv->win.width, 
+                                                        btv->win.height);
+					bt848_set_geo(btv, btv->win.width, 
 						      btv->win.height,
 						      btv->win.color_fmt, 0);
 				}
@@ -3463,7 +3563,8 @@
 			        btv->risc_jmp[5]=cpu_to_le32(btv->gro);
 				btv->risc_jmp[11]=cpu_to_le32(btv->gre);
 				btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP);
-				bt848_set_geo(btv, btv->gwidth, btv->gheight,
+                                clip_cropwin(btv, btv->gwidth, btv->gheight);
+                                bt848_set_geo(btv, btv->gwidth, btv->gheight,
 					      btv->gfmt, 0);
 			}
 		}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/bttv.h linux.18p8/drivers/char/bttv.h
--- linux.vanilla/drivers/char/bttv.h	Wed May  3 22:26:11 2000
+++ linux.18p8/drivers/char/bttv.h	Fri Sep 15 15:06:01 2000
@@ -40,7 +40,7 @@
 #define VBIBUF_SIZE     65536
 
 /* maximum needed buffer size for extended VBI frame mode capturing */
-#define BTTV_MAX_FBUF	0x190000
+#define BTTV_MAX_FBUF   0x208000
 
 #ifdef __KERNEL__
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/buz.c linux.18p8/drivers/char/buz.c
--- linux.vanilla/drivers/char/buz.c	Fri Apr 21 12:45:51 2000
+++ linux.18p8/drivers/char/buz.c	Thu Aug 31 15:14:49 2000
@@ -201,6 +201,7 @@
 				mem_map_reserve(MAP_NR(mem + off));
 			DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem)));
 		} else {
+			v4l_fbuffer_free(zr);
 			return -ENOBUFS;
 		}
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/cpia.c linux.18p8/drivers/char/cpia.c
--- linux.vanilla/drivers/char/cpia.c	Sun Jun 11 21:44:12 2000
+++ linux.18p8/drivers/char/cpia.c	Tue Sep  5 23:08:25 2000
@@ -3,9 +3,9 @@
  *
  * Supports CPiA based Video Camera's.
  *
- * (C) 1999 Peter Pregler,
- *          Scott J. Bertin,
- *          Johannes Erdfelt
+ * (C) Copyright 1999-2000 Peter Pregler,
+ * (C) Copyright 1999-2000 Scott J. Bertin,
+ * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@valinux.com
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,28 +22,28 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+/* #define _CPIA_DEBUG_		define for verbose debug output */
 #include <linux/config.h>
 
 #include <linux/module.h>
+#include <linux/version.h>
 #include <linux/init.h>
-#include <linux/wrapper.h>
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
-#include <linux/slab.h>
 #include <linux/delay.h>
-#include <linux/smp_lock.h>
+#include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/ctype.h>
-#include <linux/videodev.h>
+#include <linux/pagemap.h>
 #include <asm/io.h>
 #include <asm/semaphore.h>
+#include <linux/wrapper.h>
 
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
 
-#undef _CPIA_DEBUG_		/* define for verbose debug output */
-#include <linux/cpia.h>
+#include "cpia.h"
 
 #ifdef CONFIG_VIDEO_CPIA_PP
 extern int cpia_pp_init(void);
@@ -53,7 +53,7 @@
 #endif
 
 #ifdef MODULE
-MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com>");
+MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
 MODULE_SUPPORTED_DEVICE("video");
 #endif
@@ -97,6 +97,7 @@
 #define CPIA_COMMAND_I2CRead		(INPUT | CPIA_MODULE_SYSTEM | 13)
 
 #define CPIA_COMMAND_GetVPVersion	(INPUT | CPIA_MODULE_VP_CTRL | 1)
+#define CPIA_COMMAND_ResetFrameCounter	(INPUT | CPIA_MODULE_VP_CTRL | 2)
 #define CPIA_COMMAND_SetColourParams	(OUTPUT | CPIA_MODULE_VP_CTRL | 3)
 #define CPIA_COMMAND_SetExposure	(OUTPUT | CPIA_MODULE_VP_CTRL | 4)
 #define CPIA_COMMAND_SetColourBalance	(OUTPUT | CPIA_MODULE_VP_CTRL | 6)
@@ -127,6 +128,7 @@
 #define CPIA_COMMAND_SetYUVThresh	(OUTPUT | CPIA_MODULE_CAPTURE | 12)
 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
 #define CPIA_COMMAND_DiscardFrame	(OUTPUT | CPIA_MODULE_CAPTURE | 14)
+#define CPIA_COMMAND_GrabReset		(OUTPUT | CPIA_MODULE_CAPTURE | 15)
 
 #define CPIA_COMMAND_OutputRS232	(OUTPUT | CPIA_MODULE_DEBUG | 1)
 #define CPIA_COMMAND_AbortProcess	(OUTPUT | CPIA_MODULE_DEBUG | 4)
@@ -135,117 +137,7 @@
 #define CPIA_COMMAND_StartDummyDtream	(OUTPUT | CPIA_MODULE_DEBUG | 8)
 #define CPIA_COMMAND_AbortStream	(OUTPUT | CPIA_MODULE_DEBUG | 9)
 #define CPIA_COMMAND_DownloadDRAM	(OUTPUT | CPIA_MODULE_DEBUG | 10)
-
-struct cam_params {
-	struct {
-		u8 firmwareVersion;
-		u8 firmwareRevision;
-		u8 vcVersion;
-		u8 vcRevision;
-	} version;
-	struct {
-		u16 vendor;
-		u16 product;
-		u16 deviceRevision;
-	} pnpID;
-	struct {
-		u8 vpVersion;
-		u8 vpRevision;
-		u16 cameraHeadID;
-	} vpVersion;
-	struct {
-		u8 systemState;
-		u8 grabState;
-		u8 streamState;
-		u8 fatalError;
-		u8 cmdError;
-		u8 debugFlags;
-		u8 vpStatus;
-		u8 errorCode;
-	} status;
-	struct {
-		u8 brightness;
-		u8 contrast;
-		u8 saturation;
-	} colourParams;
-	struct {
-		u8 gainMode;
-		u8 expMode;
-		u8 compMode;
-		u8 centreWeight;
-		u8 gain;
-		u8 fineExp;
-		u8 coarseExpLo;
-		u8 coarseExpHi;
-		u8 redComp;
-		u8 green1Comp;
-		u8 green2Comp;
-		u8 blueComp;
-	} exposure;
-	struct {
-		u8 balanceMode;
-		u8 redGain;
-		u8 greenGain;
-		u8 blueGain;
-	} colourBalance;
-	struct {
-		u8 divisor;
-		u8 baserate;
-	} sensorFps;
-	struct {
-		u8 gain1;
-		u8 gain2;
-		u8 gain4;
-		u8 gain8;
-	} apcor;
-	struct {
-		u8 flickerMode;
-		u8 coarseJump;
-		u8 allowableOverExposure;
-	} flickerControl;
-	struct {
-		u8 gain1;
-		u8 gain2;
-		u8 gain4;
-		u8 gain8;
-	} vlOffset;
-	struct {
-		u8 mode;
-		u8 decimation;
-	} compression;
-	struct {
-		u8 frTargeting;
-		u8 targetFR;
-		u8 targetQ;
-	} compressionTarget;
-	struct {
-		u8 yThreshold;
-		u8 uvThreshold;
-	} yuvThreshold;
-	struct {
-		u8 hysteresis;
-		u8 threshMax;
-		u8 smallStep;
-		u8 largeStep;
-		u8 decimationHysteresis;
-		u8 frDiffStepThresh;
-		u8 qDiffStepThresh;
-		u8 decimationThreshMod;
-	} compressionParams;
-	struct {
-		u8 videoSize;		/* CIF/QCIF */
-		u8 subSample;
-		u8 yuvOrder;
-	} format;
-	struct {
-		u8 colStart;		/* skip first 8*colStart pixels */
-		u8 colEnd;		/* finish at 8*colEnd pixels */
-		u8 rowStart;		/* skip first 4*rowStart lines */
-		u8 rowEnd;		/* finish at 4*rowEnd lines */
-	} roi;
-	u8 ecpTiming;
-	u8 streamStartLine;
-};
+#define CPIA_COMMAND_Null		(OUTPUT | CPIA_MODULE_DEBUG | 11)
 
 enum {
 	FRAME_READY,		/* Ready to grab into */
@@ -254,24 +146,6 @@
 	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
 };
 
-#define FRAME_NUM	2	/* double buffering for now */
-struct cpia_frame {
-	u8 *data;
-	int count;
-	int width;
-	int height;
-	volatile int state;
-};
-
-enum v4l_camstates {
-	CPIA_V4L_IDLE = 0,
-	CPIA_V4L_ERROR,
-	CPIA_V4L_COMMAND,
-	CPIA_V4L_GRABBING,
-	CPIA_V4L_STREAMING,
-	CPIA_V4L_STREAMING_PAUSED,
-};
-
 #define COMMAND_NONE			0x0000
 #define COMMAND_SETCOMPRESSION		0x0001
 #define COMMAND_SETCOMPRESSIONTARGET	0x0002
@@ -288,45 +162,7 @@
 #define COMMAND_SETAPCOR		0x1000
 #define COMMAND_SETFLICKERCTRL		0x2000
 #define COMMAND_SETVLOFFSET		0x4000
-
-struct cam_data {
-	int index;			/* which camera is this */
-        struct semaphore busy_lock;     /* guard against SMP multithreading */
-	struct cpia_camera_ops *ops;	/* lowlevel driver operations */
-	void *lowlevel_data;		/* private data for lowlevel driver */
-	u8 *raw_image;			/* buffer for raw image data */
-	struct cpia_frame decompressed_frame;
-                                        /* buffer to hold decompressed frame */
-	int image_size;		        /* sizeof last decompressed image */
-	int open_count;			/* # of process that have camera open */
-				/* camera status */
-	int fps;			/* actual fps reported by the camera */
-	int transfer_rate;		/* transfer rate from camera in kB/s */
-	u8 mainsFreq;			/* for flicker control */
-
-				/* proc interface */
-	struct semaphore param_lock;	/* params lock for this camera */
-	struct cam_params params;	/* camera settings */
-	struct proc_dir_entry *proc_entry;	/* /proc/cpia/videoX */
-	
-					/* v4l */
-	int video_size;			/* VIDEO_SIZE_ */
-	volatile enum v4l_camstates camstate;	/* v4l layer status */
-	struct video_device vdev;	/* v4l videodev */
-	struct video_picture vp;	/* v4l camera settings */
-	struct video_window vw;		/* v4l capture area */
-
-				/* mmap interface */
-	int curframe;			/* the current frame to grab into */
-	u8 *frame_buf;			/* frame buffer data */
-        struct cpia_frame frame[FRAME_NUM];
-				/* FRAME_NUM-buffering, so we need a array */
-
-        int first_frame;
-	volatile u32 cmd_queue;		/* queued commands */
-};
-
-static struct cam_data *camera[CPIA_MAXCAMS] ={ [0 ... CPIA_MAXCAMS-1] = NULL };
+#define COMMAND_SETLIGHTS               0x8000 /* GA 04/14/00 */
 
 /* Developer's Guide Table 5 p 3-34
  * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
@@ -338,6 +174,7 @@
 /* forward declaration of local function */
 static void reset_camera_struct(struct cam_data *cam);
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 /**********************************************************************
  *
  * Memory management
@@ -357,64 +194,134 @@
 	pte_t *ptep, pte;
 
 	pgd = pgd_offset(current->mm, adr);
-	if (pgd_none(*pgd)) return 0;
+	if (pgd_none(*pgd))
+		return 0;
 	pmd = pmd_offset(pgd, adr);
-	if (pmd_none(*pmd)) return 0;
+	if (pmd_none(*pmd))
+		return 0;
 	ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
 	pte = *ptep;
-	if(pte_present(pte))
-		return 
-		  virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
+	if (pte_present(pte))
+		return virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
 	return 0;
 }
 
-static inline unsigned long kvirt_to_phys(unsigned long adr) 
+static inline unsigned long kvirt_to_pa(unsigned long adr) 
 {
 	return uvirt_to_phys(VMALLOC_VMADDR(adr));
 }
 
-static void * rvmalloc(unsigned long size)
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) */
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet - jerdfelt
+ *
+ **********************************************************************/
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+	unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+
+	if (!pgd_none(*pgd)) {
+		pmd = pmd_offset(pgd, adr);
+		if (!pmd_none(*pmd)) {
+			ptep = pte_offset(pmd, adr);
+			pte = *ptep;
+			if (pte_present(pte))
+				ret = page_address(pte_page(pte)) |
+				      (adr & (PAGE_SIZE-1));
+		}
+	}
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long va, kva, ret;
+
+	va = VMALLOC_VMADDR(adr);
+	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = __pa(kva);
+	return ret;
+}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) */
+
+static void *rvmalloc(unsigned long size)
 {
-	void * mem;
+	void *mem;
 	unsigned long adr, page;
 
+	/* Round it off to PAGE_SIZE */
 	size += (PAGE_SIZE - 1);
 	size &= ~(PAGE_SIZE - 1);
 
-	mem=vmalloc(size);
-	if (mem) {
-		/* Clear the ram out, no junk to the user */
-		memset(mem, 0, size);
-		adr=(unsigned long) mem;
-		while (size > 0) {
-			page = kvirt_to_phys(adr);
-			mem_map_reserve(MAP_NR(phys_to_virt(page)));
-			adr+=PAGE_SIZE;
-			if (size > PAGE_SIZE) size-=PAGE_SIZE;
-			else  size=0;
-		}
+	mem = vmalloc(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		mem_map_reserve(MAP_NR(phys_to_virt(page)));
+#else
+		mem_map_reserve(MAP_NR(__va(page)));
+#endif
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
 	}
+
 	return mem;
 }
 
-static void rvfree(void * mem, unsigned long size)
+static void rvfree(void *mem, unsigned long size)
 {
 	unsigned long adr, page;
-        
+
+	if (!mem)
+		return;
+
 	size += (PAGE_SIZE - 1);
 	size &= ~(PAGE_SIZE - 1);
 
-	if (mem) {
-		adr=(unsigned long) mem;
-		while (size > 0) {
-			page = kvirt_to_phys(adr);
-			mem_map_unreserve(MAP_NR(phys_to_virt(page)));
-			adr+=PAGE_SIZE;
-			if (size > PAGE_SIZE) size-=PAGE_SIZE;
-			else size=0;
-		}
-		vfree(mem);
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		mem_map_unreserve(MAP_NR(phys_to_virt(page)));
+#else
+		mem_map_unreserve(MAP_NR(__va(page)));
+#endif
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
 	}
+	vfree(mem);
 }
 
 /**********************************************************************
@@ -422,6 +329,7 @@
  * /proc interface
  *
  **********************************************************************/
+#ifdef CONFIG_PROC_FS
 static struct proc_dir_entry *cpia_proc_root=NULL;
 
 static int cpia_read_proc(char *page, char **start, off_t off,
@@ -432,7 +340,7 @@
 	struct cam_data *cam = data;
 	char tmpstr[20];
 
-	/* IMPORTANT: This output MUST be kept under 4k (FIXME: PAGE_SIZE?)
+	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
 	 *            or we need to get more sophisticated. */
 
 	out += sprintf(out, "read-only\n-----------------------\n");
@@ -467,22 +375,23 @@
 	               cam->params.status.vpStatus);
 	out += sprintf(out, "error_code:               %#04x\n",
 	               cam->params.status.errorCode);
+	/* GA 04/14/00 - QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "button:                   %4d\n",
+		               cam->params.qx3.button);
+		out += sprintf(out, "cradled:                  %4d\n",
+		               cam->params.qx3.cradled);
+	}
 	out += sprintf(out, "video_size:               %s\n",
 	               cam->params.format.videoSize == VIDEOSIZE_CIF ?
 		       "CIF " : "QCIF");
-	out += sprintf(out, "sub_sample:               %s\n",
-	               cam->params.format.subSample == SUBSAMPLE_420 ?
-		       "420" : "422");
-	out += sprintf(out, "yuv_order:                %s\n",
-	               cam->params.format.yuvOrder == YUVORDER_YUYV ?
-		       "YUYV" : "UYVY");
 	out += sprintf(out, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
 	               cam->params.roi.colStart*8,
 	               cam->params.roi.rowStart*4,
 	               cam->params.roi.colEnd*8,
 	               cam->params.roi.rowEnd*4);
-	out += sprintf(out, "actual_fps:               %d\n", cam->fps);
-	out += sprintf(out, "transfer_rate:            %dkB/s\n",
+	out += sprintf(out, "actual_fps:               %3d\n", cam->fps);
+	out += sprintf(out, "transfer_rate:            %4dkB/s\n",
 	               cam->transfer_rate);
 	
 	out += sprintf(out, "\nread-write\n");
@@ -490,13 +399,13 @@
 	               "       max   default  comment\n");
 	out += sprintf(out, "brightness:             %8d  %8d  %8d  %8d\n",
 	               cam->params.colourParams.brightness, 0, 100, 50);
-	if(cam->params.version.firmwareVersion == 1 &&
-	   cam->params.version.firmwareRevision == 2) {
+	if (cam->params.version.firmwareVersion == 1 &&
+	   cam->params.version.firmwareRevision == 2)
 		/* 1-02 firmware limits contrast to 80 */
 		tmp = 80;
-	} else {
+	else
 		tmp = 96;
-	}
+
 	out += sprintf(out, "contrast:               %8d  %8d  %8d  %8d"
 	               "  steps of 8\n",
 	               cam->params.colourParams.contrast, 0, tmp, 48);
@@ -510,21 +419,20 @@
 	               2*cam->params.streamStartLine, 0,
 		       cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
 		       cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
+	out += sprintf(out, "sub_sample:             %8s  %8s  %8s  %8s\n",
+	               cam->params.format.subSample == SUBSAMPLE_420 ?
+		       "420" : "422", "420", "422", "422");
+	out += sprintf(out, "yuv_order:              %8s  %8s  %8s  %8s\n",
+	               cam->params.format.yuvOrder == YUVORDER_YUYV ?
+		       "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
 	out += sprintf(out, "ecp_timing:             %8s  %8s  %8s  %8s\n",
 	               cam->params.ecpTiming ? "slow" : "normal", "slow",
 		       "normal", "normal");
 
-	switch(cam->params.colourBalance.balanceMode) {
-	case 1:
-	  // FIXME case 3:
-		sprintf(tmpstr, "manual");
-		break;
-	case 2:
+	if (cam->params.colourBalance.balanceModeIsAuto) {
 		sprintf(tmpstr, "auto");
-		break;
-	default:
-		sprintf(tmpstr, "unknown");
-		break;
+	} else {
+		sprintf(tmpstr, "manual");
 	}
 	out += sprintf(out, "color_balance_mode:     %8s  %8s  %8s"
 		       "  %8s\n",  tmpstr, "manual", "auto", "auto");
@@ -535,20 +443,20 @@
 	out += sprintf(out, "blue_gain:              %8d  %8d  %8d  %8d\n",
 	               cam->params.colourBalance.blueGain, 0, 212, 92);
 
-	if(cam->params.version.firmwareVersion == 1 &&
-	   cam->params.version.firmwareRevision == 2) {
+	if (cam->params.version.firmwareVersion == 1 &&
+	   cam->params.version.firmwareRevision == 2)
 		/* 1-02 firmware limits gain to 2 */
 		sprintf(tmpstr, "%8d  %8d", 1, 2);
-	} else {
+	else
 		sprintf(tmpstr, "%8d  %8d", 1, 8);
-	}
-	if(cam->params.exposure.gainMode == 0) {
+
+	if (cam->params.exposure.gainMode == 0)
 		out += sprintf(out, "max_gain:                unknown  %18s"
 		               "  %8d  powers of 2\n", tmpstr, 2); 
-	} else {
+	else
 		out += sprintf(out, "max_gain:               %8d  %18s  %8d  powers of 2\n", 
 		               1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
-	}
+
 	switch(cam->params.exposure.expMode) {
 	case 1:
 	case 3:
@@ -568,22 +476,22 @@
 	               "off", "on", "on");
 	out += sprintf(out, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 possible\n",
 	               1<<cam->params.exposure.gain, 1, 1);
-	if(cam->params.version.firmwareVersion == 1 &&
-	   cam->params.version.firmwareRevision == 2) {
+	if (cam->params.version.firmwareVersion == 1 &&
+	   cam->params.version.firmwareRevision == 2)
 		/* 1-02 firmware limits fineExp to 127 */
 		tmp = 255;
-	} else {
+	else
 		tmp = 511;
-	}
+
 	out += sprintf(out, "fine_exp:               %8d  %8d  %8d  %8d\n",
 	               cam->params.exposure.fineExp*2, 0, tmp, 0);
-	if(cam->params.version.firmwareVersion == 1 &&
-	   cam->params.version.firmwareRevision == 2) {
+	if (cam->params.version.firmwareVersion == 1 &&
+	   cam->params.version.firmwareRevision == 2)
 		/* 1-02 firmware limits coarseExpHi to 0 */
 		tmp = 255;
-	} else {
+	else
 		tmp = 65535;
-	}
+
 	out += sprintf(out, "coarse_exp:             %8d  %8d  %8d"
 		       "  %8d\n", cam->params.exposure.coarseExpLo+
 		       256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
@@ -637,9 +545,9 @@
 		break;
 	}
 	out += sprintf(out, "    none,auto,manual      auto\n");
-	out += sprintf(out, "decimation:             %8s  %8s  %8s  %8s\n",
+	out += sprintf(out, "decimation_enable:      %8s  %8s  %8s  %8s\n",
         	       cam->params.compression.decimation == 
-		       DECIMATION_ENAB ? "on":"off", "off", "off",
+		       DECIMATION_ENAB ? "on":"off", "off", "on",
 		       "off");
 	out += sprintf(out, "compression_target:    %9s %9s %9s %9s\n",
 	               cam->params.compressionTarget.frTargeting  == 
@@ -647,13 +555,13 @@
 		       "framerate":"quality",
 		       "framerate", "quality", "quality");
 	out += sprintf(out, "target_framerate:       %8d  %8d  %8d  %8d\n",
-	               cam->params.compressionTarget.targetFR, 0, 30, 7);
+	               cam->params.compressionTarget.targetFR, 1, 30, 15);
 	out += sprintf(out, "target_quality:         %8d  %8d  %8d  %8d\n",
-	               cam->params.compressionTarget.targetQ, 0, 255, 10);
+	               cam->params.compressionTarget.targetQ, 1, 64, 5);
 	out += sprintf(out, "y_threshold:            %8d  %8d  %8d  %8d\n",
-	               cam->params.yuvThreshold.yThreshold, 0, 31, 15);
+	               cam->params.yuvThreshold.yThreshold, 0, 31, 6);
 	out += sprintf(out, "uv_threshold:           %8d  %8d  %8d  %8d\n",
-	               cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
+	               cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
 	out += sprintf(out, "hysteresis:             %8d  %8d  %8d  %8d\n",
 	               cam->params.compressionParams.hysteresis, 0, 255, 3);
 	out += sprintf(out, "threshold_max:          %8d  %8d  %8d  %8d\n",
@@ -674,15 +582,25 @@
 	out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
 	               cam->params.compressionParams.decimationThreshMod,
 		       0, 255, 2);
-	
+
+	/* GA 04/14/00 - QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.toplight ? "on" : "off",
+			       "off", "on", "off");
+		out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.bottomlight ? "on" : "off",
+			       "off", "on", "off");
+	}
+
 	len = out - page;
 	len -= off;
 	if (len < count) {
 		*eof = 1;
 		if (len <= 0) return 0;
-	} else {
+	} else
 		len = count;
-	}
+
 	*start = page + off;
 	return len;
 }
@@ -692,16 +610,14 @@
 {
 	struct cam_data *cam = data;
 	struct cam_params new_params;
-	int retval, len, colon_found;
+	int retval, find_colon;
 	int size = count;
-	char *p;
 	unsigned long val;
 	u32 command_flags = 0;
 	u8 new_mains;
 	
-	if(down_interruptible(&cam->param_lock)) {
+	if (down_interruptible(&cam->param_lock))
 		return -ERESTARTSYS;
-	}
 	
 	/*
 	 * Skip over leading whitespace
@@ -714,106 +630,112 @@
 	memcpy(&new_params, &cam->params, sizeof(struct cam_params));
 	new_mains = cam->mainsFreq;
 	
-#define MATCH(x) (len=strlen(x), len <= count && strncmp(buffer, x, len) == 0)
+#define MATCH(x) \
+	({ \
+		int _len = strlen(x), _ret, _colon_found; \
+		_ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
+		if (_ret) { \
+			buffer += _len; \
+			count -= _len; \
+			if (find_colon) { \
+				_colon_found = 0; \
+				while (count && (*buffer == ' ' || *buffer == '\t' || \
+				       (!_colon_found && *buffer == ':'))) { \
+					if (*buffer == ':')  \
+						_colon_found = 1; \
+					--count; \
+					++buffer; \
+				} \
+				if (!count || !_colon_found) \
+					retval = -EINVAL; \
+				find_colon = 0; \
+			} \
+		} \
+		_ret; \
+	})
 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
                                new_params.version.firmwareRevision == (y))
 #define VALUE \
-	simple_strtoul(buffer, &p, 0); \
-	if(p == buffer) { \
-		retval = -EINVAL; \
-	} else { \
-		count -= p-buffer; \
-		buffer = p; \
-	}
-#define FIND_VALUE \
-	buffer += len;\
-	count -= len; \
-	colon_found=0; \
-	while(count && (*buffer == ' ' || *buffer == '\t' || \
-	                (!colon_found && *buffer == ':'))) { \
-		if(*buffer == ':') colon_found = 1; \
-		--count; \
-		++buffer; \
-	} \
-	if(!count || !colon_found) { \
-		retval = -EINVAL; \
-	}
-#define FIND_END \
-	if(retval == 0) { \
-		while(count && isspace(*buffer) && *buffer != '\n'){ \
-			--count; \
-			++buffer; \
+	({ \
+		char *_p; \
+		unsigned long int _ret; \
+		_ret = simple_strtoul(buffer, &_p, 0); \
+		if (_p == buffer) \
+			retval = -EINVAL; \
+		else { \
+			count -= _p - buffer; \
+			buffer = _p; \
 		} \
-		if(count) { \
-			if(*buffer != '\n' && *buffer != ';') { \
-				retval = -EINVAL; \
-			} else { \
-				--count; \
-				++buffer; \
-			} \
-		} \
-	}
+		_ret; \
+	})
+
 	retval = 0;
-	while(count && !retval) {
-		if(MATCH("brightness")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 100)
-					new_params.colourParams.brightness=val;
-				else retval = -EINVAL;
+	while (count && !retval) {
+		find_colon = 1;
+		if (MATCH("brightness")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 100)
+					new_params.colourParams.brightness = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOLOURPARAMS;
-			FIND_END
-		} else if(MATCH("contrast")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 100) {
+		} else if (MATCH("contrast")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 100) {
 					/* contrast is in steps of 8, so round*/
 					val = ((val + 3) / 8) * 8;
 					/* 1-02 firmware limits contrast to 80*/
-					if(FIRMWARE_VERSION(1,2) && val > 80)
+					if (FIRMWARE_VERSION(1,2) && val > 80)
 						val = 80;
+
 					new_params.colourParams.contrast = val;
-				} else retval = -EINVAL;
+				} else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOLOURPARAMS;
-			FIND_END
-		} else if(MATCH("saturation")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 100)
-					new_params.colourParams.saturation=val;
-				else retval = -EINVAL;
+		} else if (MATCH("saturation")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 100)
+					new_params.colourParams.saturation = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOLOURPARAMS;
-			FIND_END
-		} else if(MATCH("sensor_fps")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
+		} else if (MATCH("sensor_fps")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
 				/* find values so that sensorFPS is minimized,
 				 * but >= val */
-				if(val > 30) {
+				if (val > 30)
 					retval = -EINVAL;
-				} else if(val > 25) {
+				else if (val > 25) {
 					new_params.sensorFps.divisor = 0;
 					new_params.sensorFps.baserate = 1;
-				} else if(val > 15) {
+				} else if (val > 15) {
 					new_params.sensorFps.divisor = 0;
 					new_params.sensorFps.baserate = 0;
-				} else if(val > 12) {
+				} else if (val > 12) {
 					new_params.sensorFps.divisor = 1;
 					new_params.sensorFps.baserate = 1;
-				} else if(val > 7) {
+				} else if (val > 7) {
 					new_params.sensorFps.divisor = 1;
 					new_params.sensorFps.baserate = 0;
-				} else if(val > 6) {
+				} else if (val > 6) {
 					new_params.sensorFps.divisor = 2;
 					new_params.sensorFps.baserate = 1;
-				} else if(val > 3) {
+				} else if (val > 3) {
 					new_params.sensorFps.divisor = 2;
 					new_params.sensorFps.baserate = 0;
 				} else {
@@ -825,89 +747,100 @@
 					flicker_jumps[new_mains]
 					[new_params.sensorFps.baserate]
 					[new_params.sensorFps.divisor];
-				if(new_params.flickerControl.flickerMode)
+				if (new_params.flickerControl.flickerMode)
 					command_flags |= COMMAND_SETFLICKERCTRL;
 			}
 			command_flags |= COMMAND_SETSENSORFPS;
-			FIND_END
-		} else if(MATCH("stream_start_line")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
+		} else if (MATCH("stream_start_line")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
 				int max_line = 288;
-				if(new_params.format.videoSize==VIDEOSIZE_QCIF)
+
+				if (new_params.format.videoSize == VIDEOSIZE_QCIF)
 					max_line = 144;
-				if(val <= max_line)
+				if (val <= max_line)
 					new_params.streamStartLine = val/2;
-				else retval = -EINVAL;
+				else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("ecp_timing")) {
-			FIND_VALUE
-			if(!retval && MATCH("normal")) {
-				buffer += len;
-				count -= len;
+		} else if (MATCH("sub_sample")) {
+			if (!retval && MATCH("420"))
+				new_params.format.subSample = SUBSAMPLE_420;
+			else if (!retval && MATCH("422"))
+				new_params.format.subSample = SUBSAMPLE_422;
+			else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETFORMAT;
+		} else if (MATCH("yuv_order")) {
+			if (!retval && MATCH("YUYV"))
+				new_params.format.yuvOrder = YUVORDER_YUYV;
+			else if (!retval && MATCH("UYVY"))
+				new_params.format.yuvOrder = YUVORDER_UYVY;
+			else
+				retval = -EINVAL;
+
+			command_flags |= COMMAND_SETFORMAT;
+		} else if (MATCH("ecp_timing")) {
+			if (!retval && MATCH("normal"))
 				new_params.ecpTiming = 0;
-			} else if(!retval && MATCH("slow")) {
-				buffer += len;
-				count -= len;
+			else if (!retval && MATCH("slow"))
 				new_params.ecpTiming = 1;
-			} else {
+			else
 				retval = -EINVAL;
-			}
+
 			command_flags |= COMMAND_SETECPTIMING;
-			FIND_END
-		} else if(MATCH("color_balance_mode")) {
-			FIND_VALUE
-			if(!retval && MATCH("manual")) {
-				buffer += len;
-				count -= len;
-				new_params.colourBalance.balanceMode=1;
-			} else if(!retval && MATCH("auto")) {
-				buffer += len;
-				count -= len;
-				new_params.colourBalance.balanceMode=2;
-			} else {
+		} else if (MATCH("color_balance_mode")) {
+			if (!retval && MATCH("manual"))
+				new_params.colourBalance.balanceModeIsAuto = 0;
+			else if (!retval && MATCH("auto"))
+				new_params.colourBalance.balanceModeIsAuto = 1;
+			else
 				retval = -EINVAL;
-			}
+
 			command_flags |= COMMAND_SETCOLOURBALANCE;
-			FIND_END
-		} else if(MATCH("red_gain")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 212)
+		} else if (MATCH("red_gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 212)
 					new_params.colourBalance.redGain = val;
-				else retval = -EINVAL;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOLOURBALANCE;
-			FIND_END
-		} else if(MATCH("green_gain")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 212)
-					new_params.colourBalance.greenGain=val;
-				else retval = -EINVAL;
+		} else if (MATCH("green_gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 212)
+					new_params.colourBalance.greenGain = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOLOURBALANCE;
-			FIND_END
-		} else if(MATCH("blue_gain")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 212)
+		} else if (MATCH("blue_gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 212)
 					new_params.colourBalance.blueGain = val;
-				else retval = -EINVAL;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOLOURBALANCE;
-			FIND_END
-		} else if(MATCH("max_gain")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
+		} else if (MATCH("max_gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
 				/* 1-02 firmware limits gain to 2 */
-				if(FIRMWARE_VERSION(1,2) && val > 2)
+				if (FIRMWARE_VERSION(1,2) && val > 2)
 					val = 2;
 				switch(val) {
 				case 1:
@@ -928,44 +861,32 @@
 				}
 			}
 			command_flags |= COMMAND_SETEXPOSURE;
-			FIND_END
-		} else if(MATCH("exposure_mode")) {
-			FIND_VALUE
-			if(!retval && MATCH("auto")) {
-				buffer += len;
-				count -= len;
+		} else if (MATCH("exposure_mode")) {
+			if (!retval && MATCH("auto"))
 				new_params.exposure.expMode = 2;
-			} else if(!retval && MATCH("manual")) {
-				buffer += len;
-				count -= len;
-				if(new_params.exposure.expMode == 2)
+			else if (!retval && MATCH("manual")) {
+				if (new_params.exposure.expMode == 2)
 					new_params.exposure.expMode = 3;
 				new_params.flickerControl.flickerMode = 0;
 				command_flags |= COMMAND_SETFLICKERCTRL;
-			} else {
+			} else
 				retval = -EINVAL;
-			}
+
 			command_flags |= COMMAND_SETEXPOSURE;
-			FIND_END
-		} else if(MATCH("centre_weight")) {
-			FIND_VALUE
-			if(!retval && MATCH("on")) {
-				buffer += len;
-				count -= len;
+		} else if (MATCH("centre_weight")) {
+			if (!retval && MATCH("on"))
 				new_params.exposure.centreWeight = 1;
-			} else if(!retval && MATCH("off")) {
-				buffer += len;
-				count -= len;
+			else if (!retval && MATCH("off"))
 				new_params.exposure.centreWeight = 2;
-			} else {
+			else
 				retval = -EINVAL;
-			}
+
 			command_flags |= COMMAND_SETEXPOSURE;
-			FIND_END
-		} else if(MATCH("gain")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
+		} else if (MATCH("gain")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
 				switch(val) {
 				case 1:
 					new_params.exposure.gain = 0;
@@ -996,35 +917,36 @@
 					break;
 				}
 				command_flags |= COMMAND_SETEXPOSURE;
-				if(new_params.exposure.gain >
-				   new_params.exposure.gainMode-1)
+				if (new_params.exposure.gain >
+				    new_params.exposure.gainMode-1)
 					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("fine_exp")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val < 256) {
+		} else if (MATCH("fine_exp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val < 256) {
 					/* 1-02 firmware limits fineExp to 127*/
-					if(FIRMWARE_VERSION(1,2) && val > 127)
+					if (FIRMWARE_VERSION(1,2) && val > 127)
 						val = 127;
 					new_params.exposure.fineExp = val;
 					new_params.exposure.expMode = 1;
 					command_flags |= COMMAND_SETEXPOSURE;
 					new_params.flickerControl.flickerMode = 0;
 					command_flags |= COMMAND_SETFLICKERCTRL;
-				} else retval = -EINVAL;
+				} else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("coarse_exp")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val < 65536) {
+		} else if (MATCH("coarse_exp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val < 65536) {
 					/* 1-02 firmware limits
 					 * coarseExp to 255 */
-					if(FIRMWARE_VERSION(1,2) && val > 255)
+					if (FIRMWARE_VERSION(1,2) && val > 255)
 						val = 255;
 					new_params.exposure.coarseExpLo =
 						val & 0xff;
@@ -1034,353 +956,398 @@
 					command_flags |= COMMAND_SETEXPOSURE;
 					new_params.flickerControl.flickerMode = 0;
 					command_flags |= COMMAND_SETFLICKERCTRL;
-				} else retval = -EINVAL;
+				} else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("red_comp")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val >= 220 && val <= 255) {
+		} else if (MATCH("red_comp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val >= 220 && val <= 255) {
 					new_params.exposure.redComp = val;
 					command_flags |= COMMAND_SETEXPOSURE;
-				} else retval = -EINVAL;
+				} else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("green1_comp")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val >= 214 && val <= 255) {
+		} else if (MATCH("green1_comp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val >= 214 && val <= 255) {
 					new_params.exposure.green1Comp = val;
 					command_flags |= COMMAND_SETEXPOSURE;
-				} else retval = -EINVAL;
+				} else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("green2_comp")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val >= 214 && val <= 255) {
+		} else if (MATCH("green2_comp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val >= 214 && val <= 255) {
 					new_params.exposure.green2Comp = val;
 					command_flags |= COMMAND_SETEXPOSURE;
-				} else retval = -EINVAL;
+				} else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("blue_comp")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val >= 230 && val <= 255) {
+		} else if (MATCH("blue_comp")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val >= 230 && val <= 255) {
 					new_params.exposure.blueComp = val;
 					command_flags |= COMMAND_SETEXPOSURE;
-				} else retval = -EINVAL;
+				} else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("apcor_gain1")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
+		} else if (MATCH("apcor_gain1")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
 				command_flags |= COMMAND_SETAPCOR;
-				if(val <= 0xff) new_params.apcor.gain1 = val;
-				else retval = -EINVAL;
+				if (val <= 0xff)
+					new_params.apcor.gain1 = val;
+				else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("apcor_gain2")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
+		} else if (MATCH("apcor_gain2")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
 				command_flags |= COMMAND_SETAPCOR;
-				if(val <= 0xff) new_params.apcor.gain2 = val;
-				else retval = -EINVAL;
+				if (val <= 0xff)
+					new_params.apcor.gain2 = val;
+				else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("apcor_gain4")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
+		} else if (MATCH("apcor_gain4")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
 				command_flags |= COMMAND_SETAPCOR;
-				if(val <= 0xff) new_params.apcor.gain4 = val;
-				else retval = -EINVAL;
+				if (val <= 0xff)
+					new_params.apcor.gain4 = val;
+				else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("apcor_gain8")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
+		} else if (MATCH("apcor_gain8")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
 				command_flags |= COMMAND_SETAPCOR;
-				if(val <= 0xff) new_params.apcor.gain8 = val;
-				else retval = -EINVAL;
+				if (val <= 0xff)
+					new_params.apcor.gain8 = val;
+				else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("vl_offset_gain1")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 0xff) new_params.vlOffset.gain1 = val;
-				else retval = -EINVAL;
+		} else if (MATCH("vl_offset_gain1")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.vlOffset.gain1 = val;
+				else
+					retval = -EINVAL;
 			}
-			FIND_END
 			command_flags |= COMMAND_SETVLOFFSET;
-		} else if(MATCH("vl_offset_gain2")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 0xff) new_params.vlOffset.gain2 = val;
-				else retval = -EINVAL;
+		} else if (MATCH("vl_offset_gain2")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.vlOffset.gain2 = val;
+				else
+					retval = -EINVAL;
 			}
-			FIND_END
 			command_flags |= COMMAND_SETVLOFFSET;
-		} else if(MATCH("vl_offset_gain4")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 0xff) new_params.vlOffset.gain4 = val;
-				else retval = -EINVAL;
+		} else if (MATCH("vl_offset_gain4")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.vlOffset.gain4 = val;
+				else
+					retval = -EINVAL;
 			}
-			FIND_END
 			command_flags |= COMMAND_SETVLOFFSET;
-		} else if(MATCH("vl_offset_gain8")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 0xff) new_params.vlOffset.gain8 = val;
-				else retval = -EINVAL;
+		} else if (MATCH("vl_offset_gain8")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.vlOffset.gain8 = val;
+				else
+					retval = -EINVAL;
 			}
-			FIND_END
 			command_flags |= COMMAND_SETVLOFFSET;
-		} else if(MATCH("flicker_control")) {
-			FIND_VALUE
-			if(!retval && MATCH("on")) {
-				buffer += len;
-				count -= len;
+		} else if (MATCH("flicker_control")) {
+			if (!retval && MATCH("on")) {
 				new_params.flickerControl.flickerMode = 1;
 				new_params.exposure.expMode = 2;
 				command_flags |= COMMAND_SETEXPOSURE;
-			} else if(!retval && MATCH("off")) {
-				buffer += len;
-				count -= len;
+			} else if (!retval && MATCH("off"))
 				new_params.flickerControl.flickerMode = 0;
-			} else {
+			else
 				retval = -EINVAL;
-			}
+
 			command_flags |= COMMAND_SETFLICKERCTRL;
-			FIND_END
-		} else if(MATCH("mains_frequency")) {
-			FIND_VALUE
-			if(!retval && MATCH("50")) {
-				buffer += len;
-				count -= len;
+		} else if (MATCH("mains_frequency")) {
+			if (!retval && MATCH("50")) {
 				new_mains = 0;
 				new_params.flickerControl.coarseJump = 
 					flicker_jumps[new_mains]
 					[new_params.sensorFps.baserate]
 					[new_params.sensorFps.divisor];
-				if(new_params.flickerControl.flickerMode)
+				if (new_params.flickerControl.flickerMode)
 					command_flags |= COMMAND_SETFLICKERCTRL;
-			} else if(!retval && MATCH("60")) {
-				buffer += len;
-				count -= len;
+			} else if (!retval && MATCH("60")) {
 				new_mains = 1;
 				new_params.flickerControl.coarseJump = 
 					flicker_jumps[new_mains]
 					[new_params.sensorFps.baserate]
 					[new_params.sensorFps.divisor];
-				if(new_params.flickerControl.flickerMode)
+				if (new_params.flickerControl.flickerMode)
 					command_flags |= COMMAND_SETFLICKERCTRL;
-			} else {
+			} else
 				retval = -EINVAL;
-			}
-			FIND_END
-		} else if(MATCH("allowable_overexposure")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val <= 0xff) {
+		} else if (MATCH("allowable_overexposure")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff) {
 					new_params.flickerControl.
 						allowableOverExposure = val;
 					command_flags |= COMMAND_SETFLICKERCTRL;
-				} else retval = -EINVAL;
+				} else
+					retval = -EINVAL;
 			}
-			FIND_END
-		} else if(MATCH("compression_mode")) {
-			FIND_VALUE
-			if(!retval && MATCH("none")) {
-				buffer += len;
-				count -= len;
+		} else if (MATCH("compression_mode")) {
+			if (!retval && MATCH("none"))
 				new_params.compression.mode =
 					CPIA_COMPRESSION_NONE;
-			} else if(!retval && MATCH("auto")) {
-				buffer += len;
-				count -= len;
+			else if (!retval && MATCH("auto"))
 				new_params.compression.mode =
 					CPIA_COMPRESSION_AUTO;
-			} else if(!retval && MATCH("manual")) {
-				buffer += len;
-				count -= len;
+			else if (!retval && MATCH("manual"))
 				new_params.compression.mode =
 					CPIA_COMPRESSION_MANUAL;
-			} else {
+			else
 				retval = -EINVAL;
-			}
+
 			command_flags |= COMMAND_SETCOMPRESSION;
-			FIND_END
-		} else if(MATCH("decimation")) {
-			FIND_VALUE
-			if(!retval && MATCH("off")) {
-				buffer += len;
-				count -= len;
+		} else if (MATCH("decimation_enable")) {
+			if (!retval && MATCH("off"))
 				new_params.compression.decimation = 0;
-			} else {
+			else if (!retval && MATCH("on"))
+				new_params.compression.decimation = 1;
+			else
 				retval = -EINVAL;
-			}
+
 			command_flags |= COMMAND_SETCOMPRESSION;
-			FIND_END
-		} else if(MATCH("compression_target")) {
-			FIND_VALUE
-			if(!retval && MATCH("quality")) {
-				buffer += len;
-				count -= len;
+		} else if (MATCH("compression_target")) {
+			if (!retval && MATCH("quality"))
 				new_params.compressionTarget.frTargeting = 
 					CPIA_COMPRESSION_TARGET_QUALITY;
-			} else if(!retval && MATCH("framerate")) {
-				buffer += len;
-				count -= len;
+			else if (!retval && MATCH("framerate"))
 				new_params.compressionTarget.frTargeting = 
 					CPIA_COMPRESSION_TARGET_FRAMERATE;
-			} else {
+			else
 				retval = -EINVAL;
-			}
+
 			command_flags |= COMMAND_SETCOMPRESSIONTARGET;
-			FIND_END
-		} else if(MATCH("target_framerate")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval)
-				new_params.compressionTarget.targetFR = val;
+		} else if (MATCH("target_framerate")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if(val > 0 && val <= 30)
+					new_params.compressionTarget.targetFR = val;
+				else
+					retval = -EINVAL;
+			}
 			command_flags |= COMMAND_SETCOMPRESSIONTARGET;
-			FIND_END
-		} else if(MATCH("target_quality")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) new_params.compressionTarget.targetQ = val;
+		} else if (MATCH("target_quality")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if(val > 0 && val <= 64)
+					new_params.compressionTarget.targetQ = val;
+				else 
+					retval = -EINVAL;
+			}
 			command_flags |= COMMAND_SETCOMPRESSIONTARGET;
-			FIND_END
-		} else if(MATCH("y_threshold")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val < 32)
-					new_params.yuvThreshold.yThreshold=val;
-				else retval = -EINVAL;
+		} else if (MATCH("y_threshold")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val < 32)
+					new_params.yuvThreshold.yThreshold = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETYUVTHRESH;
-			FIND_END
-		} else if(MATCH("uv_threshold")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(val < 32)
-					new_params.yuvThreshold.uvThreshold=val;
-				else retval = -EINVAL;
+		} else if (MATCH("uv_threshold")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val < 32)
+					new_params.yuvThreshold.uvThreshold = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETYUVTHRESH;
-			FIND_END
-		} else if(MATCH("hysteresis")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(retval <= 0xff)
-				    new_params.compressionParams.hysteresis=val;
-				else retval = -EINVAL;
+		} else if (MATCH("hysteresis")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.hysteresis = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
-			FIND_END
-		} else if(MATCH("threshold_max")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(retval <= 0xff)
-				    new_params.compressionParams.threshMax=val;
-				else retval = -EINVAL;
+		} else if (MATCH("threshold_max")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.threshMax = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
-			FIND_END
-		} else if(MATCH("small_step")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(retval <= 0xff)
-				    new_params.compressionParams.smallStep=val;
-				else retval = -EINVAL;
+		} else if (MATCH("small_step")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.smallStep = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
-			FIND_END
-		} else if(MATCH("large_step")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(retval <= 0xff)
-				    new_params.compressionParams.largeStep=val;
-				else retval = -EINVAL;
+		} else if (MATCH("large_step")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.largeStep = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
-			FIND_END
-		} else if(MATCH("decimation_hysteresis")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(retval <= 0xff)
-				    new_params.compressionParams.
-				        decimationHysteresis = val;
-				else retval = -EINVAL;
+		} else if (MATCH("decimation_hysteresis")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.decimationHysteresis = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
-			FIND_END
-		} else if(MATCH("fr_diff_step_thresh")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(retval <= 0xff)
-				    new_params.compressionParams.
-				        frDiffStepThresh = val;
-				else retval = -EINVAL;
+		} else if (MATCH("fr_diff_step_thresh")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.frDiffStepThresh = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
-			FIND_END
-		} else if(MATCH("q_diff_step_thresh")) {
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(retval <= 0xff)
-				    new_params.compressionParams.
-				        qDiffStepThresh = val;
-				else retval = -EINVAL;
-			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
-			FIND_END
-		} else if(MATCH("decimation_thresh_mod")) {
+		} else if (MATCH("q_diff_step_thresh")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.qDiffStepThresh = val;
+				else
+					retval = -EINVAL;
 			}
-			FIND_VALUE
-			if(!retval) { val = VALUE }
-			if(!retval) {
-				if(retval <= 0xff)
-				    new_params.compressionParams.
-				        decimationThreshMod = val;
-				else retval = -EINVAL;
+			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("decimation_thresh_mod")) {
+			if (!retval)
+				val = VALUE;
+
+			if (!retval) {
+				if (val <= 0xff)
+					new_params.compressionParams.decimationThreshMod = val;
+				else
+					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
-			FIND_END
+		} else if (MATCH("toplight")) { /* GA 4/14/00 */
+		        if (!retval && MATCH("on"))
+			  new_params.qx3.toplight = 1;
+
+			else if (!retval && MATCH("off")) 
+			  new_params.qx3.toplight = 0;
+
+			else 
+			  retval = -EINVAL;
+                        command_flags |= COMMAND_SETLIGHTS;
+                        
+		} else if (MATCH("bottomlight")) { /* GA 4/14/00 */
+		        if (!retval && MATCH("on"))
+			  new_params.qx3.bottomlight = 1;
+
+			else if (!retval && MATCH("off")) 
+			  new_params.qx3.bottomlight = 0;
+
+			else 
+			  retval = -EINVAL;
+                        command_flags |= COMMAND_SETLIGHTS;
+                        
 		} else {
+			DBG("No match found\n");
 			retval = -EINVAL;
 		}
+
+		if (!retval) {
+			while (count && isspace(*buffer) && *buffer != '\n') {
+				--count;
+				++buffer;
+			}
+			if (count) {
+				if (*buffer != '\n' && *buffer != ';')
+					retval = -EINVAL;
+				else {
+					--count;
+					++buffer;
+				}
+			}
+		}
 	}
 #undef MATCH	
 #undef FIRMWARE_VERSION
 #undef VALUE
 #undef FIND_VALUE
 #undef FIND_END
-	if(retval == 0) {
-		if(command_flags & COMMAND_SETCOLOURPARAMS) {
+	if (!retval) {
+		if (command_flags & COMMAND_SETCOLOURPARAMS) {
 			/* Adjust cam->vp to reflect these changes */
 			cam->vp.brightness =
 				new_params.colourParams.brightness*65535/100;
@@ -1394,9 +1361,8 @@
 		cam->mainsFreq = new_mains;
 		cam->cmd_queue |= command_flags;
 		retval = size;
-	} else {
+	} else
 		DBG("error: %d\n", retval);
-	}
 	
 	up(&cam->param_lock);
 	
@@ -1408,17 +1374,21 @@
 	char name[7];
 	struct proc_dir_entry *ent;
 	
-	if(cpia_proc_root == NULL || cam == NULL) {
+	if (!cpia_proc_root || !cam)
 		return;
-	}
+
 	sprintf(name, "video%d", cam->vdev.minor);
 	
 	ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
-	if (!ent) return;
+	if (!ent)
+		return;
+
 	ent->data = cam;
 	ent->read_proc = cpia_read_proc;
 	ent->write_proc = cpia_write_proc;
-	ent->size = 3623;
+	ent->size = 3736;
+	if (cam->params.qx3.qx3_detected)
+		ent->size += 188;
 	cam->proc_entry = ent;
 }
 
@@ -1426,16 +1396,43 @@
 {
 	char name[7];
 	
-	if(cam == NULL || cam->proc_entry == NULL) return;
+	if (!cam || !cam->proc_entry)
+		return;
 	
 	sprintf(name, "video%d", cam->vdev.minor);
 	remove_proc_entry(name, cpia_proc_root);
 	cam->proc_entry = NULL;
 }
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+/*
+ * This is called as the fill_inode function when an inode
+ * is going into (fill = 1) or out of service (fill = 0).
+ * We use it here to manage the module use counts.
+ */
+static void proc_cpia_modcount(struct inode *inode, int fill)
+{
+#ifdef MODULE
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
+#endif
+}
+#endif
+
 static void proc_cpia_create(void)
 {
 	cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
+
+	if (cpia_proc_root) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		cpia_proc_root->fill_inode = &proc_cpia_modcount;
+#else
+		cpia_proc_root->owner = THIS_MODULE;
+#endif
+	} else
+		LOG("Unable to initialise /proc/cpia\n");
 }
 
 #ifdef MODULE
@@ -1444,6 +1441,7 @@
 	remove_proc_entry("cpia", 0);
 }
 #endif
+#endif /* CONFIG_PROC_FS */
 
 /* ----------------------- debug functions ---------------------- */
 
@@ -1473,39 +1471,41 @@
 {
 	/* return the best match, where 'best' is as always
 	 * the largest that is not bigger than what is requested. */
-	if(width>=352 && height>=288) {
+	if (width>=352 && height>=288)
 		return VIDEOSIZE_352_288; /* CIF */
-	}
-	if(width>=320 && height>=240) {
+
+	if (width>=320 && height>=240)
 		return VIDEOSIZE_320_240; /* SIF */
-	}
-	if(width>=288 && height>=216) {
+
+	if (width>=288 && height>=216)
 		return VIDEOSIZE_288_216;
-	}
-	if(width>=256 && height>=192) {
+
+	if (width>=256 && height>=192)
 		return VIDEOSIZE_256_192;
-	}
-	if(width>=224 && height>=168) {
+
+	if (width>=224 && height>=168)
 		return VIDEOSIZE_224_168;
-	}
-	if(width>=192 && height>=144) {
+
+	if (width>=192 && height>=144)
 		return VIDEOSIZE_192_144;
-	}
-	if(width>=176 && height>=144) {
+
+	if (width>=176 && height>=144)
 		return VIDEOSIZE_176_144; /* QCIF */
-	}
-	if(width>=160 && height>=120) {
+
+	if (width>=160 && height>=120)
 		return VIDEOSIZE_160_120; /* QSIF */
-	}
-	if(width>=128 && height>=96) {
+
+	if (width>=128 && height>=96)
 		return VIDEOSIZE_128_96;
-	}
-	if(width>=64 && height>=48) {
+
+	if (width>=88 && height>=72)
+		return VIDEOSIZE_88_72;
+
+	if (width>=64 && height>=48)
 		return VIDEOSIZE_64_48;
-	}
-	if(width>=48 && height>=48) {
+
+	if (width>=48 && height>=48)
 		return VIDEOSIZE_48_48;
-	}
 
 	return -1;
 }
@@ -1608,6 +1608,16 @@
 		cam->params.roi.rowEnd=30;
 		cam->params.streamStartLine = 60;
 		break;
+	case VIDEOSIZE_88_72:
+		cam->vw.width = 88;
+		cam->vw.height = 72;
+		cam->params.format.videoSize=VIDEOSIZE_QCIF;
+		cam->params.roi.colStart=5;
+		cam->params.roi.colEnd=16;
+		cam->params.roi.rowStart=9;
+		cam->params.roi.rowEnd=27;
+		cam->params.streamStartLine = 60;
+		break;
 	case VIDEOSIZE_64_48:
 		cam->vw.width = 64;
 		cam->vw.height = 48;
@@ -1635,27 +1645,29 @@
 	return;
 }
 
-static int allocate_frame_buf(struct cam_data *cam) {
+static int allocate_frame_buf(struct cam_data *cam)
+{
 	int i;
 
-	cam->frame_buf = rvmalloc(FRAME_NUM*CPIA_MAX_FRAME_SIZE);
-	if (!cam->frame_buf) {
+	cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
+	if (!cam->frame_buf)
 		return -ENOBUFS;
-	}
-	for( i=0; i<FRAME_NUM; i++ ) {
-		cam->frame[i].data = cam->frame_buf + i*CPIA_MAX_FRAME_SIZE;
-	}
+
+	for (i = 0; i < FRAME_NUM; i++)
+		cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
+
 	return 0;
 }
 
-static int free_frame_buf(struct cam_data *cam) {
+static int free_frame_buf(struct cam_data *cam)
+{
 	int i;
 	
 	rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
-	cam->frame_buf=0;
-	for( i=0; i<FRAME_NUM; i++ ) {
+	cam->frame_buf = 0;
+	for (i=0; i < FRAME_NUM; i++)
 		cam->frame[i].data = NULL;
-	}
+
 	return 0;
 }
 
@@ -1663,9 +1675,9 @@
 static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
 {
 	int i;
-	for( i=0; i<FRAME_NUM; i++ ) {
-		frame[i].state=FRAME_UNUSED;
-	}
+
+	for (i=0; i < FRAME_NUM; i++)
+		frame[i].state = FRAME_UNUSED;
 	return;
 }
 
@@ -1693,6 +1705,10 @@
 		down(&cam->param_lock);
 		datasize=8;
 		break;
+        case CPIA_COMMAND_ReadMCPorts: /* GA 4/14/00 */
+        case CPIA_COMMAND_ReadVCRegs:
+                datasize = 4;
+                break;
 	default:
 		datasize=0;
 		break;
@@ -1708,12 +1724,12 @@
 	cmd[7] = 0;
 
 	retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
-	if(retval) {
-		LOG("%x - failed\n", command);
+	if (retval) {
+		DBG("%x - failed, retval=%d\n", command, retval);
 		if (command == CPIA_COMMAND_GetColourParams ||
 		    command == CPIA_COMMAND_GetColourBalance ||
 		    command == CPIA_COMMAND_GetExposure)
-                	up(&cam->param_lock);
+			up(&cam->param_lock);
 	} else {
 		switch(command) {
 		case CPIA_COMMAND_GetCPIAVersion:
@@ -1765,9 +1781,48 @@
 			cam->params.exposure.green1Comp = data[5];
 			cam->params.exposure.green2Comp = data[6];
 			cam->params.exposure.blueComp = data[7];
+			/* If the *Comp parameters are wacko, generate
+			 * a warning, and reset them back to default
+			 * values.             - rich@annexia.org
+			 */
+			if (cam->params.exposure.redComp < 220 ||
+			    cam->params.exposure.redComp > 255 ||
+			    cam->params.exposure.green1Comp < 214 ||
+			    cam->params.exposure.green1Comp > 255 ||
+			    cam->params.exposure.green2Comp < 214 ||
+			    cam->params.exposure.green2Comp > 255 ||
+			    cam->params.exposure.blueComp < 230 ||
+			    cam->params.exposure.blueComp > 255)
+			  {
+			    printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
+				    cam->params.exposure.redComp,
+				    cam->params.exposure.green1Comp,
+				    cam->params.exposure.green2Comp,
+				    cam->params.exposure.blueComp);
+			    cam->params.exposure.redComp = 220;
+			    cam->params.exposure.green1Comp = 214;
+			    cam->params.exposure.green2Comp = 214;
+			    cam->params.exposure.blueComp = 230;
+			  }
 			up(&cam->param_lock);
 			break;
-		default:
+
+                case CPIA_COMMAND_ReadMCPorts: /* GA 04/14/00 */
+                  if (!cam->params.qx3.qx3_detected) break;
+
+		  /* test button press */ 
+		  cam->params.qx3.button = ((data[1] & 0x02) == 0);
+		  if (cam->params.qx3.button) {
+		    /* button pressed - unlock the latch */
+		    do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
+		    do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
+		  }
+
+		  /* test whether microscope is cradled */
+		  cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
+		  break;
+
+ 		default:
 			break;
 		}
 	}
@@ -1782,6 +1837,7 @@
 {
 	int retval;
 	u8 cmd[8], data[8];
+
 	cmd[0] = command>>8;
 	cmd[1] = command&0xff;
 	cmd[2] = a;
@@ -1800,29 +1856,186 @@
 	data[7] = l;
 
 	retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
-	if(retval) {
+	if (retval)
 		LOG("%x - failed\n", command);
+
+	return retval;
+}
+
+/**********************************************************************
+ *
+ * Colorspace conversion
+ *
+ **********************************************************************/
+#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
+
+static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
+                      int linesize, int mmap_kludge)
+{
+	int y, u, v, r, g, b, y1;
+
+	switch(out_fmt) {
+	case VIDEO_PALETTE_RGB555:
+		y = (*yuv++ - 16) * 76310;
+		y1 = (*yuv - 16) * 76310;
+		r = ((*(rgb+1-linesize)) & 0x7c) << 1;
+		g = ((*(rgb-linesize)) & 0xe0) >> 4 |
+		    ((*(rgb+1-linesize)) & 0x03) << 6;
+		b = ((*(rgb-linesize)) & 0x1f) << 3;
+		u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
+		v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
+		r = 104635 * v;
+		g = -25690 * u - 53294 * v;
+		b = 132278 * u;
+		break;
+	case VIDEO_PALETTE_RGB565:
+		y = (*yuv++ - 16) * 76310;
+		y1 = (*yuv - 16) * 76310;
+		r = (*(rgb+1-linesize)) & 0xf8;
+		g = ((*(rgb-linesize)) & 0xe0) >> 3 |
+		    ((*(rgb+1-linesize)) & 0x07) << 5;
+		b = ((*(rgb-linesize)) & 0x1f) << 3;
+		u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
+		v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
+		r = 104635 * v;
+		g = -25690 * u - 53294 * v;
+		b = 132278 * u;
+		break;
+	case VIDEO_PALETTE_RGB24:
+	case VIDEO_PALETTE_RGB32:
+		y = (*yuv++ - 16) * 76310;
+		y1 = (*yuv - 16) * 76310;
+		if (mmap_kludge) {
+			r = *(rgb+2-linesize);
+			g = *(rgb+1-linesize);
+			b = *(rgb-linesize);
+		} else {
+			r = *(rgb-linesize);
+			g = *(rgb+1-linesize);
+			b = *(rgb+2-linesize);
+		}
+		u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
+		v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
+		r = 104635 * v;
+		g = -25690 * u + -53294 * v;
+		b = 132278 * u;
+		break;
+	case VIDEO_PALETTE_YUV422:
+	case VIDEO_PALETTE_YUYV:
+		y = *yuv++;
+		u = *(rgb+1-linesize);
+		y1 = *yuv;
+		v = *(rgb+3-linesize);
+		/* Just to avoid compiler warnings */
+		r = 0;
+		g = 0;
+		b = 0;
+		break;
+	case VIDEO_PALETTE_UYVY:
+		u = *(rgb-linesize);
+		y = *yuv++;
+		v = *(rgb+2-linesize);
+		y1 = *yuv;
+		/* Just to avoid compiler warnings */
+		r = 0;
+		g = 0;
+		b = 0;
+		break;
+	case VIDEO_PALETTE_GREY:
+	default:
+		y = *yuv++;
+		y1 = *yuv;
+		/* Just to avoid compiler warnings */
+		u = 0;
+		v = 0;
+		r = 0;
+		g = 0;
+		b = 0;
+		break;
+	}
+	switch(out_fmt) {
+	case VIDEO_PALETTE_RGB555:
+		*rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
+		*rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
+		*rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
+		*rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
+		return 4;
+	case VIDEO_PALETTE_RGB565:
+		*rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
+		*rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
+		*rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
+		*rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
+		return 4;
+	case VIDEO_PALETTE_RGB24:
+		if (mmap_kludge) {
+			*rgb++ = LIMIT(b+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(r+y);
+			*rgb++ = LIMIT(b+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(r+y1);
+		} else {
+			*rgb++ = LIMIT(r+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(b+y);
+			*rgb++ = LIMIT(r+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(b+y1);
+		}
+		return 6;
+	case VIDEO_PALETTE_RGB32:
+		if (mmap_kludge) {
+			*rgb++ = LIMIT(b+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(r+y);
+			rgb++;
+			*rgb++ = LIMIT(b+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(r+y1);
+		} else {
+			*rgb++ = LIMIT(r+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(b+y);
+			rgb++;
+			*rgb++ = LIMIT(r+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(b+y1);
+		}
+		return 8;
+	case VIDEO_PALETTE_GREY:
+		*rgb++ = y;
+		*rgb = y1;
+		return 2;
+	case VIDEO_PALETTE_YUV422:
+	case VIDEO_PALETTE_YUYV:
+		*rgb++ = y;
+		*rgb++ = u;
+		*rgb++ = y1;
+		*rgb = v;
+		return 4;
+	case VIDEO_PALETTE_UYVY:
+		*rgb++ = u;
+		*rgb++ = y;
+		*rgb++ = v;
+		*rgb = y1;
+		return 4;
+	default:
+		DBG("Empty: %d\n", out_fmt);
+		return 0;
 	}
-	return retval;
 }
 
-/**********************************************************************
- *
- * Colorspace conversion
- *
- **********************************************************************/
-#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
-
 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
-                      int in_uyvy)
+                      int in_uyvy, int mmap_kludge)
 {
 	int y, u, v, r, g, b, y1;
+
 	switch(out_fmt) {
 	case VIDEO_PALETTE_RGB555:
 	case VIDEO_PALETTE_RGB565:
 	case VIDEO_PALETTE_RGB24:
 	case VIDEO_PALETTE_RGB32:
-		if(in_uyvy) {
+		if (in_uyvy) {
 			u = *yuv++ - 128;
 			y = (*yuv++ - 16) * 76310;
 			v = *yuv++ - 128;
@@ -1862,21 +2075,40 @@
 		*rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
 		return 4;
 	case VIDEO_PALETTE_RGB24:
-		*rgb++ = LIMIT(b+y);
-		*rgb++ = LIMIT(g+y);
-		*rgb++ = LIMIT(r+y);
-		*rgb++ = LIMIT(b+y1);
-		*rgb++ = LIMIT(g+y1);
-		*rgb = LIMIT(r+y1);
+		if (mmap_kludge) {
+			*rgb++ = LIMIT(b+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(r+y);
+			*rgb++ = LIMIT(b+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(r+y1);
+		} else {
+			*rgb++ = LIMIT(r+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(b+y);
+			*rgb++ = LIMIT(r+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(b+y1);
+		}
 		return 6;
 	case VIDEO_PALETTE_RGB32:
-		*rgb++ = LIMIT(b+y);
-		*rgb++ = LIMIT(g+y);
-		*rgb++ = LIMIT(r+y);
-		rgb++;
-		*rgb++ = LIMIT(b+y1);
-		*rgb++ = LIMIT(g+y1);
-		*rgb = LIMIT(r+y1);
+		if (mmap_kludge) {
+			*rgb++ = LIMIT(b+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(r+y);
+			rgb++;
+			*rgb++ = LIMIT(b+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(r+y1);
+		} else {
+			*rgb++ = LIMIT(r+y);
+			*rgb++ = LIMIT(g+y);
+			*rgb++ = LIMIT(b+y);
+			rgb++;
+			*rgb++ = LIMIT(r+y1);
+			*rgb++ = LIMIT(g+y1);
+			*rgb = LIMIT(b+y1);
+		}
 		return 8;
 	case VIDEO_PALETTE_GREY:
 		*rgb++ = y;
@@ -1896,11 +2128,13 @@
 		*rgb = y1;
 		return 4;
 	default:
+		DBG("Empty: %d\n", out_fmt);
 		return 0;
 	}
 }
 
-static int skipcount(int count, int fmt) {
+static int skipcount(int count, int fmt)
+{
 	switch(fmt) {
 	case VIDEO_PALETTE_GREY:
 		return count;
@@ -1922,66 +2156,68 @@
 static int parse_picture(struct cam_data *cam, int size)
 {
 	u8 *obuf, *ibuf, *end_obuf;
-	int ll, in_uyvy, compressed, origsize, out_fmt;
+	int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
+	int rows, cols, linesize, subsample_422;
 
 	/* make sure params don't change while we are decoding */
 	down(&cam->param_lock);
-	
+
 	obuf = cam->decompressed_frame.data;
 	end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
 	ibuf = cam->raw_image;
 	origsize = size;
 	out_fmt = cam->vp.palette;
-	
-	if((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
+
+	if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
 		LOG("header not found\n");
 		up(&cam->param_lock);
 		return -1;
 	}
 
-	if((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
+	if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
 		LOG("wrong video size\n");
 		up(&cam->param_lock);
 		return -1;
 	}
 	
-	if(ibuf[17] != SUBSAMPLE_422) {
+	if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
 		LOG("illegal subtype %d\n",ibuf[17]);
 		up(&cam->param_lock);
 		return -1;
 	}
+	subsample_422 = ibuf[17] == SUBSAMPLE_422;
 	
-	if(ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
+	if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
 		LOG("illegal yuvorder %d\n",ibuf[18]);
 		up(&cam->param_lock);
 		return -1;
 	}
 	in_uyvy = ibuf[18] == YUVORDER_UYVY;
 	
-#if 0
-	/* FIXME: ROI mismatch occurs when switching capture sizes */
-	if((ibuf[24] != cam->params.roi.colStart) ||
-	   (ibuf[25] != cam->params.roi.colEnd) ||
-	   (ibuf[26] != cam->params.roi.rowStart) ||
-	   (ibuf[27] != cam->params.roi.rowEnd)) {
+	if ((ibuf[24] != cam->params.roi.colStart) ||
+	    (ibuf[25] != cam->params.roi.colEnd) ||
+	    (ibuf[26] != cam->params.roi.rowStart) ||
+	    (ibuf[27] != cam->params.roi.rowEnd)) {
 		LOG("ROI mismatch\n");
 		up(&cam->param_lock);
 		return -1;
 	}
-#endif
+	cols = 8*(ibuf[25] - ibuf[24]);
+	rows = 4*(ibuf[27] - ibuf[26]);
 	
-	if((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
+	if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
 		LOG("illegal compression %d\n",ibuf[28]);
 		up(&cam->param_lock);
 		return -1;
 	}
 	compressed = (ibuf[28] == COMPRESSED);
 	
-	if(ibuf[29] != NO_DECIMATION) {
-		LOG("decimation not supported\n");
+	if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
+		LOG("illegal decimation %d\n",ibuf[29]);
 		up(&cam->param_lock);
 		return -1;
 	}
+	decimation = (ibuf[29] == DECIMATION_ENAB);
 	
 	cam->params.yuvThreshold.yThreshold = ibuf[30];
 	cam->params.yuvThreshold.uvThreshold = ibuf[31];
@@ -1994,98 +2230,135 @@
 	cam->params.status.vpStatus = ibuf[38];
 	cam->params.status.errorCode = ibuf[39];
 	cam->fps = ibuf[41];
+	up(&cam->param_lock);
 	
-	ibuf += 64;
-	size -= 64;
+	linesize = skipcount(cols, out_fmt);
+	ibuf += FRAME_HEADER_SIZE;
+	size -= FRAME_HEADER_SIZE;
 	ll = ibuf[0] | (ibuf[1] << 8);
 	ibuf += 2;
-	while(size > 0) {
+	even_line = 1;
+
+	while (size > 0) {
 		size -= (ll+2);
-		if(size < 0) {
+		if (size < 0) {
 			LOG("Insufficient data in buffer\n");
-			up(&cam->param_lock);
 			return -1;
 		}
-		while(ll > 1) {
-			if(!compressed || (compressed && !(*ibuf & 1))) {
-				obuf += yuvconvert(ibuf,obuf,out_fmt,in_uyvy);
-				ibuf += 4;
-				ll -= 4;
+
+		while (ll > 1) {
+			if (!compressed || (compressed && !(*ibuf & 1))) {
+				if(subsample_422 || even_line) {
+					obuf += yuvconvert(ibuf, obuf, out_fmt,
+			                	   in_uyvy, cam->mmap_kludge);
+					ibuf += 4;
+					ll -= 4;
+				} else {
+					/* SUBSAMPLE_420 on an odd line */
+					obuf += convert420(ibuf, obuf,
+					                   out_fmt, linesize,
+			                		   cam->mmap_kludge);
+					ibuf += 2;
+					ll -= 2;
+				}
 			} else {
 				/*skip compressed interval from previous frame*/
-				int skipsize = skipcount(*ibuf >> 1, out_fmt);
-				obuf += skipsize;
-				if( obuf > end_obuf ) {
-					LOG("Insufficient data in buffer\n");
-					up(&cam->param_lock);
+				obuf += skipcount(*ibuf >> 1, out_fmt);
+				if (obuf > end_obuf) {
+					LOG("Insufficient buffer size\n");
 					return -1;
 				}
 				++ibuf;
 				ll--;
 			}
 		}
-		if(ll == 1) {
-			if(*ibuf != EOL) {
+		if (ll == 1) {
+			if (*ibuf != EOL) {
 				LOG("EOL not found giving up after %d/%d"
 				    " bytes\n", origsize-size, origsize);
-				up(&cam->param_lock);
 				return -1;
 			}
 
-			ibuf++; /* skip over EOL */
+			++ibuf; /* skip over EOL */
 
-			if((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
+			if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
 			   (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
 			 	size -= 4;
 				break;
 			}
 
-			if(size > 1) {
+			if(decimation) {
+				/* skip the odd lines for now */
+				obuf += linesize;
+			}
+			
+			if (size > 1) {
 				ll = ibuf[0] | (ibuf[1] << 8);
 				ibuf += 2; /* skip over line length */
 			}
+			
+			if(!decimation)
+				even_line = !even_line;
 		} else {
 			LOG("line length was not 1 but %d after %d/%d bytes\n",
 			    ll, origsize-size, origsize);
-			up(&cam->param_lock);
 			return -1;
 		}
 	}
 	
+	if(decimation) {
+		/* interpolate odd rows */
+		int i, j;
+		u8 *prev, *next;
+		prev = cam->decompressed_frame.data;
+		obuf = prev+linesize;
+		next = obuf+linesize;
+		for(i=1; i<rows-1; i+=2) {
+			for(j=0; j<linesize; ++j) {
+				*obuf++ = ((int)*prev++ + *next++) / 2;
+			}
+			prev += linesize;
+			obuf += linesize;
+			next += linesize;
+		}
+		/* last row is odd, just copy previous row */
+		memcpy(obuf, prev, linesize);
+	}
+	
 	cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
 
-	up(&cam->param_lock);
-	
 	return cam->decompressed_frame.count;
 }
 
 /* InitStreamCap wrapper to select correct start line */
-static inline int init_stream_cap(struct cam_data *cam) {
+static inline int init_stream_cap(struct cam_data *cam)
+{
 	return do_command(cam, CPIA_COMMAND_InitStreamCap,
 	                  0, cam->params.streamStartLine, 0, 0);
 }
 
 /* update various camera modes and settings */
-static void dispatch_commands(struct cam_data *cam ) {
+static void dispatch_commands(struct cam_data *cam)
+{
 	down(&cam->param_lock);
-	if( cam->cmd_queue==COMMAND_NONE ) {
+	if (cam->cmd_queue==COMMAND_NONE) {
 		up(&cam->param_lock);
 		return;
 	}
 	DEB_BYTE(cam->cmd_queue);
 	DEB_BYTE(cam->cmd_queue>>8);
-	if( cam->cmd_queue & COMMAND_SETCOLOURPARAMS ) {
+	if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
 		do_command(cam, CPIA_COMMAND_SetColourParams,
 		           cam->params.colourParams.brightness,
 		           cam->params.colourParams.contrast,
 		           cam->params.colourParams.saturation, 0);
-	}
-	if( cam->cmd_queue & COMMAND_SETCOMPRESSION ) {
+
+	if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
 		do_command(cam, CPIA_COMMAND_SetCompression,
 		           cam->params.compression.mode,
 			   cam->params.compression.decimation, 0, 0);
-	}
-	if( cam->cmd_queue & COMMAND_SETFORMAT ) {
+
+	if (cam->cmd_queue & COMMAND_SETFORMAT) {
 		do_command(cam, CPIA_COMMAND_SetFormat,
 	        	   cam->params.format.videoSize,
 	        	   cam->params.format.subSample,
@@ -2095,22 +2368,23 @@
 	        	   cam->params.roi.rowStart, cam->params.roi.rowEnd);
 		cam->first_frame = 1;
 	}
-	if( cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET ) {
+
+	if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
 		do_command(cam, CPIA_COMMAND_SetCompressionTarget,
 		           cam->params.compressionTarget.frTargeting,
 		           cam->params.compressionTarget.targetFR,
 		           cam->params.compressionTarget.targetQ, 0);
-	}
-	if( cam->cmd_queue & COMMAND_SETYUVTHRESH ) {
+
+	if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
 		do_command(cam, CPIA_COMMAND_SetYUVThresh,
 		           cam->params.yuvThreshold.yThreshold,
 		           cam->params.yuvThreshold.uvThreshold, 0, 0);
-	}
-	if( cam->cmd_queue & COMMAND_SETECPTIMING ) {
+
+	if (cam->cmd_queue & COMMAND_SETECPTIMING)
 		do_command(cam, CPIA_COMMAND_SetECPTiming,
 		           cam->params.ecpTiming, 0, 0, 0);
-	}
-	if( cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS ) {
+
+	if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
 		do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
 		            0, 0, 0, 0,
 		            cam->params.compressionParams.hysteresis,
@@ -2121,8 +2395,8 @@
 		            cam->params.compressionParams.frDiffStepThresh,
 		            cam->params.compressionParams.qDiffStepThresh,
 		            cam->params.compressionParams.decimationThreshMod);
-	}
-	if( cam->cmd_queue & COMMAND_SETEXPOSURE ) {
+
+	if (cam->cmd_queue & COMMAND_SETEXPOSURE)
 		do_command_extended(cam, CPIA_COMMAND_SetExposure,
 		                    cam->params.exposure.gainMode,
 		                    cam->params.exposure.expMode,
@@ -2136,150 +2410,191 @@
 		                    cam->params.exposure.green1Comp,
 		                    cam->params.exposure.green2Comp,
 		                    cam->params.exposure.blueComp);
+
+	if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
+		if (cam->params.colourBalance.balanceModeIsAuto) {
+			do_command(cam, CPIA_COMMAND_SetColourBalance,
+				   2, 0, 0, 0);
+		} else {
+			do_command(cam, CPIA_COMMAND_SetColourBalance,
+				   1,
+				   cam->params.colourBalance.redGain,
+				   cam->params.colourBalance.greenGain,
+				   cam->params.colourBalance.blueGain);
+			do_command(cam, CPIA_COMMAND_SetColourBalance,
+				   3, 0, 0, 0);
+		}
 	}
-	if( cam->cmd_queue & COMMAND_SETCOLOURBALANCE ) {
-		do_command(cam, CPIA_COMMAND_SetColourBalance,
-		           cam->params.colourBalance.balanceMode,
-		           cam->params.colourBalance.redGain,
-		           cam->params.colourBalance.greenGain,
-		           cam->params.colourBalance.blueGain);
-	}
-	if( cam->cmd_queue & COMMAND_SETSENSORFPS ) {
+
+	if (cam->cmd_queue & COMMAND_SETSENSORFPS)
 		do_command(cam, CPIA_COMMAND_SetSensorFPS,
 		           cam->params.sensorFps.divisor,
 		           cam->params.sensorFps.baserate, 0, 0);
-	}
-	if( cam->cmd_queue & COMMAND_SETAPCOR ) {
+
+	if (cam->cmd_queue & COMMAND_SETAPCOR)
 		do_command(cam, CPIA_COMMAND_SetApcor,
 		           cam->params.apcor.gain1,
 		           cam->params.apcor.gain2,
 		           cam->params.apcor.gain4,
 		           cam->params.apcor.gain8);
-	}
-	if( cam->cmd_queue & COMMAND_SETFLICKERCTRL ) {
+
+	if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
 		do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
 		           cam->params.flickerControl.flickerMode,
 		           cam->params.flickerControl.coarseJump,
 		           cam->params.flickerControl.allowableOverExposure, 0);
-	}
-	if( cam->cmd_queue & COMMAND_SETVLOFFSET ) {
+
+	if (cam->cmd_queue & COMMAND_SETVLOFFSET)
 		do_command(cam, CPIA_COMMAND_SetVLOffset,
 		           cam->params.vlOffset.gain1,
 		           cam->params.vlOffset.gain2,
 		           cam->params.vlOffset.gain4,
 		           cam->params.vlOffset.gain8);
-	}
-	if( cam->cmd_queue & COMMAND_PAUSE ) {
+
+	if (cam->cmd_queue & COMMAND_PAUSE)
 		do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
-	}
-	if( cam->cmd_queue & COMMAND_RESUME ) {
-		init_stream_cap( cam );
-	}
+
+	if (cam->cmd_queue & COMMAND_RESUME)
+		init_stream_cap(cam);
+
+	/* GA 04/14/00 */
+	if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
+	  {
+	    int p1 = (cam->params.qx3.bottomlight == 0) << 1;
+            int p2 = (cam->params.qx3.toplight == 0) << 3;
+            do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
+            do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
+	  }
+
 	up(&cam->param_lock);
-	cam->cmd_queue=COMMAND_NONE;
+	cam->cmd_queue = COMMAND_NONE;
 	return;
 }
 
 /* kernel thread function to read image from camera */
 static void fetch_frame(void *data)
 {
-	int image_size;
+	int image_size, retry;
 	struct cam_data *cam = (struct cam_data *)data;
 	unsigned long oldjif, rate, diff;
 
-        /* load first frame always uncompressed */
-        if( cam->first_frame &&
-            cam->params.compression.mode != CPIA_COMPRESSION_NONE ) {
-                do_command(cam, CPIA_COMMAND_SetCompression,
-                           CPIA_COMPRESSION_NONE,
-                           NO_DECIMATION, 0, 0);
-        }
-
-        /* init camera upload */
-        if(do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_CONTINUOUS,
-                      0, 0, 0)) goto end;
-        if(do_command(cam, CPIA_COMMAND_GrabFrame, 0,
-                      cam->params.streamStartLine, 0, 0)) goto end;
-
-	/* loop until image ready */
-	do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
-	while(cam->params.status.streamState != STREAM_READY) {
-		if(current->need_resched) {schedule();}
-		current->state=TASK_INTERRUPTIBLE;
-		schedule_timeout(10*HZ/1000); /* 10 ms, hopefully ;) */
-		if(signal_pending(current)) {
-			goto end;
-		}
-		do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
-	}
-
-	/* grab image from camera */
-	if(current->need_resched) {schedule();}
-	oldjif = jiffies;
-	image_size=cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
-	if(image_size<=0) {
-		DBG("read frame failed\n");
-		goto end;
-	}
-	rate = image_size * HZ / 1024;
-	diff = jiffies-oldjif;
-	rate = diff==0 ? rate : rate/diff; /* unlikely but possible */
-	/* Keep track of transfer_rate as a runnung average over 3 frames
-	 * to smooth out any inconsistencies */
-	cam->transfer_rate = (2*cam->transfer_rate + rate) / 3;
-
-	/* camera idle now so dispatch queued commands */
-	dispatch_commands( cam );
-
-	/* Update our knowledge of the camera state - FIXME: necessary? */
-	do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
-	do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
-	
-	/* decompress and convert image to by copying it from
-	*  raw_image to decompressed_frame
-	*/
-	if(current->need_resched) {schedule();}
-	cam->image_size = parse_picture(cam, image_size);
-	if( cam->image_size <= 0 ) {
-		DBG("parse frame failed\n");
-		goto end;
-	}
-
-	/* FIXME: this only works for double buffering */
-	if( cam->frame[cam->curframe].state == FRAME_READY ) {
-		memcpy(cam->frame[cam->curframe].data,
-		       cam->decompressed_frame.data,
-		       cam->decompressed_frame.count);
-		cam->frame[cam->curframe].state = FRAME_DONE;
-	} else {
-		cam->decompressed_frame.state = FRAME_DONE;
-	}
+	/* Allow up to two bad images in a row to be read and
+	 * ignored before an error is reported */
+	for (retry = 0; retry < 3; ++retry) {
+		if (retry)
+			DBG("retry=%d\n", retry);
+
+		if (!cam->ops)
+			continue;
+
+		/* load first frame always uncompressed */
+		if (cam->first_frame &&
+		    cam->params.compression.mode != CPIA_COMPRESSION_NONE)
+			do_command(cam, CPIA_COMMAND_SetCompression,
+				   CPIA_COMPRESSION_NONE,
+				   NO_DECIMATION, 0, 0);
+
+		/* init camera upload */
+		if (do_command(cam, CPIA_COMMAND_SetGrabMode,
+			       CPIA_GRAB_CONTINUOUS, 0, 0, 0))
+			continue;
+
+		if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
+			       cam->params.streamStartLine, 0, 0))
+			continue;
+
+		if (cam->ops->wait_for_stream_ready) {
+			/* loop until image ready */
+			do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
+			while (cam->params.status.streamState != STREAM_READY) {
+				if (current->need_resched)
+					schedule();
+
+				current->state = TASK_INTERRUPTIBLE;
+
+				/* sleep for 10 ms, hopefully ;) */
+				schedule_timeout(10*HZ/1000);
+				if (signal_pending(current))
+					return;
+
+				do_command(cam, CPIA_COMMAND_GetCameraStatus,
+				           0, 0, 0, 0);
+			}
+		}
+
+		/* grab image from camera */
+		if (current->need_resched)
+			schedule();
+
+		oldjif = jiffies;
+		image_size = cam->ops->streamRead(cam->lowlevel_data,
+						  cam->raw_image, 0);
+		if (image_size <= 0) {
+			DBG("streamRead failed: %d\n", image_size);
+			continue;
+		}
+
+		rate = image_size * HZ / 1024;
+		diff = jiffies-oldjif;
+		cam->transfer_rate = diff==0 ? rate : rate/diff;
+			/* diff==0 ? unlikely but possible */
+
+		/* camera idle now so dispatch queued commands */
+		dispatch_commands(cam);
+
+		/* Update our knowledge of the camera state - FIXME: necessary? */
+		do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+		do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+		do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); /* GA */
+
+
+		/* decompress and convert image to by copying it from
+		 * raw_image to decompressed_frame
+		 */
+		if (current->need_resched)
+			schedule();
+
+		cam->image_size = parse_picture(cam, image_size);
+		if (cam->image_size <= 0)
+			DBG("parse_picture failed %d\n", cam->image_size);
+		else
+			break;
+	}
+
+	if (retry < 3) {
+		/* FIXME: this only works for double buffering */
+		if (cam->frame[cam->curframe].state == FRAME_READY) {
+			memcpy(cam->frame[cam->curframe].data,
+			       cam->decompressed_frame.data,
+			       cam->decompressed_frame.count);
+			cam->frame[cam->curframe].state = FRAME_DONE;
+		} else
+			cam->decompressed_frame.state = FRAME_DONE;
 
 #if 0
-	if( cam->first_frame &&
-	    cam->params.compression.mode != CPIA_COMPRESSION_NONE ) {
-		cam->first_frame = 0;
-		cam->cmd_queue |= COMMAND_SETCOMPRESSION;
-	}
+		if (cam->first_frame &&
+		    cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
+			cam->first_frame = 0;
+			cam->cmd_queue |= COMMAND_SETCOMPRESSION;
+		}
 #else
-	if( cam->first_frame ) {
-		cam->first_frame = 0;
-		cam->cmd_queue |= COMMAND_SETCOMPRESSION;
-		cam->cmd_queue |= COMMAND_SETEXPOSURE;
-	}
+		if (cam->first_frame) {
+			cam->first_frame = 0;
+			cam->cmd_queue |= COMMAND_SETCOMPRESSION;
+			cam->cmd_queue |= COMMAND_SETEXPOSURE;
+		}
 #endif
-end:
-	return;
+	}
 }
 
 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
 {
 	int retval = 0;
 
-	if( cam->frame_buf == NULL ) { /* we do lazy allocation */
-		if( (retval = allocate_frame_buf(cam)) ) {
+	if (!cam->frame_buf) {
+		/* we do lazy allocation */
+		if ((retval = allocate_frame_buf(cam)))
 			return retval;
-		}
 	}
 	
 	/* FIXME: the first frame seems to be captured by the camera
@@ -2287,25 +2602,30 @@
 	   that one, the next one is generated with our settings
 	   (exposure, color balance, ...)
 	*/
-	if(cam->first_frame) {
-	  cam->curframe = vm->frame;
-	  cam->frame[cam->curframe].state = FRAME_READY;
-	  fetch_frame(cam);
-	  if(cam->frame[cam->curframe].state != FRAME_DONE) retval=-EIO;
+	if (cam->first_frame) {
+		cam->curframe = vm->frame;
+		cam->frame[cam->curframe].state = FRAME_READY;
+		fetch_frame(cam);
+		if (cam->frame[cam->curframe].state != FRAME_DONE)
+			retval = -EIO;
 	}
 	cam->curframe = vm->frame;
-        cam->frame[cam->curframe].state = FRAME_READY;
-        fetch_frame(cam);
-        if(cam->frame[cam->curframe].state != FRAME_DONE) retval=-EIO;
+	cam->frame[cam->curframe].state = FRAME_READY;
+	fetch_frame(cam);
+	if (cam->frame[cam->curframe].state != FRAME_DONE)
+		retval=-EIO;
 
 	return retval;
 }
   
 static int goto_high_power(struct cam_data *cam)
 {
-	if(do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0)) return -1;
-	if(do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) return -1;
-	if(cam->params.status.systemState == HI_POWER_STATE) {
+	if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
+		return -1;
+	mdelay(100);		/* windows driver does it too */
+	if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+		return -1;
+	if (cam->params.status.systemState == HI_POWER_STATE) {
 		DBG("camera now in HIGH power state\n");
 		return 0;
 	}
@@ -2315,14 +2635,15 @@
 
 static int goto_low_power(struct cam_data *cam)
 {
-	if(do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0)) return -1;
-	if(do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0)) return -1;
-	if(cam->params.status.systemState == LO_POWER_STATE) {
+	if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
+		return -1;
+	if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+		return -1;
+	if (cam->params.status.systemState == LO_POWER_STATE) {
 		DBG("camera now in LOW power state\n");
 		return 0;
 	}
 	printstatus(cam);
-	mdelay(100);		/* windows driver does it too */
 	return -1;
 }
 
@@ -2344,21 +2665,23 @@
 	     cam->params.colourBalance.redGain,
 	     cam->params.colourBalance.greenGain,
 	     cam->params.colourBalance.blueGain);
-
-	return;
 }
 
 static void set_camera_state(struct cam_data *cam)
 {
-	if(cam->params.colourBalance.balanceMode != 1) {
+	if(cam->params.colourBalance.balanceModeIsAuto) {
+		do_command(cam, CPIA_COMMAND_SetColourBalance, 
+	        	   2, 0, 0, 0);
+	} else {
 		do_command(cam, CPIA_COMMAND_SetColourBalance, 
 	        	   1,
 	        	   cam->params.colourBalance.redGain,
 	        	   cam->params.colourBalance.greenGain,
 	        	   cam->params.colourBalance.blueGain);
+		do_command(cam, CPIA_COMMAND_SetColourBalance, 
+	        	   3, 0, 0, 0);
 	}
-	if(cam->params.colourBalance.balanceMode == 0)
-		cam->params.colourBalance.balanceMode = 2;
+
 
 	do_command_extended(cam, CPIA_COMMAND_SetExposure,
 			    cam->params.exposure.gainMode, 1, 1,
@@ -2367,19 +2690,19 @@
 	                    cam->params.exposure.fineExp,
 	                    cam->params.exposure.coarseExpLo,
 	                    cam->params.exposure.coarseExpHi,
-	                    cam->params.exposure.redComp,
-	                    cam->params.exposure.green1Comp,
-	                    cam->params.exposure.green2Comp,
-	                    cam->params.exposure.blueComp);
+			    cam->params.exposure.redComp,
+			    cam->params.exposure.green1Comp,
+			    cam->params.exposure.green2Comp,
+			    cam->params.exposure.blueComp);
 	do_command_extended(cam, CPIA_COMMAND_SetExposure,
 			    0, 3, 0, 0,
 			    0, 0, 0, 0, 0, 0, 0, 0);
 
-	if(cam->params.exposure.gainMode == 0)
+	if (!cam->params.exposure.gainMode)
 		cam->params.exposure.gainMode = 2;
-	if(cam->params.exposure.expMode == 0)
+	if (!cam->params.exposure.expMode)
 		cam->params.exposure.expMode = 2;
-	if(cam->params.exposure.centreWeight == 0)
+	if (!cam->params.exposure.centreWeight)
 		cam->params.exposure.centreWeight = 1;
 	
 	cam->cmd_queue = COMMAND_SETCOMPRESSION |
@@ -2407,32 +2730,25 @@
 {
 	/* GetCPIAVersion */
 	do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
-	printk(KERN_INFO "  CPIA Version: %d.%02d (%d.%d)\n",
-	       cam->params.version.firmwareVersion,
-	       cam->params.version.firmwareRevision,
-	       cam->params.version.vcVersion,
-	       cam->params.version.vcRevision);
 
 	/* GetPnPID */
 	do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
-	printk(KERN_INFO "  CPIA PnP-ID: %04x:%04x:%04x\n",
-	       cam->params.pnpID.vendor, cam->params.pnpID.product,
-	       cam->params.pnpID.deviceRevision);
 }
 
 /* initialize camera */
 static int reset_camera(struct cam_data *cam)
 {
 	/* Start the camera in low power mode */
-	if(goto_low_power(cam)) {
-		if( cam->params.status.systemState != 0x4 ) {
+	if (goto_low_power(cam)) {
+		if (cam->params.status.systemState != WARM_BOOT_STATE)
 			return -ENODEV;
-		}
+
 		/* FIXME: this is just dirty trial and error */
 		reset_camera_struct(cam);
 		goto_high_power(cam);
 		do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
-		if(goto_low_power(cam)) return -NODEV;
+		if (goto_low_power(cam))
+			return -NODEV;
 	}
 	
 	/* procedure described in developer's guide p3-28 */
@@ -2440,11 +2756,15 @@
 	/* Check the firmware version FIXME: should we check PNPID? */
 	cam->params.version.firmwareVersion = 0;
 	get_version_information(cam);
-	if(cam->params.version.firmwareVersion != 1) {
+	if (cam->params.version.firmwareVersion != 1)
 		return -ENODEV;
-	}
+	
+	/* GA 04/14/00 - set QX3 detected flag */
+	cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
+					cam->params.pnpID.product == 0x0001);
 
-	/* The fatal error checking should be done after the camera powers up (developer's guide p 3-38) */
+	/* The fatal error checking should be done after
+	 * the camera powers up (developer's guide p 3-38) */
 
 	/* Set streamState before transition to high power to avoid bug
 	 * in firmware 1-02 */
@@ -2452,40 +2772,38 @@
 	           STREAM_NOT_READY, 0);
 	
 	/* GotoHiPower */
-	if(goto_high_power(cam))
+	if (goto_high_power(cam))
 		return -ENODEV;
 
-	
 	/* Check the camera status */
-	if(do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
+	if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
 		return -EIO;
-	if(cam->params.status.fatalError) {
-		DBG("fatal_error:              %#04x\n",cam->params.status.fatalError);
-		DBG("vp_status:                %#04x\n",cam->params.status.vpStatus);
-		if(cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
+
+	if (cam->params.status.fatalError) {
+		DBG("fatal_error:              %#04x\n",
+		    cam->params.status.fatalError);
+		DBG("vp_status:                %#04x\n",
+		    cam->params.status.vpStatus);
+		if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
 			/* Fatal error in camera */
 			return -EIO;
-		} else if(cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)){
+		} else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
 			/* Firmware 1-02 may do this for parallel port cameras,
 			 * just clear the flags (developer's guide p 3-38) */
 			do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
 			           FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
 		}
 	}
-		
+	
 	/* Check the camera status again */
-	if(cam->params.status.fatalError) {
-		if(cam->params.status.fatalError)
+	if (cam->params.status.fatalError) {
+		if (cam->params.status.fatalError)
 			return -EIO;
 	}
 	
 	/* VPVersion can't be retrieved before the camera is in HiPower,
 	 * so get it here instead of in get_version_information. */
 	do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
-	printk(KERN_INFO "  VP-Version: %d.%d %04x\n",
-	       cam->params.vpVersion.vpVersion,
-	       cam->params.vpVersion.vpRevision,
-	       cam->params.vpVersion.cameraHeadID);
 
 	/* set camera to a known state */
 	set_camera_state(cam);
@@ -2499,54 +2817,60 @@
 	int i;
 	struct cam_data *cam = dev->priv;
 
-	DBG("cpia_open\n");
-
-	if(cam->open_count > 0) {
-		DBG("Camera[%d] already open\n",cam->index);
+	if (!cam) {
+		DBG("Internal error, cam_data not found!\n");
+		return -EBUSY;
+	}
+	    
+	if (cam->open_count > 0) {
+		DBG("Camera already open\n");
 		return -EBUSY;
 	}
 	
-	if(cam->raw_image == NULL) {
-		if((cam->raw_image=rvmalloc(CPIA_MAX_IMAGE_SIZE)) == NULL){
+	if (!cam->raw_image) {
+		cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
+		if (!cam->raw_image)
 			return -ENOMEM;
-		}
 	}
-	if(cam->decompressed_frame.data == NULL) {
-		cam->decompressed_frame.data=rvmalloc(CPIA_MAX_FRAME_SIZE);
-		if(cam->decompressed_frame.data == NULL){
+
+	if (!cam->decompressed_frame.data) {
+		cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
+		if (!cam->decompressed_frame.data) {
 			rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-			cam->raw_image=NULL;
+			cam->raw_image = NULL;
 			return -ENOMEM;
 		}
 	}
 	
 	/* open cpia */
-	if (cam->ops->open(cam->index, &cam->lowlevel_data)) {
+	if (cam->ops->open(cam->lowlevel_data)) {
 		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
-		cam->decompressed_frame.data=NULL;
+		cam->decompressed_frame.data = NULL;
 		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-		cam->raw_image=NULL;
+		cam->raw_image = NULL;
 		return -ENODEV;
 	}
 	
 	/* reset the camera */
-	if((i = reset_camera(cam)) != 0) {
+	if ((i = reset_camera(cam)) != 0) {
 		cam->ops->close(cam->lowlevel_data);
 		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
-		cam->decompressed_frame.data=NULL;
+		cam->decompressed_frame.data = NULL;
 		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-		cam->raw_image=NULL;
+		cam->raw_image = NULL;
 		return i;
 	}
 	
 	/* Set ownership of /proc/cpia/videoX to current user */
-	if(cam->proc_entry != NULL)
+	if(cam->proc_entry)
 		cam->proc_entry->uid = current->uid;
-	
+
 	/* set mark for loading first frame uncompressed */
 	cam->first_frame = 1;
-	cam->busy_lock = MUTEX;
-        
+
+	/* init it to something */
+	cam->mmap_kludge = 0;
+	
 	++cam->open_count;
 #ifdef MODULE
 	MOD_INC_USE_COUNT;
@@ -2554,78 +2878,51 @@
 	return 0;
 }
 
-/* FIXME */
 static void cpia_close(struct video_device *dev)
 {
 	struct cam_data *cam;
 
-	DBG("cpia_close\n");
 	cam = dev->priv;
 
-	if(cam->ops == NULL) {
-		if(--cam->open_count == 0) {
-			int i;
-			video_unregister_device(dev);
-			/* Need a lock when adding/removing cameras */
-			lock_kernel();
-			if(cam->raw_image) {
-				rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-				cam->raw_image=0;
-			}
-			if(cam->decompressed_frame.data) {
-				rvfree(cam->decompressed_frame.data,
-				       CPIA_MAX_FRAME_SIZE);
-				cam->decompressed_frame.data=0;
-			}
-			if(cam->frame_buf) {
-				free_frame_buf(cam);
-			}
-			for(i=0; i<CPIA_MAXCAMS; ++i) {
-				if(camera[i] == cam) break;
-			}
-			kfree(cam);
-			if(i != CPIA_MAXCAMS) { /* should always be true */
-				camera[i] = NULL;
-			}
-			unlock_kernel();
-		}
-#ifdef MODULE
-		MOD_DEC_USE_COUNT;
-#endif
-		return;
-	}
+	if (cam->ops) {
+	        /* Return ownership of /proc/cpia/videoX to root */
+		if(cam->proc_entry)
+			cam->proc_entry->uid = 0;
 	
-	/* Return ownership of /proc/cpia/videoX to root */
-	if(cam->proc_entry != NULL)
-		cam->proc_entry->uid = 0;
-	
-	/* save camera state for later open (developers guide ch 3.5.3) */
-	save_camera_state(cam);
+		/* save camera state for later open (developers guide ch 3.5.3) */
+		save_camera_state(cam);
 
-	/* GotoLoPower */
-	goto_low_power(cam);
+		/* GotoLoPower */
+		goto_low_power(cam);
 
-	/* cleanup internal state stuff */
-	free_frames(cam->frame);
+		/* Update the camera ststus */
+		do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
 
-	/* Update the camera ststus */
-	do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+		/* cleanup internal state stuff */
+		free_frames(cam->frame);
 
-	/* close cpia */
-	cam->ops->close(cam->lowlevel_data);
+		/* close cpia */
+		cam->ops->close(cam->lowlevel_data);
+	}
 
-	if(--cam->open_count == 0) {
+	if (--cam->open_count == 0) {
 		/* clean up capture-buffers */
-		if(cam->raw_image) {
+		if (cam->raw_image) {
 			rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-			cam->raw_image = 0;
+			cam->raw_image = NULL;
 		}
-		if(cam->decompressed_frame.data) {
+
+		if (cam->decompressed_frame.data) {
 			rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
-			cam->decompressed_frame.data = 0;
+			cam->decompressed_frame.data = NULL;
 		}
-		if(cam->frame_buf) {
+
+		if (cam->frame_buf)
 			free_frame_buf(cam);
+
+		if (!cam->ops) {
+			video_unregister_device(dev);
+			kfree(cam);
 		}
 	}
 	
@@ -2637,26 +2934,27 @@
 }
 
 static long cpia_read(struct video_device *dev, char *buf,
-                     unsigned long count, int noblock)
+                      unsigned long count, int noblock)
 {
 	struct cam_data *cam = dev->priv;
 
 	/* make this _really_ smp and multithredi-safe */
-	if( down_interruptible(&cam->busy_lock) ) {
+	if (down_interruptible(&cam->busy_lock))
 		return -EINTR;
-	}
 
 	if (!buf) {
 		DBG("buf NULL\n");
 		up(&cam->busy_lock);
 		return -EINVAL;
 	}
-	if(count == 0) {
+
+	if (!count) {
 		DBG("count 0\n");
 		up(&cam->busy_lock);
 		return 0;
 	}
-	if(!cam->ops) {
+
+	if (!cam->ops) {
 		DBG("ops NULL\n");
 		up(&cam->busy_lock);
 		return -ENODEV;
@@ -2664,8 +2962,9 @@
 
 	/* upload frame */
 	cam->decompressed_frame.state = FRAME_READY;
+	cam->mmap_kludge=0;
 	fetch_frame(cam);
-	if( cam->decompressed_frame.state != FRAME_DONE ) {
+	if (cam->decompressed_frame.state != FRAME_DONE) {
 		DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
 		    cam->decompressed_frame.state);
 		up(&cam->busy_lock);
@@ -2674,12 +2973,13 @@
 	cam->decompressed_frame.state = FRAME_UNUSED;
 
 	/* copy data to user space */
-	if(cam->decompressed_frame.count > count) {
-		DBG("count wrong\n");
+	if (cam->decompressed_frame.count > count) {
+		DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
+		    count);
 		up(&cam->busy_lock);
 		return -EFAULT;
 	}
-	if(copy_to_user(buf, cam->decompressed_frame.data,
+	if (copy_to_user(buf, cam->decompressed_frame.data,
 	                cam->decompressed_frame.count)) {
 		DBG("copy_to_user failed\n");
 		up(&cam->busy_lock);
@@ -2695,31 +2995,34 @@
 	struct cam_data *cam = dev->priv;
 	int retval = 0;
 
+	if (!cam || !cam->ops)
+		return -ENODEV;
+	
 	/* make this _really_ smp-safe */
-	if( down_interruptible(&cam->busy_lock) ) {
+	if (down_interruptible(&cam->busy_lock))
 		return -EINTR;
-	}
+
 	//DBG("cpia_ioctl: %u\n", ioctlnr);
 
 	switch (ioctlnr) {
-
 	/* query capabilites */
 	case VIDIOCGCAP:
 	{
 		struct video_capability b;
 
 		DBG("VIDIOCGCAP\n");
-		strcpy(b.name, "CPiA Parport Camera");
+		strcpy(b.name, "CPiA Camera");
 		b.type = VID_TYPE_CAPTURE;
 		b.channels = 1;
 		b.audios = 0;
-		b.maxwidth = 352;         /* VIDEOSIZE_CIF */
+		b.maxwidth = 352;	/* VIDEOSIZE_CIF */
 		b.maxheight = 288;
-		b.minwidth = 48;         /* VIDEOSIZE_48_48 */
+		b.minwidth = 48;	/* VIDEOSIZE_48_48 */
 		b.minheight = 48;
 
 		if (copy_to_user(arg, &b, sizeof(b)))
 			retval = -EFAULT;
+
 		break;
 	}
 
@@ -2782,13 +3085,15 @@
 			retval = -EFAULT;
 			break;
 		}
+
 		/* check validity */
 		DBG("palette: %d\n", vp.palette);
 		DBG("depth: %d\n", vp.depth);
-		if ( !valid_mode(vp.palette, vp.depth) ) {
+		if (!valid_mode(vp.palette, vp.depth)) {
 			retval = -EINVAL;
 			break;
 		}
+
 		down(&cam->param_lock);
 		/* brightness, colour, contrast need no check 0-65535 */
 		memcpy( &cam->vp, &vp, sizeof(vp) );
@@ -2799,12 +3104,13 @@
 		/* contrast is in steps of 8, so round */
 		cam->params.colourParams.contrast =
 			((cam->params.colourParams.contrast + 3) / 8) * 8;
-		if(cam->params.version.firmwareVersion == 1 &&
-		   cam->params.version.firmwareRevision == 2 &&
-		   cam->params.colourParams.contrast > 80) {
+		if (cam->params.version.firmwareVersion == 1 &&
+		    cam->params.version.firmwareRevision == 2 &&
+		    cam->params.colourParams.contrast > 80) {
 			/* 1-02 firmware limits contrast to 80 */
 			cam->params.colourParams.contrast = 80;
 		}
+
 		/* queue command to update camera */
 		cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
 		up(&cam->param_lock);
@@ -2845,9 +3151,10 @@
 		* is requested by the user???
 		*/
 		down(&cam->param_lock);
-		if(vw.width!=cam->vw.width || vw.height!=cam->vw.height) {
+		if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
 			int video_size = match_videosize(vw.width, vw.height);
-			if(video_size < 0) {
+
+			if (video_size < 0) {
 				retval = -EINVAL;
 				up(&cam->param_lock);
 				break;
@@ -2863,7 +3170,7 @@
 
 		/* setformat ignored by camera during streaming,
 		 * so stop/dispatch/start */
-		if(cam->cmd_queue & COMMAND_SETFORMAT) {
+		if (cam->cmd_queue & COMMAND_SETFORMAT) {
 			DBG("\n");
 			dispatch_commands(cam);
 		}
@@ -2882,10 +3189,10 @@
 		memset(&vm, 0, sizeof(vm));
 		vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
 		vm.frames = FRAME_NUM;
-		for( i=0; i<FRAME_NUM; i++ ) {
-			vm.offsets[i] = CPIA_MAX_FRAME_SIZE*i;
-		}
-		if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+		for (i = 0; i < FRAME_NUM; i++)
+			vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
+
+		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
 			retval = -EFAULT;
 
 		break;
@@ -2900,7 +3207,7 @@
 			retval = -EFAULT;
 			break;
 		}
-#if 0
+#if 1
 		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
 		    vm.width, vm.height);
 #endif
@@ -2913,6 +3220,8 @@
 		cam->vp.palette = vm.format;
 		switch(vm.format) {
 		case VIDEO_PALETTE_GREY:
+			cam->vp.depth = 8;
+			break;
 		case VIDEO_PALETTE_RGB555:
 		case VIDEO_PALETTE_RGB565:
 		case VIDEO_PALETTE_YUV422:
@@ -2930,15 +3239,16 @@
 			retval = -EINVAL;
 			break;
 		}
-		if(retval != 0) break;
+		if (retval)
+			break;
 
 		/* set video size */
 		video_size = match_videosize(vm.width, vm.height);
-		if(cam->video_size<0) {
+		if (cam->video_size < 0) {
 			retval = -EINVAL;
 			break;
 		}
-		if( video_size != cam->video_size ) {
+		if (video_size != cam->video_size) {
 			cam->video_size = video_size;
 			set_vw_size(cam);
 			cam->cmd_queue |= COMMAND_SETFORMAT;
@@ -2949,6 +3259,7 @@
 		    cam->vw.width, cam->vw.height);
 #endif
 		/* according to v4l-spec we must start streaming here */
+		cam->mmap_kludge = 1;
 		retval = capture_frame(cam, &vm);
 
 		break;
@@ -2964,7 +3275,7 @@
 		}
 		//DBG("VIDIOCSYNC: %d\n", frame);
 
-		if (frame<0||frame>=FRAME_NUM) {
+		if (frame<0 || frame >= FRAME_NUM) {
 			retval = -EINVAL;
 			break;
 		}
@@ -2982,7 +3293,7 @@
 			//DBG("VIDIOCSYNC: %d synced\n", frame);
 			break;
 		}
-		if(retval == -EINTR) {
+		if (retval == -EINTR) {
 			/* FIXME - xawtv does not handle this nice */
 			retval = 0;
 		}
@@ -3040,49 +3351,57 @@
 {
 	unsigned long start = (unsigned long)adr;
 	unsigned long page, pos;
-	struct cam_data *cam;
+	struct cam_data *cam = dev->priv;
 	int retval;
 
+	if (!cam || !cam->ops)
+		return -ENODEV;
+	
 	DBG("cpia_mmap: %ld\n", size);
 
-	if(size > FRAME_NUM*CPIA_MAX_FRAME_SIZE){
+	if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
 		return -EINVAL;
-	}
-
-	cam = dev->priv;
 
+	if (!cam || !cam->ops)
+		return -ENODEV;
+	
 	/* make this _really_ smp-safe */
-	if( down_interruptible(&cam->busy_lock) ) {
+	if (down_interruptible(&cam->busy_lock))
 		return -EINTR;
-	}
 
-	if( cam->frame_buf == NULL ) { /* we do lazy allocation */
-		if( (retval = allocate_frame_buf(cam)) ) {
+	if (!cam->frame_buf) {	/* we do lazy allocation */
+		if ((retval = allocate_frame_buf(cam))) {
 			up(&cam->busy_lock);
 			return retval;
 		}
 	}
+
 	pos = (unsigned long)(cam->frame_buf);
 	while (size > 0) {
-		page = kvirt_to_phys(pos);
+		page = kvirt_to_pa(pos);
 		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
 			up(&cam->busy_lock);
 			return -EAGAIN;
 		}
-		start+=PAGE_SIZE;
-		pos+=PAGE_SIZE;
-		if (size > PAGE_SIZE) size-=PAGE_SIZE;
-		else size=0;
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
 	}
 
 	DBG("cpia_mmap: %ld\n", size);
 	up(&cam->busy_lock);
+
 	return 0;
 }
 
 int cpia_video_init(struct video_device *vdev)
 {
+#ifdef CONFIG_PROC_FS
 	create_proc_cpia_cam(vdev->priv);
+#endif
 	return 0;
 }
 
@@ -3124,7 +3443,7 @@
 	cam->params.exposure.green1Comp = 214;
 	cam->params.exposure.green2Comp = 214;
 	cam->params.exposure.blueComp = 230;
-	cam->params.colourBalance.balanceMode = 2;	/* auto color balance */
+	cam->params.colourBalance.balanceModeIsAuto = 1;
 	cam->params.colourBalance.redGain = 32;
 	cam->params.colourBalance.greenGain = 6;
 	cam->params.colourBalance.blueGain = 92;
@@ -3151,16 +3470,15 @@
 	cam->params.compressionParams.decimationThreshMod = 2;
 	/* End of default values from Software Developer's Guide */
 	
-	/* Start with a reasonable transfer rate */
-	cam->transfer_rate = 500;
+	cam->transfer_rate = 0;
 	
 	/* Set Sensor FPS to 15fps. This seems better than 30fps
 	 * for indoor lighting. */
 	cam->params.sensorFps.divisor = 1;
 	cam->params.sensorFps.baserate = 1;
 	
-	cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
-	cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
+	cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
+	cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
 	
 	cam->params.format.subSample = SUBSAMPLE_422;
 	cam->params.format.yuvOrder = YUVORDER_YUYV;
@@ -3168,8 +3486,14 @@
 	cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
 	cam->params.compressionTarget.frTargeting =
 		CPIA_COMPRESSION_TARGET_QUALITY;
-	cam->params.compressionTarget.targetFR = 7; /* FIXME? */
-	cam->params.compressionTarget.targetQ = 10; /* FIXME? */
+	cam->params.compressionTarget.targetFR = 15; /* From windows driver */
+	cam->params.compressionTarget.targetQ = 5; /* From windows driver */
+	
+	cam->params.qx3.qx3_detected = 0;
+	cam->params.qx3.toplight = 0;
+	cam->params.qx3.bottomlight = 0;
+	cam->params.qx3.button = 0;
+	cam->params.qx3.cradled = 0;
 
 	cam->video_size = VIDEOSIZE_CIF;
 	
@@ -3179,7 +3503,7 @@
 	cam->vp.contrast = 32768;    /* 50% */
 	cam->vp.whiteness = 0;       /* not used -> grayscale only */
 	cam->vp.depth = 0;           /* FIXME: to be set by user? */
-	cam->vp.palette = 0;         /* FIXME: to be set by user? */
+	cam->vp.palette = VIDEO_PALETTE_RGB24;         /* FIXME: to be set by user? */
 
 	cam->vw.x = 0;
 	cam->vw.y = 0;
@@ -3201,11 +3525,13 @@
                                struct cpia_camera_ops *ops )
 {
 	int i;
+
 	/* Default everything to 0 */
 	memset(cam, 0, sizeof(struct cam_data));
 
 	cam->ops = ops;
-	cam->param_lock = MUTEX;
+	init_MUTEX(&cam->param_lock);
+	init_MUTEX(&cam->busy_lock);
 
 	reset_camera_struct(cam);
 
@@ -3215,7 +3541,7 @@
 	cam->vdev.priv = cam;
 	
 	cam->curframe = 0;
-	for( i=0; i<FRAME_NUM; i++) {
+	for (i = 0; i < FRAME_NUM; i++) {
 		cam->frame[i].width = 0;
 		cam->frame[i].height = 0;
 		cam->frame[i].state = FRAME_UNUSED;
@@ -3225,95 +3551,84 @@
 	cam->decompressed_frame.height = 0;
 	cam->decompressed_frame.state = FRAME_UNUSED;
 	cam->decompressed_frame.data = NULL;
-
-	return;
 }
 
-int cpia_register_camera(struct cpia_camera_ops *ops)
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
 {
-	int i;
-	struct cam_data *cam;
+        struct cam_data *camera;
+	
 	/* Need a lock when adding/removing cameras.  This doesn't happen
 	 * often and doesn't take very long, so grabbing the kernel lock
 	 * should be OK. */
-	lock_kernel();
-	for(i=0; i < CPIA_MAXCAMS && camera[i] != NULL; ++i); /* no loop body */
-	if(i == CPIA_MAXCAMS) {
-		unlock_kernel();
-		return -ENODEV;
-	}
 	
-	if((camera[i] = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
+	if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
 		unlock_kernel();
-		return -ENOMEM;
+		return NULL;
 	}
 	
-	init_camera_struct( camera[i], ops );
-	camera[i]->index = i;
-
+	init_camera_struct( camera, ops );
+	camera->lowlevel_data = lowlevel;
+	
 	/* register v4l device */
-	if (video_register_device(&camera[i]->vdev, VFL_TYPE_GRABBER) == -1) {
-		kfree(camera[i]);
-		camera[i] = NULL;
+	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) {
+		kfree(camera);
 		unlock_kernel();
 		printk(KERN_DEBUG "video_register_device failed\n");
-		return -ENODEV;
+		return NULL;
 	}
 
-	unlock_kernel();
-	
-	/* FIXME */
-#if 0
-	cam = camera[i];
+	/* get version information from camera: open/reset/close */
+
 	/* open cpia */
-	if (cam->ops->open(cam->index, &cam->lowlevel_data)) {
-		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
-		cam->decompressed_frame.data=NULL;
-		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-		cam->raw_image=NULL;
-		return -ENODEV;
-	}
+	if (camera->ops->open(camera->lowlevel_data))
+		return camera;
 	
 	/* reset the camera */
-	if((i = reset_camera(cam)) != 0) {
-		cam->ops->close(cam->lowlevel_data);
-		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
-		cam->decompressed_frame.data=NULL;
-		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
-		cam->raw_image=NULL;
-		return i;
+	if (reset_camera(camera) != 0) {
+		camera->ops->close(camera->lowlevel_data);
+		return camera;
 	}
-#endif	
-	return i;
+
+	/* close cpia */
+	camera->ops->close(camera->lowlevel_data);
+
+	printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
+	       camera->params.version.firmwareVersion,
+	       camera->params.version.firmwareRevision,
+	       camera->params.version.vcVersion,
+	       camera->params.version.vcRevision);
+	printk(KERN_INFO "  CPiA PnP-ID: %04x:%04x:%04x\n",
+	       camera->params.pnpID.vendor,
+	       camera->params.pnpID.product,
+	       camera->params.pnpID.deviceRevision);
+	printk(KERN_INFO "  VP-Version: %d.%d %04x\n",
+	       camera->params.vpVersion.vpVersion,
+	       camera->params.vpVersion.vpRevision,
+	       camera->params.vpVersion.cameraHeadID);
+
+	return camera;
 }
 
-void cpia_unregister_camera(int camnr)
+void cpia_unregister_camera(struct cam_data *cam)
 {
-	struct cam_data *cam;
-	if(camnr >= CPIA_MAXCAMS || camera[camnr] == NULL) return;
-	cam = camera[camnr];
-	
-	DBG("unregistering video\n");
-	/* FIXME: Is this safe if the device is open? */
-	video_unregister_device(&cam->vdev);
-	
-	/* Need a lock when adding/removing cameras.  This doesn't happen
-	 * often and doesn't take very long, so grabbing the kernel lock
-	 * should be OK. */
-	lock_kernel();
+	if (!cam->open_count) {
+		DBG("unregistering video\n");
+		video_unregister_device(&cam->vdev);
+	} else {
+		LOG("/dev/video%d removed while open, "
+		    "deferring video_unregister_device\n", cam->vdev.minor);
+		DBG("camera open -- setting ops to NULL\n");
+		cam->ops = NULL;
+	}
 	
+#ifdef CONFIG_PROC_FS
 	DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
 	destroy_proc_cpia_cam(cam);
-	
-	if(cam->open_count == 0) {
+#endif	
+	if (!cam->open_count) {
 		DBG("freeing camera\n");
-		kfree(camera[camnr]);
-		camera[camnr] = NULL;
-	} else {
-		DBG("camera open -- setting ops to NULL\n");
-		cam->ops = NULL;
+		kfree(cam);
 	}
-	unlock_kernel();
 }
 
 /****************************************************************************
@@ -3327,7 +3642,9 @@
 {
 	printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
 	       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+#ifdef CONFIG_PROC_FS
 	proc_cpia_create();
+#endif
 #ifdef CONFIG_KMOD
 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
 	request_module("cpia_pp");
@@ -3341,14 +3658,9 @@
 
 void cleanup_module(void)
 {
-	int i;
-	for(i=0; i<CPIA_MAXCAMS; ++i) {
-		if(camera[i]) {
-			video_unregister_device(&camera[i]->vdev);
-		}
-	}
-	
+#ifdef CONFIG_PROC_FS
 	proc_cpia_destroy();
+#endif
 }
 
 #else
@@ -3357,25 +3669,25 @@
 {
 	printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
 	       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
+#ifdef CONFIG_PROC_FS
 	proc_cpia_create();
+#endif
 
-#ifdef MODULE
+#ifdef CONFIG_VIDEO_CPIA_PP
+	cpia_pp_init();
+#endif
 #ifdef CONFIG_KMOD
 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
 	request_module("cpia_pp");
 #endif
+
 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
 	request_module("cpia_usb");
 #endif
 #endif	/* CONFIG_KMOD */
-#else	/* !MODULE */
-#ifdef CONFIG_VIDEO_CPIA_PP
-	cpia_pp_init();
-#endif
 #ifdef CONFIG_VIDEO_CPIA_USB
 	cpia_usb_init();
 #endif
-#endif	/* !MODULE */
 	return 0;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/cpia.h linux.18p8/drivers/char/cpia.h
--- linux.vanilla/drivers/char/cpia.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/cpia.h	Fri Sep 15 15:05:11 2000
@@ -0,0 +1,430 @@
+#ifndef cpia_h
+#define cpia_h
+
+/*
+ * CPiA Parallel Port Video4Linux driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * (C) Copyright 1999 Bas Huisman,
+ *                    Peter Pregler,
+ *                    Scott J. Bertin,
+ *                    VLSI Vision Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define CPIA_MAJ_VER	1
+#define CPIA_MIN_VER    0
+#define CPIA_PATCH_VER	0
+
+#define CPIA_PP_MAJ_VER       1
+#define CPIA_PP_MIN_VER       0
+#define CPIA_PP_PATCH_VER     0
+
+#define CPIA_MAX_FRAME_SIZE_UNALIGNED	(352 * 288 * 4)   /* CIF at RGB32 */
+#define CPIA_MAX_FRAME_SIZE	((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
+
+#ifdef __KERNEL__
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+
+struct cpia_camera_ops
+{
+	/* open sets privdata to point to structure for this camera.
+         * Returns negative value on error, otherwise 0.
+	 */
+	int (*open)(void *privdata);
+	
+	/* Registers callback function cb to be called with cbdata
+	 * when an image is ready.  If cb is NULL, only single image grabs
+	 * should be used.  cb should immediately call streamRead to read
+	 * the data or data may be lost. Returns negative value on error,
+	 * otherwise 0.
+	 */
+	int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
+	                        void *cbdata);
+	
+	/* transferCmd sends commands to the camera.  command MUST point to
+	 * an  8 byte buffer in kernel space. data can be NULL if no extra
+	 * data is needed.  The size of the data is given by the last 2
+	 * bytes of comand.  data must also point to memory in kernel space.
+	 * Returns negative value on error, otherwise 0.
+	 */
+	int (*transferCmd)(void *privdata, u8 *command, u8 *data);
+
+	/* streamStart initiates stream capture mode.
+	 * Returns negative value on error, otherwise 0.
+	 */
+	int (*streamStart)(void *privdata);
+	
+	/* streamStop terminates stream capture mode.
+	 * Returns negative value on error, otherwise 0.
+	 */
+	int (*streamStop)(void *privdata);
+        
+	/* streamRead reads a frame from the camera.  buffer points to a
+         * buffer large enough to hold a complete frame in kernel space.
+         * noblock indicates if this should be a non blocking read.
+	 * Returns the number of bytes read, or negative value on error.
+         */
+	int (*streamRead)(void *privdata, u8 *buffer, int noblock);
+	
+	/* close disables the device until open() is called again.
+	 * Returns negative value on error, otherwise 0.
+	 */
+	int (*close)(void *privdata);
+	
+	/* If wait_for_stream_ready is non-zero, wait until the streamState
+	 * is STREAM_READY before calling streamRead.
+	 */
+	int wait_for_stream_ready;
+};
+
+struct cpia_frame {
+	u8 *data;
+	int count;
+	int width;
+	int height;
+	volatile int state;
+};
+
+struct cam_params {
+	struct {
+		u8 firmwareVersion;
+		u8 firmwareRevision;
+		u8 vcVersion;
+		u8 vcRevision;
+	} version;
+	struct {
+		u16 vendor;
+		u16 product;
+		u16 deviceRevision;
+	} pnpID;
+	struct {
+		u8 vpVersion;
+		u8 vpRevision;
+		u16 cameraHeadID;
+	} vpVersion;
+	struct {
+		u8 systemState;
+		u8 grabState;
+		u8 streamState;
+		u8 fatalError;
+		u8 cmdError;
+		u8 debugFlags;
+		u8 vpStatus;
+		u8 errorCode;
+	} status;
+	struct {
+		u8 brightness;
+		u8 contrast;
+		u8 saturation;
+	} colourParams;
+	struct {
+		u8 gainMode;
+		u8 expMode;
+		u8 compMode;
+		u8 centreWeight;
+		u8 gain;
+		u8 fineExp;
+		u8 coarseExpLo;
+		u8 coarseExpHi;
+		u8 redComp;
+		u8 green1Comp;
+		u8 green2Comp;
+		u8 blueComp;
+	} exposure;
+	struct {
+		u8 balanceModeIsAuto;
+		u8 redGain;
+		u8 greenGain;
+		u8 blueGain;
+	} colourBalance;
+	struct {
+		u8 divisor;
+		u8 baserate;
+	} sensorFps;
+	struct {
+		u8 gain1;
+		u8 gain2;
+		u8 gain4;
+		u8 gain8;
+	} apcor;
+	struct {
+		u8 flickerMode;
+		u8 coarseJump;
+		u8 allowableOverExposure;
+	} flickerControl;
+	struct {
+		u8 gain1;
+		u8 gain2;
+		u8 gain4;
+		u8 gain8;
+	} vlOffset;
+	struct {
+		u8 mode;
+		u8 decimation;
+	} compression;
+	struct {
+		u8 frTargeting;
+		u8 targetFR;
+		u8 targetQ;
+	} compressionTarget;
+	struct {
+		u8 yThreshold;
+		u8 uvThreshold;
+	} yuvThreshold;
+	struct {
+		u8 hysteresis;
+		u8 threshMax;
+		u8 smallStep;
+		u8 largeStep;
+		u8 decimationHysteresis;
+		u8 frDiffStepThresh;
+		u8 qDiffStepThresh;
+		u8 decimationThreshMod;
+	} compressionParams;
+	struct {
+		u8 videoSize;		/* CIF/QCIF */
+		u8 subSample;
+		u8 yuvOrder;
+	} format;
+
+        struct {     /* GA 04/14/00 - Intel QX3 specific data */
+	        u8 qx3_detected;        /* a QX3 is present */
+	        u8 toplight;            /* top light lit , R/W */
+	        u8 bottomlight;         /* bottom light lit, R/W */
+	        u8 button;              /* snapshot button pressed (R/O) */
+	        u8 cradled;             /* microscope is in cradle (R/O) */
+	} qx3;
+
+	struct {
+		u8 colStart;		/* skip first 8*colStart pixels */
+		u8 colEnd;		/* finish at 8*colEnd pixels */
+		u8 rowStart;		/* skip first 4*rowStart lines */
+		u8 rowEnd;		/* finish at 4*rowEnd lines */
+	} roi;
+	u8 ecpTiming;
+	u8 streamStartLine;
+};
+
+enum v4l_camstates {
+	CPIA_V4L_IDLE = 0,
+	CPIA_V4L_ERROR,
+	CPIA_V4L_COMMAND,
+	CPIA_V4L_GRABBING,
+	CPIA_V4L_STREAMING,
+	CPIA_V4L_STREAMING_PAUSED,
+};
+
+#define FRAME_NUM	2	/* double buffering for now */
+
+struct cam_data {
+	struct cam_data **previous;
+	struct cam_data *next;
+
+        struct semaphore busy_lock;     /* guard against SMP multithreading */
+	struct cpia_camera_ops *ops;	/* lowlevel driver operations */
+	void *lowlevel_data;		/* private data for lowlevel driver */
+	u8 *raw_image;			/* buffer for raw image data */
+	struct cpia_frame decompressed_frame;
+                                        /* buffer to hold decompressed frame */
+	int image_size;		        /* sizeof last decompressed image */
+	int open_count;			/* # of process that have camera open */
+
+				/* camera status */
+	int fps;			/* actual fps reported by the camera */
+	int transfer_rate;		/* transfer rate from camera in kB/s */
+	u8 mainsFreq;			/* for flicker control */
+
+				/* proc interface */
+	struct semaphore param_lock;	/* params lock for this camera */
+	struct cam_params params;	/* camera settings */
+	struct proc_dir_entry *proc_entry;	/* /proc/cpia/videoX */
+	
+					/* v4l */
+	int video_size;			/* VIDEO_SIZE_ */
+	volatile enum v4l_camstates camstate;	/* v4l layer status */
+	struct video_device vdev;	/* v4l videodev */
+	struct video_picture vp;	/* v4l camera settings */
+	struct video_window vw;		/* v4l capture area */
+
+				/* mmap interface */
+	int curframe;			/* the current frame to grab into */
+	u8 *frame_buf;			/* frame buffer data */
+        struct cpia_frame frame[FRAME_NUM];
+				/* FRAME_NUM-buffering, so we need a array */
+
+	int first_frame;
+	int mmap_kludge;		/* 'wrong' byte order for mmap */
+	volatile u32 cmd_queue;		/* queued commands */
+};
+
+/* cpia_register_camera is called by low level driver for each camera.
+ * A unique camera number is returned, or a negative value on error */
+struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel);
+
+/* cpia_unregister_camera is called by low level driver when a camera
+ * is removed.  This must not fail. */
+void cpia_unregister_camera(struct cam_data *cam);
+
+/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI +
+ * one byte 16bit DMA alignment
+ */
+#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5)
+
+/* constant value's */
+#define MAGIC_0		0x19
+#define MAGIC_1		0x68
+#define DATA_IN		0xC0
+#define DATA_OUT	0x40
+#define VIDEOSIZE_QCIF	0	/* 176x144 */
+#define VIDEOSIZE_CIF	1	/* 352x288 */
+#define VIDEOSIZE_SIF	2	/* 320x240 */
+#define VIDEOSIZE_QSIF	3	/* 160x120 */
+#define VIDEOSIZE_48_48		4 /* where no one has gone before, iconsize! */
+#define VIDEOSIZE_64_48		5
+#define VIDEOSIZE_128_96	6
+#define VIDEOSIZE_160_120	VIDEOSIZE_QSIF
+#define VIDEOSIZE_176_144	VIDEOSIZE_QCIF
+#define VIDEOSIZE_192_144	7
+#define VIDEOSIZE_224_168	8
+#define VIDEOSIZE_256_192	9
+#define VIDEOSIZE_288_216	10
+#define VIDEOSIZE_320_240	VIDEOSIZE_SIF
+#define VIDEOSIZE_352_288	VIDEOSIZE_CIF
+#define VIDEOSIZE_88_72		11 /* quarter CIF */
+#define SUBSAMPLE_420	0
+#define SUBSAMPLE_422	1
+#define YUVORDER_YUYV	0
+#define YUVORDER_UYVY	1
+#define NOT_COMPRESSED	0
+#define COMPRESSED	1
+#define NO_DECIMATION	0
+#define DECIMATION_ENAB	1
+#define EOI		0xff	/* End Of Image */
+#define EOL		0xfd	/* End Of Line */
+#define FRAME_HEADER_SIZE	64
+
+/* Image grab modes */
+#define CPIA_GRAB_SINGLE	0
+#define CPIA_GRAB_CONTINUOUS	1
+
+/* Compression parameters */
+#define CPIA_COMPRESSION_NONE	0
+#define CPIA_COMPRESSION_AUTO	1
+#define CPIA_COMPRESSION_MANUAL	2
+#define CPIA_COMPRESSION_TARGET_QUALITY         0
+#define CPIA_COMPRESSION_TARGET_FRAMERATE       1
+
+/* Return offsets for GetCameraState */
+#define SYSTEMSTATE	0
+#define GRABSTATE	1
+#define STREAMSTATE	2
+#define FATALERROR	3
+#define CMDERROR	4
+#define DEBUGFLAGS	5
+#define VPSTATUS	6
+#define ERRORCODE	7
+
+/* SystemState */
+#define UNINITIALISED_STATE	0
+#define PASS_THROUGH_STATE	1
+#define LO_POWER_STATE		2
+#define HI_POWER_STATE		3
+#define WARM_BOOT_STATE		4
+
+/* GrabState */
+#define GRAB_IDLE		0
+#define GRAB_ACTIVE		1
+#define GRAB_DONE		2
+
+/* StreamState */
+#define STREAM_NOT_READY	0
+#define STREAM_READY		1
+#define STREAM_OPEN		2
+#define STREAM_PAUSED		3
+#define STREAM_FINISHED		4
+
+/* Fatal Error, CmdError, and DebugFlags */
+#define CPIA_FLAG	  1
+#define SYSTEM_FLAG	  2
+#define INT_CTRL_FLAG	  4
+#define PROCESS_FLAG	  8
+#define COM_FLAG	 16
+#define VP_CTRL_FLAG	 32
+#define CAPTURE_FLAG	 64
+#define DEBUG_FLAG	128
+
+/* VPStatus */
+#define VP_STATE_OK			0x00
+
+#define VP_STATE_FAILED_VIDEOINIT	0x01
+#define VP_STATE_FAILED_AECACBINIT	0x02
+#define VP_STATE_AEC_MAX		0x04
+#define VP_STATE_ACB_BMAX		0x08
+
+#define VP_STATE_ACB_RMIN		0x10
+#define VP_STATE_ACB_GMIN		0x20
+#define VP_STATE_ACB_RMAX		0x40
+#define VP_STATE_ACB_GMAX		0x80
+
+/* ErrorCode */
+#define ERROR_FLICKER_BELOW_MIN_EXP     0x01 /*flicker exposure got below minimum exposure */
+
+#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args)
+#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO __FILE__":"__FUNCTION__"(%d):"fmt,##args)
+
+#ifdef _CPIA_DEBUG_
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):"__FUNCTION__"(%d):"fmt,##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
+
+#define DEB_BYTE(p)\
+  DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
+      (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
+        (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
+
+#define ADD_TO_LIST(l, drv) \
+  {\
+    lock_kernel();\
+    (drv)->next = l;\
+    (drv)->previous = &(l);\
+    (l) = drv;\
+    unlock_kernel();\
+  } while(0)
+
+#define REMOVE_FROM_LIST(drv) \
+  {\
+    if ((drv)->previous != NULL) {\
+      lock_kernel();\
+      if ((drv)->next != NULL)\
+        (drv)->next->previous = (drv)->previous;\
+      *((drv)->previous) = (drv)->next;\
+      (drv)->previous = NULL;\
+      (drv)->next = NULL;\
+      unlock_kernel();\
+    }\
+  } while (0)
+
+
+#endif /* __KERNEL__ */
+
+#endif /* cpia_h */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/cpia_pp.c linux.18p8/drivers/char/cpia_pp.c
--- linux.vanilla/drivers/char/cpia_pp.c	Fri Apr 21 12:45:51 2000
+++ linux.18p8/drivers/char/cpia_pp.c	Fri Sep  1 13:51:28 2000
@@ -3,10 +3,9 @@
  *
  * Supports CPiA based parallel port Video Camera's.
  *
- * (C) 1999 Bas Huisman <bhuism@cs.utwente.nl>
- *          Scott J. Bertin <sbertin@mindspring.com>,
- *          Peter Pregler <Peter_Pregler@email.com>
- *          Johannes Erdfelt
+ * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
+ * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@mindspring.com>,
+ * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,6 +23,11 @@
  */
 
 #include <linux/config.h>
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+#undef CONFIG_VIDEO_CPIA_PP_DMA
+#endif
 
 #include <linux/module.h>
 #include <linux/init.h>
@@ -32,6 +36,8 @@
 #include <linux/parport.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
+
 #ifdef CONFIG_VIDEO_CPIA_PP_DMA
 #include <asm/dma.h>
 #endif
@@ -41,6 +47,7 @@
 #endif
 
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 /* If this is a module and parport_pc is not, some parport_pc_* functions
  * are not directly availbale.  parport.h messes this up.
  * This fixes what we need.
@@ -67,11 +74,12 @@
 #define parport_disable_irq(p) parport_pc_disable_irq(p)
 #endif				/* parport_enable_irq */
 #endif				/* !PARPORT_NEED_GENERIC_OPS */
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) */
 
-#undef _CPIA_DEBUG_		/* define for verbose debug output */
-#include <linux/cpia.h>
+/* #define _CPIA_DEBUG_		define for verbose debug output */
+#include "cpia.h"
 
-static int cpia_pp_open(int camnr, void **privdata);
+static int cpia_pp_open(void *privdata);
 static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata),
                                     void *cbdata);
 static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);
@@ -126,6 +134,8 @@
 #define ECP_FIFO_SIZE	16
 #define DMA_BUFFER_SIZE               PAGE_SIZE
 	/* for 16bit DMA make sure DMA_BUFFER_SIZE is 16 bit aligned */
+#define PARPORT_CHUNK_SIZE	PAGE_SIZE/* >=2.3.x */
+				/* we read this many bytes at once */
 
 #define GetECRMasked(port,mask)	(parport_read_econtrol(port) & (mask))
 #define GetStatus(port)		((parport_read_status(port)^STATUS_INVERSION_MASK)&(0xf8))
@@ -139,7 +149,6 @@
 #define ClearControlMasked(port,mask)	SetControl(port,GetControl(port)&~(mask));
 #define FrobControlBit(port,mask,value)	SetControl(port,(GetControl(port)&~(mask))|((value)&(mask)));
 
-#define PP_MAXCAMS	(PARPORT_MAX<CPIA_MAXCAMS?PARPORT_MAX:CPIA_MAXCAMS)
 #define PACKET_LENGTH 	8
 
 /* Magic numbers for defining port-device mappings */
@@ -149,18 +158,20 @@
 #define PPCPIA_PARPORT_NONE -1
 
 #ifdef MODULE
-static int parport_nr[PP_MAXCAMS] = {[0 ... PP_MAXCAMS - 1] = PPCPIA_PARPORT_UNSPEC};
-static char *parport[PP_MAXCAMS] = {NULL,};
+static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
+static char *parport[PARPORT_MAX] = {NULL,};
 
+MODULE_AUTHOR("B. Huisman <bhuism@cs.utwente.nl> & Peter Pregler <Peter_Pregler@email.com>");
 MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras");
-MODULE_PARM(parport, "1-" __MODULE_STRING(PP_MAXCAMS) "s");
+MODULE_PARM(parport, "1-" __MODULE_STRING(PARPORT_MAX) "s");
 MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
 #else
-static int parport_nr[PP_MAXCAMS] __initdata =
-	{[0 ... PP_MAXCAMS - 1] = PPCPIA_PARPORT_UNSPEC};
+static int parport_nr[PARPORT_MAX] __initdata =
+	{[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
 static int parport_ptr = 0;
 #endif
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 enum comstates { CPIA_FORWARD, CPIA_REVERSE };	//fixme
 enum camstates {
 	CPIA_PHASE_idle = 0,
@@ -187,16 +198,22 @@
 	"CPIA_PHASE_secpwrite",
 };
 #endif
+#endif
+
 struct pp_cam_entry {
 	struct pardevice *pdev;
 	struct parport *port;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	enum comstates state;
 	enum camstates camstate;
+#endif
 	struct tq_struct cb_task;
 	int open_count;
-	int camnr;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	struct wait_queue *wq_stream;
-	
+#else
+	wait_queue_head_t wq_stream;
+#endif	
 	/* image state flags */
 	int image_ready;	/* we got an interrupt */
 	int image_complete;	/* we have seen 4 EOI */
@@ -220,8 +237,6 @@
 #endif
 };
 
-static struct pp_cam_entry *camera[PP_MAXCAMS] = {[0 ... PP_MAXCAMS - 1] = NULL};
-
 static struct cpia_camera_ops cpia_pp_ops = 
 {
 	cpia_pp_open,
@@ -230,9 +245,12 @@
 	cpia_pp_streamStart,
 	cpia_pp_streamStop,
 	cpia_pp_streamRead,
-	cpia_pp_close
+	cpia_pp_close,
+	1
 };
 
+static struct cam_data *cam_list;
+
 #ifdef _CPIA_DEBUG_
 #define DEB_PORT(port) { \
 u8 controll = GetControl(port); \
@@ -258,17 +276,18 @@
 
 /* FIXME */
 static void cpia_parport_enable_irq( struct parport *port ) {
-  parport_enable_irq(port);
-  mdelay(10);
-  return;
+	parport_enable_irq(port);
+	mdelay(10);
+	return;
 }
 
 static void cpia_parport_disable_irq( struct parport *port ) {
-  parport_disable_irq(port);
-  mdelay(10);
-  return;
+	parport_disable_irq(port);
+	mdelay(10);
+	return;
 }
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 static int while_out(struct pp_cam_entry *cam)
 {
 	struct parport *port = cam->port;
@@ -709,7 +728,7 @@
 	release_dma_lock(flags);
 	return cam->readbytes;
 }
-#endif
+#endif /* CONFIG_VIDEO_CPIA_PP_DMA */
 
 /****************************************************************************
  *
@@ -779,6 +798,7 @@
 
 	return written;
 }
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) */
 
 /****************************************************************************
  *
@@ -787,10 +807,13 @@
  ***************************************************************************/
 static void EndTransferMode(struct pp_cam_entry *cam)
 {
-	if (!cam) return;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	if (cam->state == CPIA_REVERSE)  Reverse2Forward(cam);
 	Valid1284Termination(cam);
 	if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
+#else
+	parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+#endif
 }
 
 /****************************************************************************
@@ -800,6 +823,7 @@
  ***************************************************************************/
 static int ForwardSetup(struct pp_cam_entry *cam)
 {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	if(cam->stream_irq) cpia_parport_disable_irq(cam->port);
 	if (!Negotiate2SetupPhase(cam, 0)) {
 		if (!ECPSetupPhase(cam)) {
@@ -812,6 +836,22 @@
 	}
 	EndTransferMode(cam);
 	return -1;
+#else
+	int retry;
+	
+	/* After some commands the camera needs extra time before
+	 * it will respond again, so we try up to 3 times */
+	for(retry=0; retry<3; ++retry) {
+		if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) {
+			break;
+		}
+	}
+	if(retry == 3) {
+		DBG("Unable to negotiate ECP mode\n");
+		return -1;
+	}
+	return 0;
+#endif
 }
 
 /****************************************************************************
@@ -821,6 +861,7 @@
  ***************************************************************************/
 static int ReverseSetup(struct pp_cam_entry *cam, int extensibility)
 {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	if(cam->stream_irq) cpia_parport_disable_irq(cam->port);
 	if (!Negotiate2SetupPhase(cam, extensibility)) {
 		if (!ECPSetupPhase(cam)) {
@@ -837,6 +878,28 @@
 	}
 	EndTransferMode(cam);
 	return -1;
+#else
+	int retry;
+	int mode = IEEE1284_MODE_ECP;
+	if(extensibility) mode = 8|3|IEEE1284_EXT_LINK;
+
+	/* After some commands the camera needs extra time before
+	 * it will respond again, so we try up to 3 times */
+	for(retry=0; retry<3; ++retry) {
+		if(!parport_negotiate(cam->port, mode)) {
+			break;
+		}
+	}
+	if(retry == 3) {
+		if(extensibility)
+			DBG("Unable to negotiate extensibility mode\n");
+		else
+			DBG("Unable to negotiate ECP mode\n");
+		return -1;
+	}
+	if(extensibility) cam->port->ieee1284.mode = IEEE1284_MODE_ECP;
+	return 0;
+#endif
 }
 
 #ifdef CONFIG_VIDEO_CPIA_PP_DMA
@@ -967,7 +1030,7 @@
         }
 	return;
 }
-#endif
+#endif /* CONFIG_VIDEO_CPIA_PP_DMA */
 
 /****************************************************************************
  *
@@ -975,6 +1038,7 @@
  *
  ***************************************************************************/
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 static void cpia_pp_irq_handler(int irq, void *handle, struct pt_regs *b)
 {
 	struct pp_cam_entry *cam = handle;
@@ -992,7 +1056,7 @@
 		}
 		return;
 	}
-#endif
+#endif /* CONFIG_VIDEO_CPIA_PP_DMA */
 	if (cam->camstate == CPIA_PHASE_ecpread) return;
 	if( cam->camstate != CPIA_PHASE_idle )
 		DBG("got IRQ(%d) when in %s\n",
@@ -1012,6 +1076,7 @@
         }
 	return;
 }
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) */
 
 /****************************************************************************
  *
@@ -1021,15 +1086,27 @@
 static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size)
 {
 	int retval=0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+	int size_written;
+#endif
 	if (packet == NULL) {
 		return -EINVAL;
 	}
 	if (ForwardSetup(cam)) {
+		DBG("Write failed in setup\n");
 		return -EIO;
 	}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	if (SimECPWriteBuffer(cam, packet, size) != size) {
 		retval = -EIO;
 	}
+#else
+	size_written = parport_write(cam->port, packet, size);
+	if(size_written != size) {
+		DBG("Write failed, wrote %d/%d\n", size_written, size);
+		retval = -EIO;
+	}
+#endif
 	EndTransferMode(cam);
 	return retval;
 }
@@ -1048,9 +1125,15 @@
 	if (ReverseSetup(cam, 0)) {
 		return -EIO;
 	}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	if (SimECPReadBuffer(cam, packet, size) != size) {
 		retval = -EIO;
 	}
+#else
+	if(parport_read(cam->port, packet, size) != size) {
+		retval = -EIO;
+	}
+#endif
 	EndTransferMode(cam);
 	return retval;
 }
@@ -1068,7 +1151,6 @@
 	cam->image_ready=0;
 	//if (ReverseSetup(cam,1)) return -EIO;
 	if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
-
 	return 0;
 }
 
@@ -1089,6 +1171,20 @@
 	return 0;
 }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
+{
+	int bytes_read, new_bytes;
+	for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
+		new_bytes = parport_read(port, buffer+bytes_read,
+			                 len-bytes_read);
+		if(new_bytes < 0) break;
+	}
+	return bytes_read;
+}
+
+#endif
+
 /****************************************************************************
  *
  *  cpia_pp_streamRead
@@ -1098,6 +1194,10 @@
 {
 	struct pp_cam_entry *cam = privdata;
 	int read_bytes = 0;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+	int i, endseen, block_size, new_bytes;
+#endif
+
 	if(cam == NULL) {
 		DBG("Internal driver error: cam is NULL\n");
 		return -EINVAL;
@@ -1120,8 +1220,12 @@
 			DBG("%d\n", cam->image_ready);
 		}
 	} else {
-		if (ReverseSetup(cam, 1)) return -EIO;
+		if (ReverseSetup(cam, 1)) {
+			DBG("unable to ReverseSetup\n");
+			return -EIO;
+		}
 	}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	read_bytes = ECPReadBuffer(cam, buffer, CPIA_MAX_IMAGE_SIZE);
 	if( 1/*!cam->streaming*/) {
 		EndTransferMode(cam);
@@ -1131,6 +1235,36 @@
 			DBG("incomplete image: %ld / %d / %d\n",
 			    jiffies, cam->image_complete, read_bytes);
 	}
+#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) */
+	endseen = 0;
+	block_size = PARPORT_CHUNK_SIZE;
+	while( !cam->image_complete ) {
+		if(current->need_resched)  schedule();
+		
+		new_bytes = cpia_pp_read(cam->port, buffer, block_size );
+		if( new_bytes <= 0 ) {
+			break;
+		}
+		i=-1;
+		while(++i<new_bytes && endseen<4) {
+	        	if(*buffer==EOI) {
+	                	endseen++;
+	                } else {
+	                	endseen=0;
+	                }
+			buffer++;
+		}
+		read_bytes += i;
+		if( endseen==4 ) {
+			cam->image_complete=1;
+			break;
+		}
+		if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
+			block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
+		}
+	}
+	EndTransferMode(cam);
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)) */
 	return cam->image_complete ? read_bytes : -EIO;
 }
 
@@ -1145,6 +1279,7 @@
 	int retval=0;
 	int databytes;
 	struct pp_cam_entry *cam = privdata;
+
 	if(cam == NULL) {
 		DBG("Internal driver error: cam is NULL\n");
 		return -EINVAL;
@@ -1155,6 +1290,7 @@
 	}
 	databytes = (((int)command[7])<<8) | command[6];
 	if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) {
+		DBG("Error writing command\n");
 		return err;
 	}
 	if(command[0] == DATA_IN) {
@@ -1163,9 +1299,9 @@
 			DBG("Internal driver error: data is NULL\n");
 			return -EINVAL;
 		}
-		err = ReadPacket(cam, buffer, 8);
-		if(err < 0) {
+		if((err = ReadPacket(cam, buffer, 8)) < 0) {
 			return err;
+			DBG("Error reading command result\n");
 		}
 		memcpy(data, buffer, databytes);
 	} else if(command[0] == DATA_OUT) {
@@ -1174,7 +1310,10 @@
 				DBG("Internal driver error: data is NULL\n");
 				retval = -EINVAL;
 			} else {
-				WritePacket(cam, data, databytes);
+				if((err=WritePacket(cam, data, databytes)) < 0){
+					DBG("Error writing command data\n");
+					return err;
+				}
 			}
 		}
 	} else {
@@ -1189,29 +1328,19 @@
  *  cpia_pp_open
  *
  ***************************************************************************/
-static int cpia_pp_open(int camnr, void **privdata)
+static int cpia_pp_open(void *privdata)
 {
-	struct pp_cam_entry *cam=NULL;
-	int i;
-	for(i=0; i<PP_MAXCAMS; ++i) {
-		cam=camera[i];
-		if(cam == NULL) {
-			DBG("Trying to open non-existent camera[%d]\n", camnr);
-			return -ENXIO;
-		}
-		if(cam->camnr == camnr) {
-			DBG("Found camera[%d]\n", camnr);
-			break;
-		}
-	}
+	struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
 	
-	*privdata = cam;
+	if (cam == NULL)
+		return -EINVAL;
 	
 	if(cam->open_count == 0) {
 		if (parport_claim(cam->pdev)) {
 			DBG("failed to claim the port\n");
 			return -EBUSY;
 		}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		parport_write_econtrol(cam->port, PARPORT_MODE_PCECR);
 		parport_frob_econtrol(cam->port,
 		                      ECR_serviceIntr|ECR_dmaEn|ECR_nErrIntrEn,
@@ -1222,6 +1351,15 @@
 #endif
 		cam->stream_irq=0;
 		cpia_parport_disable_irq(cam->port);
+#else
+		parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
+		parport_data_forward(cam->port);
+		parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
+		udelay(50);
+		parport_write_control(cam->port,
+		                      PARPORT_CONTROL_SELECT
+		                      | PARPORT_CONTROL_INIT);
+#endif
 	}
 	
 	++cam->open_count;
@@ -1266,6 +1404,7 @@
 	MOD_DEC_USE_COUNT;
 #endif
 	if (--cam->open_count == 0) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		if (cam->port->irq != PARPORT_IRQ_NONE) {
 			cpia_parport_disable_irq(cam->port);
 		}
@@ -1278,11 +1417,12 @@
 			interruptible_sleep_on(&cam->wq_dma);
 		}
 		restore_flags(flags);
-#endif
+#endif /* CONFIG_VIDEO_CPIA_PP_DMA */
 		if (waitqueue_active(&cam->wq_stream)) { /* FIXME */
 			wake_up(&cam->wq_stream);
 		}
 		
+#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) */
 		parport_release(cam->pdev);
 	}
 	return 0;
@@ -1293,47 +1433,55 @@
  *  cpia_pp_register
  *
  ***************************************************************************/
-static int cpia_pp_register(int nr, struct parport *port)
+static int cpia_pp_register(struct parport *port)
 {
 	struct pardevice *pdev = NULL;
-	int camnr;
+	struct pp_cam_entry *cam;
+	struct cam_data *cpia;
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	if (!(port->modes & PARPORT_MODE_PCECP)) {
+#else
+	if (!(port->modes & PARPORT_MODE_ECP) &&
+	    !(port->modes & PARPORT_MODE_TRISTATE)) {
+#endif
 		LOG("port is not ECP capable\n");
 		return -ENXIO;
 	}
 
-	if((camnr = cpia_register_camera(&cpia_pp_ops)) < 0) {
-		LOG("failed to cpia_register_camera\n");
-		return -ENXIO;
-	}
-	camera[nr] = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
-	if (camera[nr] == NULL) {
+	cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
+	if (cam == NULL) {
 		LOG("failed to allocate camera structure\n");
-		cpia_unregister_camera(camnr);
 		return -ENOMEM;
 	}
-	memset(camera[nr],0,sizeof(struct pp_cam_entry));
+	memset(cam,0,sizeof(struct pp_cam_entry));
 	
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+	pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
+	                               cpia_pp_irq_handler, 0, cam);
+#else
 	pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
-	                               cpia_pp_irq_handler, 0, camera[nr]);
+	                               NULL, 0, cam);
+#endif
 
 	if (!pdev) {
 		LOG("failed to parport_register_device\n");
-		cpia_unregister_camera(camnr);
-		kfree(camera[nr]);
+		kfree(cam);
 		return -ENXIO;
 	}
 
-	camera[nr]->pdev = pdev;
-	camera[nr]->port = port;
-	camera[nr]->state = CPIA_FORWARD;
-	camera[nr]->camstate = CPIA_PHASE_idle;
-	camera[nr]->camnr = camnr;
-	init_waitqueue(&camera[nr]->wq_stream);
+	cam->pdev = pdev;
+	cam->port = port;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+	cam->state = CPIA_FORWARD;
+	cam->camstate = CPIA_PHASE_idle;
+	init_waitqueue(&cam->wq_stream);
+#else
+	init_waitqueue_head(&cam->wq_stream);
+#endif
 
-	camera[nr]->streaming = 0;
-	camera[nr]->stream_irq = 0;
+	cam->streaming = 0;
+	cam->stream_irq = 0;
 
 #ifdef CONFIG_VIDEO_CPIA_PP_DMA
 	if (pdev->port->irq != PARPORT_IRQ_NONE &&
@@ -1341,66 +1489,151 @@
 		if(request_dma(pdev->port->dma, "cpia_pp")) {
 			LOG("failed to register dma %d\n", pdev->port->dma);
 			parport_unregister_device(pdev);
-			cpia_unregister_camera(camnr);
-			kfree(camera[nr]);
+			kfree(cam);
 			return -ENXIO;
 		}
-		camera[nr]->dma_buf=kmalloc(DMA_BUFFER_SIZE, GFP_DMA);
-		if(camera[nr]->dma_buf == NULL) {
-			free_dma(camera[nr]->pdev->port->dma);
-			LOG("failed to allocate dma buffer, using FIFO mode\n");
+		cam->dma_buf=kmalloc(DMA_BUFFER_SIZE, GFP_DMA);
+		if(cam->dma_buf == NULL) {
+			free_dma(cam->pdev->port->dma);
+			LOG("failed to allocate dma buffer, using PIO mode\n");
 		} else {
-			init_waitqueue(&camera[nr]->wq_dma);
+			init_waitqueue(&cam->wq_dma);
 			printk(KERN_INFO "  using DMA mode (irq %d, DMA %d)\n", pdev->port->irq, pdev->port->dma);
 		}
-		memset(camera[nr]->dma_buf, 0, DMA_BUFFER_SIZE);
+		memset(cam->dma_buf, 0, DMA_BUFFER_SIZE);
 	} else {
 		printk(KERN_INFO "  using PIO mode\n");
 	}
 #endif
 
+	if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) {
+		LOG("failed to cpia_register_camera\n");
+#ifdef CONFIG_VIDEO_CPIA_PP_DMA
+		if (cam->dma_buf) {
+			free_dma(cam->pdev->port->dma);
+			kfree(cam->dma_buf);
+		}
+#endif
+		parport_unregister_device(pdev);
+		kfree(cam);
+		return -ENXIO;
+	}
+	ADD_TO_LIST(cam_list, cpia);
+
 	return 0;
 }
 
+static void cpia_pp_detach (struct parport *port)
+{
+	struct cam_data *cpia;
+
+	for(cpia = cam_list; cpia != NULL; cpia = cpia->next) {
+		struct pp_cam_entry *cam = cpia->lowlevel_data;
+		if (cam && cam->port->number == port->number) {
+			REMOVE_FROM_LIST(cpia);
+			
+#ifdef CONFIG_VIDEO_CPIA_PP_DMA
+	                if (cam->dma_buf) {
+	                        free_dma(cam->pdev->port->dma);
+        	                kfree(cam->dma_buf);
+                	}
+#endif
+
+			cpia_unregister_camera(cpia);
+			
+			if(cam->open_count > 0) {
+				cpia_pp_close(cam);
+			}
+
+			parport_unregister_device(cam->pdev);
+		
+			kfree(cam);
+			cpia->lowlevel_data = NULL;
+			break;
+		}
+	}
+}
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+static void cpia_pp_attach (struct parport *port)
+{
+	unsigned int i;
+
+	switch (parport_nr[0])
+	{
+	case PPCPIA_PARPORT_UNSPEC:
+	case PPCPIA_PARPORT_AUTO:
+		if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||
+		    port->probe_info[0].cmdset == NULL ||
+		    strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0)
+			return;
+
+		cpia_pp_register(port);
+
+		break;
+
+	default:
+		for (i = 0; i < PARPORT_MAX; ++i) {
+			if (port->number == parport_nr[i]) {
+				cpia_pp_register(port);
+				break;
+			}
+		}
+		break;
+	}
+}
+
+static struct parport_driver cpia_pp_driver = {
+	"cpia_pp",
+	cpia_pp_attach,
+	cpia_pp_detach,
+	NULL
+};
+#endif
+
 int cpia_pp_init(void)
 {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	struct parport *port;
 	int i, count = 0;
+#endif
 
 	printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, 
 	       CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
 
-	switch (parport_nr[0]) {
-	case PPCPIA_PARPORT_OFF:
+	if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
 		printk("  disabled\n");
 		return 0;
-
+	}
+	
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+	switch (parport_nr[0]) {
 	case PPCPIA_PARPORT_UNSPEC:
 	case PPCPIA_PARPORT_AUTO:
 		for (port = parport_enumerate(); port; port = port->next) {
 
 #if defined(CONFIG_PNP_PARPORT) || \
     (defined(MODULE) && defined(CONFIG_PNP_PARPORT_MODULE))
-			if (port->probe_info.class != PARPORT_CLASS_MEDIA ||
-			    port->probe_info.cmdset == NULL ||
-			    strncmp(port->probe_info.cmdset, "CPIA_1", 6) != 0){
-				continue;
+			if(port->probe_info.model) {
+				if (port->probe_info.class != PARPORT_CLASS_MEDIA ||
+				    port->probe_info.cmdset == NULL ||
+				    strncmp(port->probe_info.cmdset, "CPIA_1", 6) != 0){
+					continue;
+				}
 			}
 #endif
-
-			if (cpia_pp_register(count, port) == 0 &&
-			    ++count == PP_MAXCAMS) {
-				break;
+			if (!cpia_pp_register(port)) {
+				++count;
 			}
 		}
 		break;
 
 	default:
-		for (i = 0; i < PP_MAXCAMS; i++) {
+		for (i = 0; i < PARPORT_MAX; i++) {
 			for (port = parport_enumerate(); port;
 			     port = port->next) {
 				if (port->number == parport_nr[i]) {
-					if (!cpia_pp_register(i, port)) {
+					if (!cpia_pp_register(port)) {
 						count++;
 					}
 					break;
@@ -1414,6 +1647,13 @@
 	if (count == 0) {
 		return -ENODEV;
 	}
+#else /* kernel version >= 2.3.0 */
+	if (parport_register_driver (&cpia_pp_driver)) {
+		LOG ("unable to register with parport\n");
+		return -EIO;
+	}
+#endif /* kernel version >= 2.3.0 */
+
 	return 0;
 }
 
@@ -1426,7 +1666,7 @@
 			parport_nr[0] = PPCPIA_PARPORT_AUTO;
 		} else {
 			int n;
-			for (n = 0; n < PP_MAXCAMS && parport[n]; n++) {
+			for (n = 0; n < PARPORT_MAX && parport[n]; n++) {
 				if (!strncmp(parport[n], "none", 4)) {
 					parport_nr[n] = PPCPIA_PARPORT_NONE;
 				} else {
@@ -1443,31 +1683,23 @@
 		}
 	}
 #if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE)
-	request_module("parport_probe");
+	if(parport_enumerate() && !parport_enumerate()->probe_info.model) {
+		request_module("parport_probe");
+	}
 #endif
 	return cpia_pp_init();
 }
 
 void cleanup_module(void)
 {
-	int i;
-	for (i = 0; camera[i] != NULL && i < PP_MAXCAMS; i++) {
-		while(camera[i]->open_count > 0) {
-			LOG("You forgot to close camera %d, will do it for you\n", camera[i]->camnr);
-			cpia_pp_close(camera[i]);
-		}
-		
-#ifdef CONFIG_VIDEO_CPIA_PP_DMA
-		if (camera[i]->dma_buf) {
-			free_dma(camera[i]->pdev->port->dma);
-			kfree(camera[i]->dma_buf);
-		}
-#endif
-
-		cpia_unregister_camera(camera[i]->camnr);
-		parport_unregister_device(camera[i]->pdev);
-		kfree(camera[i]);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+	parport_unregister_driver (&cpia_pp_driver);
+#else
+	while(cam_list != NULL) {
+		struct pp_cam_entry *cam = cam_list->lowlevel_data;
+		cpia_pp_detach(cam->port);
 	}
+#endif
 	return;
 }
 
@@ -1482,7 +1714,7 @@
 		}
 	} else if (!strncmp(str, "parport", 7)) {
 		int n = simple_strtoul(str + 7, NULL, 10);
-		if (parport_ptr < PP_MAXCAMS) {
+		if (parport_ptr < PARPORT_MAX) {
 			parport_nr[parport_ptr++] = n;
 		} else {
 			LOG("too many ports, %s ignored.\n", str);
@@ -1493,5 +1725,8 @@
 		parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
 	}
 }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+__setup("cpia_pp=", cpia_pp_setup);
+#endif
 
 #endif /* !MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/cpia_usb.c linux.18p8/drivers/char/cpia_usb.c
--- linux.vanilla/drivers/char/cpia_usb.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/cpia_usb.c	Fri Sep  1 13:51:28 2000
@@ -0,0 +1,636 @@
+/*
+ * cpia_usb CPiA USB driver
+ *
+ * Supports CPiA based parallel port Video Camera's.
+ *
+ * Copyright (C) 1999        Jochen Scharrlach <Jochen.Scharrlach@schwaben.de>
+ * Copyright (C) 1999, 2000  Johannes Erdfelt <jerdfelt@valinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+
+#include "cpia.h"
+
+#define USB_REQ_CPIA_GRAB_FRAME			0xC1
+#define USB_REQ_CPIA_UPLOAD_FRAME		0xC2
+#define  WAIT_FOR_NEXT_FRAME			0
+#define  FORCE_FRAME_UPLOAD			1
+
+#define FRAMES_PER_DESC		10
+#define FRAME_SIZE_PER_DESC	960	/* Shouldn't be hardcoded */
+#define CPIA_NUMSBUF		2
+#define STREAM_BUF_SIZE		(PAGE_SIZE * 4)
+#define SCRATCH_BUF_SIZE	(STREAM_BUF_SIZE * 2)
+
+struct cpia_sbuf {
+	char *data;
+	urb_t *urb;
+};
+
+#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
+enum framebuf_status {
+	FRAME_EMPTY,
+	FRAME_READING,
+	FRAME_READY,
+	FRAME_ERROR,
+};
+
+struct framebuf {
+	int length;
+	enum framebuf_status status;
+	u8 data[FRAMEBUF_LEN];
+	struct framebuf *next;
+};
+
+struct usb_cpia {
+	/* Device structure */
+	struct usb_device *dev;
+
+	unsigned char iface;
+	wait_queue_head_t wq_stream;
+
+	int cursbuf;		/* Current receiving sbuf */
+	struct cpia_sbuf sbuf[CPIA_NUMSBUF];		/* Double buffering */
+
+	int streaming;
+	int open;
+	int present;
+	struct framebuf *buffers[3];
+	struct framebuf *curbuff, *workbuff;
+};
+
+static int cpia_usb_open(void *privdata);
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+			             void *cbdata);
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
+static int cpia_usb_streamStart(void *privdata);
+static int cpia_usb_streamStop(void *privdata);
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock);
+static int cpia_usb_close(void *privdata);
+
+#define ABOUT "USB driver for Vision CPiA based cameras"
+
+static struct cpia_camera_ops cpia_usb_ops = {
+	cpia_usb_open,
+	cpia_usb_registerCallback,
+	cpia_usb_transferCmd,
+	cpia_usb_streamStart,
+	cpia_usb_streamStop,
+	cpia_usb_streamRead,
+	cpia_usb_close,
+	0
+};
+
+static struct cam_data *cam_list;
+
+static void cpia_usb_complete(struct urb *urb)
+{
+	int i;
+	char *cdata;
+	struct usb_cpia *ucpia;
+
+	if (!urb || !urb->context)
+		return;
+
+	ucpia = (struct usb_cpia *) urb->context;
+
+	if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open)
+		return;
+
+	if (ucpia->workbuff->status == FRAME_EMPTY) {
+		ucpia->workbuff->status = FRAME_READING;
+		ucpia->workbuff->length = 0;
+	}
+ 		  
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int n = urb->iso_frame_desc[i].actual_length;
+		int st = urb->iso_frame_desc[i].status;
+
+		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		if (st)
+			printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st);
+
+		if (FRAMEBUF_LEN < ucpia->workbuff->length + n) {
+			printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n);
+			return;
+		}
+	    
+		if (n) {
+			if ((ucpia->workbuff->length > 0) || 
+			    (0x19 == cdata[0] && 0x68 == cdata[1])) {
+				memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n);
+				ucpia->workbuff->length += n;
+			} else
+				DBG("Ignoring packet!\n");
+		} else {
+			if (ucpia->workbuff->length > 4 &&
+			    0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] &&
+			    0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] &&
+			    0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] &&
+			    0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) {
+				ucpia->workbuff->status = FRAME_READY;
+				ucpia->curbuff = ucpia->workbuff;
+				ucpia->workbuff = ucpia->workbuff->next;
+				ucpia->workbuff->status = FRAME_EMPTY;
+				ucpia->workbuff->length = 0;
+		  
+				if (waitqueue_active(&ucpia->wq_stream))
+					wake_up_interruptible(&ucpia->wq_stream);
+			}
+		}
+	}
+}
+
+static int cpia_usb_open(void *privdata)
+{
+	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+	urb_t *urb;
+	int ret, retval = 0, fx, err;
+  
+	if (!ucpia)
+		return -EINVAL;
+
+	ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+	if (!ucpia->sbuf[0].data)
+		return -EINVAL;
+
+	ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
+	if (!ucpia->sbuf[1].data) {
+		retval = -EINVAL;
+		goto error_0;
+	}
+	
+	ret = usb_set_interface(ucpia->dev, ucpia->iface, 3);
+	if (ret < 0) {
+		printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret);
+		retval = -EBUSY;
+		goto error_all;
+	}
+
+	ucpia->buffers[0]->status = FRAME_EMPTY;
+	ucpia->buffers[0]->length = 0;
+	ucpia->buffers[1]->status = FRAME_EMPTY;
+	ucpia->buffers[1]->length = 0;
+	ucpia->buffers[2]->status = FRAME_EMPTY;
+	ucpia->buffers[2]->length = 0;
+	ucpia->curbuff = ucpia->buffers[0];
+	ucpia->workbuff = ucpia->buffers[1];
+
+	/* We double buffer the Iso lists */
+	urb = usb_alloc_urb(FRAMES_PER_DESC);
+	if (!urb) {
+		printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
+		retval = -ENOMEM;
+		goto error_all;
+	}
+
+	ucpia->sbuf[0].urb = urb;
+	urb->dev = ucpia->dev;
+	urb->context = ucpia;
+	urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+	urb->transfer_flags = USB_ISO_ASAP;
+	urb->transfer_buffer = ucpia->sbuf[0].data;
+	urb->complete = cpia_usb_complete;
+	urb->number_of_packets = FRAMES_PER_DESC;
+	urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+		urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+		urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+	}
+
+	urb = usb_alloc_urb(FRAMES_PER_DESC);
+	if (!urb) {
+		printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
+		retval = -ENOMEM;
+		goto error_all;
+	}
+
+	ucpia->sbuf[1].urb = urb;
+	urb->dev = ucpia->dev;
+	urb->context = ucpia;
+	urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
+	urb->transfer_flags = USB_ISO_ASAP;
+	urb->transfer_buffer = ucpia->sbuf[1].data;
+	urb->complete = cpia_usb_complete;
+	urb->number_of_packets = FRAMES_PER_DESC;
+	urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
+	for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+		urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
+		urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
+	}
+
+	ucpia->sbuf[1].urb->next = ucpia->sbuf[0].urb;
+	ucpia->sbuf[0].urb->next = ucpia->sbuf[1].urb;
+	
+	err = usb_submit_urb(ucpia->sbuf[0].urb);
+	if (err)
+		printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n",
+			err);
+	err = usb_submit_urb(ucpia->sbuf[1].urb);
+	if (err)
+		printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n",
+			err);
+
+	ucpia->streaming = 1;
+	ucpia->open = 1;
+
+	return 0;
+
+error_all:
+	kfree (ucpia->sbuf[1].data);
+error_0:
+	kfree (ucpia->sbuf[0].data);
+	
+	return retval;
+}
+
+//
+// convenience functions
+//
+
+/****************************************************************************
+ *
+ *  WritePacket
+ *
+ ***************************************************************************/
+static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size)
+{
+	if (!packet)
+		return -EINVAL;
+
+	return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			 packet[1] + (packet[0] << 8),
+			 USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			 packet[2] + (packet[3] << 8), 
+			 packet[4] + (packet[5] << 8), buf, size, HZ);
+}
+
+/****************************************************************************
+ *
+ *  ReadPacket
+ *
+ ***************************************************************************/
+static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
+{
+	if (!packet || size <= 0)
+		return -EINVAL;
+
+	return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			 packet[1] + (packet[0] << 8),
+			 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			 packet[2] + (packet[3] << 8), 
+			 packet[4] + (packet[5] << 8), buf, size, HZ);
+}
+
+static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
+{
+	int err = 0;
+	int databytes;
+	struct usb_cpia *ucpia = (struct usb_cpia *)privdata;
+	struct usb_device *udev = ucpia->dev;
+
+	if (!udev) {
+		DBG("Internal driver error: udev is NULL\n");
+		return -EINVAL;
+	}
+
+	if (!command) {
+		DBG("Internal driver error: command is NULL\n");
+		return -EINVAL;
+	}
+
+	databytes = (((int)command[7])<<8) | command[6];
+
+	if (command[0] == DATA_IN) {
+		u8 buffer[8];
+
+		if (!data) {
+			DBG("Internal driver error: data is NULL\n");
+			return -EINVAL;
+		}
+
+		err = ReadPacket(udev, command, buffer, 8);
+		if (err < 0)
+			return err;
+
+		memcpy(data, buffer, databytes);
+	} else if(command[0] == DATA_OUT)
+		WritePacket(udev, command, data, databytes);
+	else {
+		DBG("Unexpected first byte of command: %x\n", command[0]);
+		err = -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
+	void *cbdata)
+{
+	return -ENODEV;
+}
+
+static int cpia_usb_streamStart(void *privdata)
+{
+	return -ENODEV;
+}
+
+static int cpia_usb_streamStop(void *privdata)
+{
+	return -ENODEV;
+}
+
+static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
+{
+	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+	struct framebuf *mybuff;
+
+	if (!ucpia || !ucpia->present)
+		return -1;
+  
+	if (ucpia->curbuff->status != FRAME_READY)
+		interruptible_sleep_on(&ucpia->wq_stream);
+	else
+		DBG("Frame already waiting!\n");
+
+	mybuff = ucpia->curbuff;
+
+	if (!mybuff)
+		return -1;
+  
+	if (mybuff->status != FRAME_READY || mybuff->length < 4) {
+		DBG("Something went wrong!\n");
+		return -1;
+	}
+
+	memcpy(frame, mybuff->data, mybuff->length);
+	mybuff->status = FRAME_EMPTY;
+  
+/*   DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n",  */
+/*       mybuff->length, frame[0], frame[1], */
+/*       frame[mybuff->length-4], frame[mybuff->length-3],  */
+/*       frame[mybuff->length-2], frame[mybuff->length-1]); */
+
+	return mybuff->length;
+}
+
+static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
+{
+	if (!ucpia->streaming)
+		return;
+
+	ucpia->streaming = 0;
+
+	/* Set packet size to 0 */
+	if (try) {
+		int ret;
+
+		ret = usb_set_interface(ucpia->dev, ucpia->iface, 0);
+		if (ret < 0) {
+			printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret);
+			return;
+		}
+	}
+
+	/* Unschedule all of the iso td's */
+	if (ucpia->sbuf[1].urb) {
+		usb_unlink_urb(ucpia->sbuf[1].urb);
+		usb_free_urb(ucpia->sbuf[1].urb);
+		ucpia->sbuf[1].urb = NULL;
+	}
+
+	if (ucpia->sbuf[0].urb) {
+		usb_unlink_urb(ucpia->sbuf[0].urb);
+		usb_free_urb(ucpia->sbuf[0].urb);
+		ucpia->sbuf[0].urb = NULL;
+	}
+}
+
+static int cpia_usb_close(void *privdata)
+{
+	struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
+
+	ucpia->open = 0;
+
+	cpia_usb_free_resources(ucpia, 1);
+
+	if (!ucpia->present)
+		kfree(ucpia);
+
+	return 0;
+}
+
+int cpia_usb_init(void)
+{
+	/* return -ENODEV; */
+	return 0;
+}
+
+/* Probing and initializing */
+
+static void *cpia_probe(struct usb_device *udev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_cpia *ucpia;
+	struct cam_data *cam;
+	int ret;
+  
+	/* A multi-config CPiA camera? */
+	if (udev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	interface = &udev->actconfig->interface[ifnum].altsetting[0];
+
+	/* Is it a CPiA? */
+	if (!((udev->descriptor.idVendor == 0x0553 && 
+	     udev->descriptor.idProduct == 0x0002) ||
+	    (udev->descriptor.idVendor == 0x0813 &&
+	     udev->descriptor.idProduct == 0x0001))) /* GA 04/14/00 */
+	  return NULL;
+
+	/* We found a CPiA */
+	printk(KERN_INFO "USB CPiA camera found\n");
+
+	ucpia = kmalloc(sizeof(*ucpia), GFP_KERNEL);
+	if (!ucpia) {
+		printk(KERN_ERR "couldn't kmalloc cpia struct\n");
+		return NULL;
+	}
+
+	memset(ucpia, 0, sizeof(*ucpia));
+
+	ucpia->dev = udev;
+	ucpia->iface = interface->bInterfaceNumber;
+	init_waitqueue_head(&ucpia->wq_stream);
+
+	ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0]));
+	if (!ucpia->buffers[0]) {
+		printk(KERN_ERR "couldn't vmalloc frame buffer 0\n");
+		goto fail_alloc_0;
+	}
+
+	ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1]));
+	if (!ucpia->buffers[1]) {
+		printk(KERN_ERR "couldn't vmalloc frame buffer 1\n");
+		goto fail_alloc_1;
+	}
+
+	ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2]));
+	if (!ucpia->buffers[2]) {
+		printk(KERN_ERR "couldn't vmalloc frame buffer 2\n");
+		goto fail_alloc_2;
+	}
+
+	ucpia->buffers[0]->next = ucpia->buffers[1];
+	ucpia->buffers[1]->next = ucpia->buffers[2];
+	ucpia->buffers[2]->next = ucpia->buffers[0];
+
+	ret = usb_set_interface(udev, ucpia->iface, 0);
+	if (ret < 0) {
+		printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret);
+		/* goto fail_all; */
+	}
+
+	/* Before register_camera, important */
+	ucpia->present = 1;
+  
+	cam = cpia_register_camera(&cpia_usb_ops, ucpia);
+	if (!cam) {
+		LOG("failed to cpia_register_camera\n");
+		goto fail_all;
+	}
+
+	ADD_TO_LIST(cam_list, cam);
+
+	return cam;
+
+fail_all:
+	vfree(ucpia->buffers[2]);
+	ucpia->buffers[2] = NULL;
+fail_alloc_2:
+	vfree(ucpia->buffers[1]);
+	ucpia->buffers[1] = NULL;
+fail_alloc_1:
+	vfree(ucpia->buffers[0]);
+	ucpia->buffers[0] = NULL;
+fail_alloc_0:
+
+	return NULL;
+}
+
+static void cpia_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver cpia_driver = {
+	"cpia",
+	cpia_probe,
+	cpia_disconnect,
+	{ NULL, NULL }
+};
+
+/* don't use dev, it may be NULL! (see usb_cpia_cleanup) */
+/* _disconnect from usb_cpia_cleanup is not necessary since usb_deregister */
+/* will do it for us as well as passing a udev structure - jerdfelt */
+static void cpia_disconnect(struct usb_device *udev, void *ptr)
+{
+	struct cam_data *cam = (struct cam_data *) ptr;
+	struct usb_cpia *ucpia = (struct usb_cpia *) cam->lowlevel_data;
+  
+	REMOVE_FROM_LIST(cam);
+
+	/* Don't even try to reset the altsetting if we're disconnected */
+	cpia_usb_free_resources(ucpia, 0);
+
+	ucpia->present = 0;
+
+	cpia_unregister_camera(cam);
+
+	ucpia->curbuff->status = FRAME_ERROR;
+
+	if (waitqueue_active(&ucpia->wq_stream))
+		wake_up_interruptible(&ucpia->wq_stream);
+
+	usb_driver_release_interface(&cpia_driver,
+				     &udev->actconfig->interface[0]);
+
+	ucpia->curbuff = ucpia->workbuff = NULL;
+
+	if (ucpia->buffers[2]) {
+		vfree(ucpia->buffers[2]);
+		ucpia->buffers[2] = NULL;
+	}
+
+	if (ucpia->buffers[1]) {
+		vfree(ucpia->buffers[1]);
+		ucpia->buffers[1] = NULL;
+	}
+
+	if (ucpia->buffers[0]) {
+		vfree(ucpia->buffers[0]);
+		ucpia->buffers[0] = NULL;
+	}
+
+	if (!ucpia->open)
+		kfree(ucpia);
+}
+
+int usb_cpia_init(void)
+{
+	cam_list = NULL;
+
+	return usb_register(&cpia_driver);
+}
+
+void usb_cpia_cleanup(void)
+{
+/*
+	struct cam_data *cam;
+
+	while ((cam = cam_list) != NULL)
+		cpia_disconnect(NULL, cam);
+*/
+
+	usb_deregister(&cpia_driver);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return usb_cpia_init();
+}
+
+void cleanup_module(void)
+{
+	usb_cpia_cleanup();
+}
+
+#else /* !MODULE */
+
+__initfunc(void cpia_usb_setup(char *str, int *ints))
+{
+}
+
+#endif /* !MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/Config.in linux.18p8/drivers/char/drm/Config.in
--- linux.vanilla/drivers/char/drm/Config.in	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/Config.in	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,15 @@
+#
+# drm device configuration
+#
+# This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.x.
+#
+
+tristate 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
+if [ "$CONFIG_DRM" != "n" ]; then
+    tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX
+    tristate '  3dlabs GMX 2000' CONFIG_DRM_GAMMA
+    tristate '  ATI Rage 128' CONFIG_DRM_R128
+    dep_tristate '  Intel I810' CONFIG_DRM_I810 $CONFIG_AGP
+    dep_tristate '  Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP
+fi
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/Makefile linux.18p8/drivers/char/drm/Makefile
--- linux.vanilla/drivers/char/drm/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/Makefile	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,88 @@
+#
+# Makefile for the drm device driver.  This driver provides support for
+# the Direct Rendering Infrastructure (DRI) in XFree86 4.x.
+#
+
+# drm.o is a fake target -- it is never built
+# The real targets are in the module-list
+O_TARGET	:= drm.o
+module-list     := gamma.o tdfx.o r128.o ffb.o mga.o i810.o
+export-objs     := $(patsubst %.o,%_drv.o,$(module-list))
+
+# libs-objs are included in every module so that radical changes to the
+# architecture of the DRM support library can be made at a later time.
+#
+# The downside is that each module is larger, and a system that uses
+# more than one module (i.e., a dual-head system) will use more memory
+# (but a system that uses exactly one module will use the same amount of
+# memory).
+#
+# The upside is that if the DRM support library ever becomes insufficient
+# for new families of cards, a new library can be implemented for those new
+# cards without impacting the drivers for the old cards.  This is significant,
+# because testing architectural changes to old cards may be impossible, and
+# may delay the implementation of a better architecture.  We've traded slight
+# memory waste (in the dual-head case) for greatly improved long-term
+# maintainability.
+#
+lib-objs   := init.o memory.o proc.o auth.o context.o drawable.o bufs.o
+lib-objs   += lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o
+
+ifeq ($(CONFIG_AGP),y)
+ lib-objs  += agpsupport.o
+else
+ ifeq ($(CONFIG_AGP),m)
+  lib-objs  += agpsupport.o
+ endif
+endif
+
+gamma-objs := $(lib-objs) gamma_drv.o gamma_dma.o
+tdfx-objs  := $(lib-objs) tdfx_drv.o                tdfx_context.o
+r128-objs  := $(lib-objs) r128_drv.o  r128_dma.o    r128_context.o r128_bufs.o
+ffb-objs   := $(lib-objs) ffb_drv.o                 ffb_context.o
+mga-objs   := $(lib-objs) mga_drv.o   mga_dma.o     mga_context.o  mga_bufs.o \
+	      mga_state.o
+i810-objs  := $(lib-objs) i810_drv.o  i810_dma.o    i810_context.o i810_bufs.o
+
+obj-$(CONFIG_DRM_GAMMA) += gamma.o $(gamma-objs)
+obj-$(CONFIG_DRM_TDFX)  += tdfx.o  $(tdfx-objs)
+obj-$(CONFIG_DRM_R128)  += r128.o  $(r128-objs)
+obj-$(CONFIG_DRM_FFB)   += ffb.o   $(ffb-objs)
+
+ifneq ($CONFIG_AGP),)
+obj-$(CONFIG_DRM_MGA)   += mga.o   $(mga-objs)
+obj-$(CONFIG_DRM_I810)  += i810.o  $(i810-objs)
+endif
+
+# Take module names out of obj-y and int-m
+
+obj-y           := $(filter-out $(module-list), $(obj-y))
+int-m           := $(filter-out $(module-list), $(obj-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS          := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS         := $(filter     $(export-objs), $(obj-y))
+M_OBJS          := $(sort $(filter     $(module-list), $(obj-m)))
+MI_OBJS         := $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS        := $(sort $(filter     $(export-objs), $(int-m)))
+
+include $(TOPDIR)/Rules.make
+
+gamma.o: $(gamma-objs)
+	$(LD) -r -o $@ $(gamma-objs)
+
+tdfx.o: $(tdfx-objs)
+	$(LD) -r -o $@ $(tdfx-objs)
+
+mga.o: $(mga-objs)
+	$(LD) -r -o $@ $(mga-objs)
+
+i810.o: $(i810-objs)
+	$(LD) -r -o $@ $(i810-objs)
+
+r128.o: $(r128-objs)
+	$(LD) -r -o $@ $(r128-objs)
+
+ffb.o: $(ffb-objs)
+	$(LD) -r -o $@ $(ffb-objs)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/README.drm linux.18p8/drivers/char/drm/README.drm
--- linux.vanilla/drivers/char/drm/README.drm	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/README.drm	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,41 @@
+
+The Direct Rendering Manager (drm) is a device-independent kernel-level
+device driver that provides support for the XFree86 Direct Rendering
+Infrastructure (DRI).
+
+The DRM supports the Direct Rendering Infrastructure (DRI) in four major
+ways:
+
+    1. The DRM provides synchronized access to the graphics hardware via
+       the use of an optimized two-tiered lock.
+
+    2. The DRM enforces the DRI security policy for access to the graphics
+       hardware by only allowing authenticated X11 clients access to
+       restricted regions of memory.
+
+    3. The DRM provides a generic DMA engine, complete with multiple
+       queues and the ability to detect the need for an OpenGL context
+       switch.
+
+    4. The DRM is extensible via the use of small device-specific modules
+       that rely extensively on the API exported by the DRM module.
+
+
+Documentation on the DRI is available from:
+    http://precisioninsight.com/piinsights.html
+
+For specific information about kernel-level support, see:
+
+    The Direct Rendering Manager, Kernel Support for the Direct Rendering
+    Infrastructure
+    http://precisioninsight.com/dr/drm.html
+
+    Hardware Locking for the Direct Rendering Infrastructure
+    http://precisioninsight.com/dr/locking.html
+
+    A Security Analysis of the Direct Rendering Infrastructure
+    http://precisioninsight.com/dr/security.html
+
+
+
+$XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/README.drm,v 1.2 1999/09/27 14:59:24 dawes Exp $
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/agpsupport.c linux.18p8/drivers/char/drm/agpsupport.c
--- linux.vanilla/drivers/char/drm/agpsupport.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/agpsupport.c	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,329 @@
+/* agpsupport.c -- DRM support for AGP/GART backend -*- linux-c -*-
+ * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <linux/module.h>
+
+drm_agp_func_t drm_agp = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+
+/* The C standard says that 'void *' is not guaranteed to hold a function
+   pointer, so we use this union to define a generic pointer that is
+   guaranteed to hold any of the function pointers we care about. */
+typedef union {
+	void          (*free_memory)(agp_memory *);
+	agp_memory    *(*allocate_memory)(size_t, u32);
+	int           (*bind_memory)(agp_memory *, off_t);
+	int           (*unbind_memory)(agp_memory *);
+	void          (*enable)(u32);
+	int           (*acquire)(void);
+	void          (*release)(void);
+	void          (*copy_info)(agp_kern_info *);
+	unsigned long address;
+} drm_agp_func_u;
+
+typedef struct drm_agp_fill {
+        const char     *name;
+	drm_agp_func_u *f;
+} drm_agp_fill_t;
+
+static drm_agp_fill_t drm_agp_fill[] = {
+	{ __MODULE_STRING(agp_free_memory),
+	   (drm_agp_func_u *)&drm_agp.free_memory     },
+	{ __MODULE_STRING(agp_allocate_memory), 
+	   (drm_agp_func_u *)&drm_agp.allocate_memory },
+	{ __MODULE_STRING(agp_bind_memory),     
+	   (drm_agp_func_u *)&drm_agp.bind_memory     },
+	{ __MODULE_STRING(agp_unbind_memory),   
+	   (drm_agp_func_u *)&drm_agp.unbind_memory   },
+	{ __MODULE_STRING(agp_enable),          
+	   (drm_agp_func_u *)&drm_agp.enable          },
+	{ __MODULE_STRING(agp_backend_acquire), 
+	   (drm_agp_func_u *)&drm_agp.acquire         },
+	{ __MODULE_STRING(agp_backend_release), 
+	   (drm_agp_func_u *)&drm_agp.release         },
+	{ __MODULE_STRING(agp_copy_info),       
+	   (drm_agp_func_u *)&drm_agp.copy_info       },
+	{ NULL, NULL }
+};
+
+int drm_agp_info(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	agp_kern_info    *kern;
+	drm_agp_info_t   info;
+
+	if (!dev->agp->acquired || !drm_agp.copy_info) return -EINVAL;
+
+	kern                   = &dev->agp->agp_info;
+	info.agp_version_major = kern->version.major;
+	info.agp_version_minor = kern->version.minor;
+	info.mode              = kern->mode;
+	info.aperture_base     = kern->aper_base;
+	info.aperture_size     = kern->aper_size * 1024 * 1024;
+	info.memory_allowed    = kern->max_memory << PAGE_SHIFT;
+	info.memory_used       = kern->current_memory << PAGE_SHIFT;
+	info.id_vendor         = kern->device->vendor;
+	info.id_device         = kern->device->device;
+
+	copy_to_user_ret((drm_agp_info_t *)arg, &info, sizeof(info), -EFAULT);
+	return 0;
+}
+
+int drm_agp_acquire(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int              retcode;
+
+	if (dev->agp->acquired || !drm_agp.acquire) return -EINVAL;
+	if ((retcode = (*drm_agp.acquire)())) return retcode;
+	dev->agp->acquired = 1;
+	return 0;
+}
+
+int drm_agp_release(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+
+	if (!dev->agp->acquired || !drm_agp.release) return -EINVAL;
+	(*drm_agp.release)();
+	dev->agp->acquired = 0;
+	return 0;
+	
+}
+
+int drm_agp_enable(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_agp_mode_t   mode;
+
+	if (!dev->agp->acquired || !drm_agp.enable) return -EINVAL;
+
+	copy_from_user_ret(&mode, (drm_agp_mode_t *)arg, sizeof(mode),
+			   -EFAULT);
+	
+	dev->agp->mode    = mode.mode;
+	(*drm_agp.enable)(mode.mode);
+	dev->agp->base    = dev->agp->agp_info.aper_base;
+	dev->agp->enabled = 1;
+	return 0;
+}
+
+int drm_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_agp_buffer_t request;
+	drm_agp_mem_t    *entry;
+	agp_memory       *memory;
+	unsigned long    pages;
+	u32 		 type;
+	if (!dev->agp->acquired) return -EINVAL;
+	copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request),
+			   -EFAULT);
+	if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS)))
+		return -ENOMEM;
+   
+   	memset(entry, 0, sizeof(*entry));
+
+	pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
+	type = (u32) request.type;
+
+	if (!(memory = drm_alloc_agp(pages, type))) {
+		drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+		return -ENOMEM;
+	}
+	
+	entry->handle    = (unsigned long)memory->memory;
+	entry->memory    = memory;
+	entry->bound     = 0;
+	entry->pages     = pages;
+	entry->prev      = NULL;
+	entry->next      = dev->agp->memory;
+	if (dev->agp->memory) dev->agp->memory->prev = entry;
+	dev->agp->memory = entry;
+
+	request.handle   = entry->handle;
+        request.physical = memory->physical;
+
+	if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) {
+		dev->agp->memory       = entry->next;
+		dev->agp->memory->prev = NULL;
+		drm_free_agp(memory, pages);
+		drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t *dev,
+					   unsigned long handle)
+{
+	drm_agp_mem_t *entry;
+
+	for (entry = dev->agp->memory; entry; entry = entry->next) {
+		if (entry->handle == handle) return entry;
+	}
+	return NULL;
+}
+
+int drm_agp_unbind(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	  *priv	 = filp->private_data;
+	drm_device_t	  *dev	 = priv->dev;
+	drm_agp_binding_t request;
+	drm_agp_mem_t     *entry;
+
+	if (!dev->agp->acquired) return -EINVAL;
+	copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request),
+			   -EFAULT);
+	if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
+		return -EINVAL;
+	if (!entry->bound) return -EINVAL;
+	return drm_unbind_agp(entry->memory);
+}
+
+int drm_agp_bind(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	 = filp->private_data;
+	drm_device_t	  *dev	 = priv->dev;
+	drm_agp_binding_t request;
+	drm_agp_mem_t     *entry;
+	int               retcode;
+	int               page;
+	
+	if (!dev->agp->acquired || !drm_agp.bind_memory) return -EINVAL;
+	copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request),
+			   -EFAULT);
+	if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
+		return -EINVAL;
+	if (entry->bound) return -EINVAL;
+	page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE;
+	if ((retcode = drm_bind_agp(entry->memory, page))) return retcode;
+	entry->bound = dev->agp->base + (page << PAGE_SHIFT);
+	DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", 
+		  dev->agp->base, entry->bound);
+	return 0;
+}
+
+int drm_agp_free(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_agp_buffer_t request;
+	drm_agp_mem_t    *entry;
+	
+	if (!dev->agp->acquired) return -EINVAL;
+	copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request),
+			   -EFAULT);
+	if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
+		return -EINVAL;
+	if (entry->bound) drm_unbind_agp(entry->memory);
+   
+	if (entry->prev) entry->prev->next = entry->next;
+	else             dev->agp->memory  = entry->next;
+	if (entry->next) entry->next->prev = entry->prev;
+	drm_free_agp(entry->memory, entry->pages);
+	drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+	return 0;
+}
+
+drm_agp_head_t *drm_agp_init(void)
+{
+	drm_agp_fill_t *fill;
+	drm_agp_head_t *head         = NULL;
+	int            agp_available = 1;
+
+	for (fill = &drm_agp_fill[0]; fill->name; fill++) {
+		char *n  = (char *)fill->name;
+		*fill->f = (drm_agp_func_u)get_module_symbol(NULL, n);
+		DRM_DEBUG("%s resolves to 0x%08lx\n", n, (*fill->f).address);
+		if (!(*fill->f).address) agp_available = 0;
+	}
+   
+	DRM_DEBUG("agp_available = %d\n", agp_available);
+
+	if (agp_available) {
+		if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS)))
+			return NULL;
+		memset((void *)head, 0, sizeof(*head));
+		(*drm_agp.copy_info)(&head->agp_info);
+		head->memory = NULL;
+		switch (head->agp_info.chipset) {
+		case INTEL_GENERIC:    head->chipset = "Intel";            break;
+		case INTEL_LX:         head->chipset = "Intel 440LX";      break;
+		case INTEL_BX:         head->chipset = "Intel 440BX";      break;
+		case INTEL_GX:         head->chipset = "Intel 440GX";      break;
+		case INTEL_I810:       head->chipset = "Intel i810";       break;
+		case VIA_GENERIC:      head->chipset = "VIA";              break;
+		case VIA_VP3:          head->chipset = "VIA VP3";          break;
+		case VIA_MVP3:         head->chipset = "VIA MVP3";         break;
+		case VIA_APOLLO_PRO:   head->chipset = "VIA Apollo Pro";   break;
+		case VIA_APOLLO_SUPER: head->chipset = "VIA Apollo Super"; break;
+		case SIS_GENERIC:      head->chipset = "SiS";              break;
+		case AMD_GENERIC:      head->chipset = "AMD";              break;
+		case AMD_IRONGATE:     head->chipset = "AMD Irongate";     break;
+		case ALI_GENERIC:      head->chipset = "ALi";              break;
+		case ALI_M1541:        head->chipset = "ALi M1541";        break;
+		default:
+		}
+		DRM_INFO("AGP %d.%d on %s @ 0x%08lx %dMB\n",
+			 head->agp_info.version.major,
+			 head->agp_info.version.minor,
+			 head->chipset,
+			 head->agp_info.aper_base,
+			 head->agp_info.aper_size);
+	}
+	return head;
+}
+
+void drm_agp_uninit(void)
+{
+	drm_agp_fill_t *fill;
+	
+	for (fill = &drm_agp_fill[0]; fill->name; fill++) {
+#if LINUX_VERSION_CODE >= 0x020400
+		if ((*fill->f).address) put_module_symbol((*fill->f).address);
+#endif
+		(*fill->f).address = 0;
+	}
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/auth.c linux.18p8/drivers/char/drm/auth.c
--- linux.vanilla/drivers/char/drm/auth.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/auth.c	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,160 @@
+/* auth.c -- IOCTLs for authentication -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_hash_magic(drm_magic_t magic)
+{
+	return magic & (DRM_HASH_SIZE-1);
+}
+
+static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic)
+{
+	drm_file_t	  *retval = NULL;
+	drm_magic_entry_t *pt;
+	int		  hash	  = drm_hash_magic(magic);
+
+	down(&dev->struct_sem);
+	for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
+		if (pt->magic == magic) {
+			retval = pt->priv;
+			break;
+		}
+	}
+	up(&dev->struct_sem);
+	return retval;
+}
+
+int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
+{
+	int		  hash;
+	drm_magic_entry_t *entry;
+	
+	DRM_DEBUG("%d\n", magic);
+	
+	hash	     = drm_hash_magic(magic);
+	entry	     = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
+	if (!entry) return -ENOMEM;
+	entry->magic = magic;
+	entry->priv  = priv;
+	entry->next  = NULL;
+
+	down(&dev->struct_sem);
+	if (dev->magiclist[hash].tail) {
+		dev->magiclist[hash].tail->next = entry;
+		dev->magiclist[hash].tail	= entry;
+	} else {
+		dev->magiclist[hash].head	= entry;
+		dev->magiclist[hash].tail	= entry;
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
+{
+	drm_magic_entry_t *prev = NULL;
+	drm_magic_entry_t *pt;
+	int		  hash;
+	
+	DRM_DEBUG("%d\n", magic);
+	hash = drm_hash_magic(magic);
+	
+	down(&dev->struct_sem);
+	for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
+		if (pt->magic == magic) {
+			if (dev->magiclist[hash].head == pt) {
+				dev->magiclist[hash].head = pt->next;
+			}
+			if (dev->magiclist[hash].tail == pt) {
+				dev->magiclist[hash].tail = prev;
+			}
+			if (prev) {
+				prev->next = pt->next;
+			}
+			up(&dev->struct_sem);
+			return 0;
+		}
+	}
+	up(&dev->struct_sem);
+
+	drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+	
+	return -EINVAL;
+}
+
+int drm_getmagic(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	static drm_magic_t sequence = 0;
+	static spinlock_t  lock	    = SPIN_LOCK_UNLOCKED;
+	drm_file_t	   *priv    = filp->private_data;
+	drm_device_t	   *dev	    = priv->dev;
+	drm_auth_t	   auth;
+
+				/* Find unique magic */
+	if (priv->magic) {
+		auth.magic = priv->magic;
+	} else {
+		spin_lock(&lock);
+		do {
+			if (!sequence) ++sequence; /* reserve 0 */
+			auth.magic = sequence++;
+		} while (drm_find_file(dev, auth.magic));
+		spin_unlock(&lock);
+		priv->magic = auth.magic;
+		drm_add_magic(dev, priv, auth.magic);
+	}
+	
+	DRM_DEBUG("%u\n", auth.magic);
+	copy_to_user_ret((drm_auth_t *)arg, &auth, sizeof(auth), -EFAULT);
+	return 0;
+}
+
+int drm_authmagic(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	   *priv    = filp->private_data;
+	drm_device_t	   *dev	    = priv->dev;
+	drm_auth_t	   auth;
+	drm_file_t	   *file;
+
+	copy_from_user_ret(&auth, (drm_auth_t *)arg, sizeof(auth), -EFAULT);
+	DRM_DEBUG("%u\n", auth.magic);
+	if ((file = drm_find_file(dev, auth.magic))) {
+		file->authenticated = 1;
+		drm_remove_magic(dev, auth.magic);
+		return 0;
+	}
+	return -EINVAL;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/bufs.c linux.18p8/drivers/char/drm/bufs.c
--- linux.vanilla/drivers/char/drm/bufs.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/bufs.c	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,538 @@
+/* bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "drmP.h"
+#include "linux/un.h"
+
+				/* Compute order.  Can be made faster. */
+int drm_order(unsigned long size)
+{
+	int	      order;
+	unsigned long tmp;
+
+	for (order = 0, tmp = size; tmp >>= 1; ++order);
+	if (size & ~(1 << order)) ++order;
+	return order;
+}
+
+int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_map_t	*map;
+	
+	if (!(filp->f_mode & 3)) return -EACCES; /* Require read/write */
+
+	map	     = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
+	if (!map) return -ENOMEM;
+	if (copy_from_user(map, (drm_map_t *)arg, sizeof(*map))) {
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		return -EFAULT;
+	}
+
+	DRM_DEBUG("offset = 0x%08lx, size = 0x%08lx, type = %d\n",
+		  map->offset, map->size, map->type);
+	if ((map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK))) {
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		return -EINVAL;
+	}
+	map->mtrr   = -1;
+	map->handle = 0;
+
+	switch (map->type) {
+	case _DRM_REGISTERS:
+	case _DRM_FRAME_BUFFER:
+#ifndef __sparc__
+		if (map->offset + map->size < map->offset
+		    || map->offset < virt_to_phys(high_memory)) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -EINVAL;
+		}
+#endif
+#ifdef CONFIG_MTRR
+		if (map->type == _DRM_FRAME_BUFFER
+		    || (map->flags & _DRM_WRITE_COMBINING)) {
+			map->mtrr = mtrr_add(map->offset, map->size,
+					     MTRR_TYPE_WRCOMB, 1);
+		}
+#endif
+		map->handle = drm_ioremap(map->offset, map->size);
+		break;
+			
+
+	case _DRM_SHM:
+		map->handle = (void *)drm_alloc_pages(drm_order(map->size)
+						      - PAGE_SHIFT,
+						      DRM_MEM_SAREA);
+		DRM_DEBUG("%ld %d %p\n", map->size, drm_order(map->size),
+			  map->handle);
+		if (!map->handle) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -ENOMEM;
+		}
+		map->offset = (unsigned long)map->handle;
+		if (map->flags & _DRM_CONTAINS_LOCK) {
+			dev->lock.hw_lock = map->handle; /* Pointer to lock */
+		}
+		break;
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	case _DRM_AGP:
+		map->offset = map->offset + dev->agp->base;
+		break;
+#endif
+	default:
+		drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		return -EINVAL;
+	}
+
+	down(&dev->struct_sem);
+	if (dev->maplist) {
+		++dev->map_count;
+		dev->maplist = drm_realloc(dev->maplist,
+					   (dev->map_count-1)
+					   * sizeof(*dev->maplist),
+					   dev->map_count
+					   * sizeof(*dev->maplist),
+					   DRM_MEM_MAPS);
+	} else {
+		dev->map_count = 1;
+		dev->maplist = drm_alloc(dev->map_count*sizeof(*dev->maplist),
+					 DRM_MEM_MAPS);
+	}
+	dev->maplist[dev->map_count-1] = map;
+	up(&dev->struct_sem);
+
+	copy_to_user_ret((drm_map_t *)arg, map, sizeof(*map), -EFAULT);
+	if (map->type != _DRM_SHM) {
+		copy_to_user_ret(&((drm_map_t *)arg)->handle,
+				 &map->offset,
+				 sizeof(map->offset),
+				 -EFAULT);
+	}		
+	return 0;
+}
+
+int drm_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 count;
+	int		 order;
+	int		 size;
+	int		 total;
+	int		 page_order;
+	drm_buf_entry_t	 *entry;
+	unsigned long	 page;
+	drm_buf_t	 *buf;
+	int		 alignment;
+	unsigned long	 offset;
+	int		 i;
+	int		 byte_count;
+	int		 page_count;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	count	   = request.count;
+	order	   = drm_order(request.size);
+	size	   = 1 << order;
+	
+	DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n",
+		  request.count, request.size, size, order, dev->queue_count);
+
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+
+	alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total	   = PAGE_SIZE << page_order;
+
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+	
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;	/* May only call once for each order */
+	}
+	
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+
+	entry->seglist = drm_alloc(count * sizeof(*entry->seglist),
+				   DRM_MEM_SEGS);
+	if (!entry->seglist) {
+		drm_free(entry->buflist,
+			 count * sizeof(*entry->buflist),
+			 DRM_MEM_BUFS);
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->seglist, 0, count * sizeof(*entry->seglist));
+
+	dma->pagelist = drm_realloc(dma->pagelist,
+				    dma->page_count * sizeof(*dma->pagelist),
+				    (dma->page_count + (count << page_order))
+				    * sizeof(*dma->pagelist),
+				    DRM_MEM_PAGES);
+	DRM_DEBUG("pagelist: %d entries\n",
+		  dma->page_count + (count << page_order));
+
+
+	entry->buf_size	  = size;
+	entry->page_order = page_order;
+	byte_count	  = 0;
+	page_count	  = 0;
+	while (entry->buf_count < count) {
+		if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break;
+		entry->seglist[entry->seg_count++] = page;
+		for (i = 0; i < (1 << page_order); i++) {
+			DRM_DEBUG("page %d @ 0x%08lx\n",
+				  dma->page_count + page_count,
+				  page + PAGE_SIZE * i);
+			dma->pagelist[dma->page_count + page_count++]
+				= page + PAGE_SIZE * i;
+		}
+		for (offset = 0;
+		     offset + size <= total && entry->buf_count < count;
+		     offset += alignment, ++entry->buf_count) {
+			buf	     = &entry->buflist[entry->buf_count];
+			buf->idx     = dma->buf_count + entry->buf_count;
+			buf->total   = alignment;
+			buf->order   = order;
+			buf->used    = 0;
+			buf->offset  = (dma->byte_count + byte_count + offset);
+			buf->address = (void *)(page + offset);
+			buf->next    = NULL;
+			buf->waiting = 0;
+			buf->pending = 0;
+			init_waitqueue_head(&buf->dma_wait);
+			buf->pid     = 0;
+#if DRM_DMA_HISTOGRAM
+			buf->time_queued     = 0;
+			buf->time_dispatched = 0;
+			buf->time_completed  = 0;
+			buf->time_freed	     = 0;
+#endif
+			DRM_DEBUG("buffer %d @ %p\n",
+				  entry->buf_count, buf->address);
+		}
+		byte_count += PAGE_SIZE << page_order;
+	}
+
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+
+	dma->buf_count	+= entry->buf_count;
+	dma->seg_count	+= entry->seg_count;
+	dma->page_count += entry->seg_count << page_order;
+	dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
+	
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+	
+	up(&dev->struct_sem);
+
+	request.count = entry->buf_count;
+	request.size  = size;
+
+	copy_to_user_ret((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+	
+	atomic_dec(&dev->buf_alloc);
+	return 0;
+}
+
+int drm_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_info_t	 request;
+	int		 i;
+	int		 count;
+
+	if (!dma) return -EINVAL;
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	copy_from_user_ret(&request,
+			   (drm_buf_info_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+		if (dma->bufs[i].buf_count) ++count;
+	}
+	
+	DRM_DEBUG("count = %d\n", count);
+	
+	if (request.count >= count) {
+		for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+			if (dma->bufs[i].buf_count) {
+				copy_to_user_ret(&request.list[count].count,
+						 &dma->bufs[i].buf_count,
+						 sizeof(dma->bufs[0]
+							.buf_count),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count].size,
+						 &dma->bufs[i].buf_size,
+						 sizeof(dma->bufs[0].buf_size),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count].low_mark,
+						 &dma->bufs[i]
+						 .freelist.low_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.low_mark),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count]
+						 .high_mark,
+						 &dma->bufs[i]
+						 .freelist.high_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.high_mark),
+						 -EFAULT);
+				DRM_DEBUG("%d %d %d %d %d\n",
+					  i,
+					  dma->bufs[i].buf_count,
+					  dma->bufs[i].buf_size,
+					  dma->bufs[i].freelist.low_mark,
+					  dma->bufs[i].freelist.high_mark);
+				++count;
+			}
+		}
+	}
+	request.count = count;
+
+	copy_to_user_ret((drm_buf_info_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+	
+	return 0;
+}
+
+int drm_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 order;
+	drm_buf_entry_t	 *entry;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	DRM_DEBUG("%d, %d, %d\n",
+		  request.size, request.low_mark, request.high_mark);
+	order = drm_order(request.size);
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	entry = &dma->bufs[order];
+
+	if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+		return -EINVAL;
+	if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+		return -EINVAL;
+
+	entry->freelist.low_mark  = request.low_mark;
+	entry->freelist.high_mark = request.high_mark;
+	
+	return 0;
+}
+
+int drm_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_free_t	 request;
+	int		 i;
+	int		 idx;
+	drm_buf_t	 *buf;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_free_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	DRM_DEBUG("%d\n", request.count);
+	for (i = 0; i < request.count; i++) {
+		copy_from_user_ret(&idx,
+				   &request.list[i],
+				   sizeof(idx),
+				   -EFAULT);
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  idx, dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[idx];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d freeing buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		drm_free_buffer(dev, buf);
+	}
+	
+	return 0;
+}
+
+int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	int		 retcode = 0;
+	const int	 zero	 = 0;
+	unsigned long	 virtual;
+	unsigned long	 address;
+	drm_buf_map_t	 request;
+	int		 i;
+
+	if (!dma) return -EINVAL;
+	
+	DRM_DEBUG("\n");
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	copy_from_user_ret(&request,
+			   (drm_buf_map_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	if (request.count >= dma->buf_count) {
+		down(&current->mm->mmap_sem);
+		virtual = do_mmap(filp, 0, dma->byte_count,
+				  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+		up(&current->mm->mmap_sem);
+		if (virtual > -1024UL) {
+				/* Real error */
+			retcode = (signed long)virtual;
+			goto done;
+		}
+		request.virtual = (void *)virtual;
+
+		for (i = 0; i < dma->buf_count; i++) {
+			if (copy_to_user(&request.list[i].idx,
+					 &dma->buflist[i]->idx,
+					 sizeof(request.list[0].idx))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].total,
+					 &dma->buflist[i]->total,
+					 sizeof(request.list[0].total))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].used,
+					 &zero,
+					 sizeof(zero))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			address = virtual + dma->buflist[i]->offset;
+			if (copy_to_user(&request.list[i].address,
+					 &address,
+					 sizeof(address))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+		}
+	}
+done:
+	request.count = dma->buf_count;
+	DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
+
+	copy_to_user_ret((drm_buf_map_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+
+	return retcode;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/context.c linux.18p8/drivers/char/drm/context.c
--- linux.vanilla/drivers/char/drm/context.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/context.c	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,308 @@
+/* context.c -- IOCTLs for contexts and DMA queues -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static int drm_init_queue(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx)
+{
+	DRM_DEBUG("\n");
+	
+	if (atomic_read(&q->use_count) != 1
+	    || atomic_read(&q->finalization)
+	    || atomic_read(&q->block_count)) {
+		DRM_ERROR("New queue is already in use: u%d f%d b%d\n",
+			  atomic_read(&q->use_count),
+			  atomic_read(&q->finalization),
+			  atomic_read(&q->block_count));
+	}
+		  
+	atomic_set(&q->finalization,  0);
+	atomic_set(&q->block_count,   0);
+	atomic_set(&q->block_read,    0);
+	atomic_set(&q->block_write,   0);
+	atomic_set(&q->total_queued,  0);
+	atomic_set(&q->total_flushed, 0);
+	atomic_set(&q->total_locks,   0);
+
+	init_waitqueue_head(&q->write_queue);
+	init_waitqueue_head(&q->read_queue);
+	init_waitqueue_head(&q->flush_queue);
+
+	q->flags = ctx->flags;
+
+	drm_waitlist_create(&q->waitlist, dev->dma->buf_count);
+
+	return 0;
+}
+
+
+/* drm_alloc_queue:
+PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not
+	disappear (so all deallocation must be done after IOCTLs are off)
+     2) dev->queue_count < dev->queue_slots
+     3) dev->queuelist[i].use_count == 0 and
+	dev->queuelist[i].finalization == 0 if i not in use 
+POST: 1) dev->queuelist[i].use_count == 1
+      2) dev->queue_count < dev->queue_slots */
+		
+static int drm_alloc_queue(drm_device_t *dev)
+{
+	int	    i;
+	drm_queue_t *queue;
+	int	    oldslots;
+	int	    newslots;
+				/* Check for a free queue */
+	for (i = 0; i < dev->queue_count; i++) {
+		atomic_inc(&dev->queuelist[i]->use_count);
+		if (atomic_read(&dev->queuelist[i]->use_count) == 1
+		    && !atomic_read(&dev->queuelist[i]->finalization)) {
+			DRM_DEBUG("%d (free)\n", i);
+			return i;
+		}
+		atomic_dec(&dev->queuelist[i]->use_count);
+	}
+				/* Allocate a new queue */
+	down(&dev->struct_sem);
+	
+	queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
+	memset(queue, 0, sizeof(*queue));
+	atomic_set(&queue->use_count, 1);
+	
+	++dev->queue_count;
+	if (dev->queue_count >= dev->queue_slots) {
+		oldslots = dev->queue_slots * sizeof(*dev->queuelist);
+		if (!dev->queue_slots) dev->queue_slots = 1;
+		dev->queue_slots *= 2;
+		newslots = dev->queue_slots * sizeof(*dev->queuelist);
+
+		dev->queuelist = drm_realloc(dev->queuelist,
+					     oldslots,
+					     newslots,
+					     DRM_MEM_QUEUES);
+		if (!dev->queuelist) {
+			up(&dev->struct_sem);
+			DRM_DEBUG("out of memory\n");
+			return -ENOMEM;
+		}
+	}
+	dev->queuelist[dev->queue_count-1] = queue;
+	
+	up(&dev->struct_sem);
+	DRM_DEBUG("%d (new)\n", dev->queue_count - 1);
+	return dev->queue_count - 1;
+}
+
+int drm_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			copy_to_user_ret(&res.contexts[i],
+					 &i,
+					 sizeof(i),
+					 -EFAULT);
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+	return 0;
+}
+
+
+int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+				/* Init kernel's context and get a new one. */
+		drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+		ctx.handle = drm_alloc_queue(dev);
+	}
+	drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
+	DRM_DEBUG("%d\n", ctx.handle);
+	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int drm_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	drm_queue_t	*q;
+		
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	
+	DRM_DEBUG("%d\n", ctx.handle);
+	
+	if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL;
+	q = dev->queuelist[ctx.handle];
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) == 1) {
+				/* No longer in use */
+		atomic_dec(&q->use_count);
+		return -EINVAL;
+	}
+
+	if (DRM_BUFCOUNT(&q->waitlist)) {
+		atomic_dec(&q->use_count);
+		return -EBUSY;
+	}
+	
+	q->flags = ctx.flags;
+	
+	atomic_dec(&q->use_count);
+	return 0;
+}
+
+int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	drm_queue_t	*q;
+		
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	
+	DRM_DEBUG("%d\n", ctx.handle);
+	
+	if (ctx.handle >= dev->queue_count) return -EINVAL;
+	q = dev->queuelist[ctx.handle];
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) == 1) {
+				/* No longer in use */
+		atomic_dec(&q->use_count);
+		return -EINVAL;
+	}
+	
+	ctx.flags = q->flags;
+	atomic_dec(&q->use_count);
+	
+	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+	
+	return 0;
+}
+
+int drm_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	return drm_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int drm_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	drm_context_switch_complete(dev, ctx.handle);
+
+	return 0;
+}
+
+int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	drm_queue_t	*q;
+	drm_buf_t	*buf;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	
+	if (ctx.handle >= dev->queue_count) return -EINVAL;
+	q = dev->queuelist[ctx.handle];
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) == 1) {
+				/* No longer in use */
+		atomic_dec(&q->use_count);
+		return -EINVAL;
+	}
+	
+	atomic_inc(&q->finalization); /* Mark queue in finalization state */
+	atomic_sub(2, &q->use_count); /* Mark queue as unused (pending
+					 finalization) */
+
+	while (test_and_set_bit(0, &dev->interrupt_flag)) {
+		schedule();
+		if (signal_pending(current)) {
+			clear_bit(0, &dev->interrupt_flag);
+			return -EINTR;
+		}
+	}
+				/* Remove queued buffers */
+	while ((buf = drm_waitlist_get(&q->waitlist))) {
+		drm_free_buffer(dev, buf);
+	}
+	clear_bit(0, &dev->interrupt_flag);
+	
+				/* Wakeup blocked processes */
+	wake_up_interruptible(&q->read_queue);
+	wake_up_interruptible(&q->write_queue);
+	wake_up_interruptible(&q->flush_queue);
+	
+				/* Finalization over.  Queue is made
+				   available when both use_count and
+				   finalization become 0, which won't
+				   happen until all the waiting processes
+				   stop waiting. */
+	atomic_dec(&q->finalization);
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/ctxbitmap.c linux.18p8/drivers/char/drm/ctxbitmap.c
--- linux.vanilla/drivers/char/drm/ctxbitmap.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/ctxbitmap.c	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,85 @@
+/* ctxbitmap.c -- Context bitmap management -*- linux-c -*-
+ * Created: Thu Jan 6 03:56:42 2000 by jhartmann@precisioninsight.com
+ * 
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+void drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle)
+{
+	if (ctx_handle < 0) goto failed;
+
+	if (ctx_handle < DRM_MAX_CTXBITMAP) {
+		clear_bit(ctx_handle, dev->ctx_bitmap);
+		return;
+	}
+failed:
+       	DRM_ERROR("Attempt to free invalid context handle: %d\n",
+		  ctx_handle);
+       	return;
+}
+
+int drm_ctxbitmap_next(drm_device_t *dev)
+{
+	int bit;
+
+	bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
+	if (bit < DRM_MAX_CTXBITMAP) {
+		set_bit(bit, dev->ctx_bitmap);
+	   	DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit);
+		return bit;
+	}
+	return -1;
+}
+
+int drm_ctxbitmap_init(drm_device_t *dev)
+{
+	int i;
+   	int temp;
+
+	dev->ctx_bitmap = (unsigned long *) drm_alloc(PAGE_SIZE, 
+						      DRM_MEM_CTXBITMAP);
+	if(dev->ctx_bitmap == NULL) {
+		return -ENOMEM;
+	}
+	memset((void *) dev->ctx_bitmap, 0, PAGE_SIZE);
+	for(i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+		temp = drm_ctxbitmap_next(dev);
+	   	DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
+	}
+
+	return 0;
+}
+
+void drm_ctxbitmap_cleanup(drm_device_t *dev)
+{
+	drm_free((void *)dev->ctx_bitmap, PAGE_SIZE,
+		 DRM_MEM_CTXBITMAP);
+}
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/dma.c linux.18p8/drivers/char/drm/dma.c
--- linux.vanilla/drivers/char/drm/dma.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/dma.c	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,540 @@
+/* dma.c -- DMA IOCTL and function support -*- linux-c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinuxa.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+void drm_dma_setup(drm_device_t *dev)
+{
+	int i;
+	
+	dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER);
+	memset(dev->dma, 0, sizeof(*dev->dma));
+	for (i = 0; i <= DRM_MAX_ORDER; i++)
+		memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
+}
+
+void drm_dma_takedown(drm_device_t *dev)
+{
+	drm_device_dma_t  *dma = dev->dma;
+	int		  i, j;
+
+	if (!dma) return;
+	
+				/* Clear dma buffers */
+	for (i = 0; i <= DRM_MAX_ORDER; i++) {
+		if (dma->bufs[i].seg_count) {
+			DRM_DEBUG("order %d: buf_count = %d,"
+				  " seg_count = %d\n",
+				  i,
+				  dma->bufs[i].buf_count,
+				  dma->bufs[i].seg_count);
+			for (j = 0; j < dma->bufs[i].seg_count; j++) {
+				drm_free_pages(dma->bufs[i].seglist[j],
+					       dma->bufs[i].page_order,
+					       DRM_MEM_DMA);
+			}
+			drm_free(dma->bufs[i].seglist,
+				 dma->bufs[i].seg_count
+				 * sizeof(*dma->bufs[0].seglist),
+				 DRM_MEM_SEGS);
+		}
+	   	if(dma->bufs[i].buf_count) {
+		   	for(j = 0; j < dma->bufs[i].buf_count; j++) {
+			   if(dma->bufs[i].buflist[j].dev_private) {
+			      drm_free(dma->bufs[i].buflist[j].dev_private,
+				       dma->bufs[i].buflist[j].dev_priv_size,
+				       DRM_MEM_BUFS);
+			   }
+			}
+		   	drm_free(dma->bufs[i].buflist,
+				 dma->bufs[i].buf_count *
+				 sizeof(*dma->bufs[0].buflist),
+				 DRM_MEM_BUFS);
+		   	drm_freelist_destroy(&dma->bufs[i].freelist);
+		}
+	}
+	
+	if (dma->buflist) {
+		drm_free(dma->buflist,
+			 dma->buf_count * sizeof(*dma->buflist),
+			 DRM_MEM_BUFS);
+	}
+
+	if (dma->pagelist) {
+		drm_free(dma->pagelist,
+			 dma->page_count * sizeof(*dma->pagelist),
+			 DRM_MEM_PAGES);
+	}
+	drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER);
+	dev->dma = NULL;
+}
+
+#if DRM_DMA_HISTOGRAM
+/* This is slow, but is useful for debugging. */
+int drm_histogram_slot(unsigned long count)
+{
+	int value = DRM_DMA_HISTOGRAM_INITIAL;
+	int slot;
+
+	for (slot = 0;
+	     slot < DRM_DMA_HISTOGRAM_SLOTS;
+	     ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) {
+		if (count < value) return slot;
+	}
+	return DRM_DMA_HISTOGRAM_SLOTS - 1;
+}
+
+void drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf)
+{
+	cycles_t queued_to_dispatched;
+	cycles_t dispatched_to_completed;
+	cycles_t completed_to_freed;
+	int	 q2d, d2c, c2f, q2c, q2f;
+	
+	if (buf->time_queued) {
+		queued_to_dispatched	= (buf->time_dispatched
+					   - buf->time_queued);
+		dispatched_to_completed = (buf->time_completed
+					   - buf->time_dispatched);
+		completed_to_freed	= (buf->time_freed
+					   - buf->time_completed);
+
+		q2d = drm_histogram_slot(queued_to_dispatched);
+		d2c = drm_histogram_slot(dispatched_to_completed);
+		c2f = drm_histogram_slot(completed_to_freed);
+
+		q2c = drm_histogram_slot(queued_to_dispatched
+					 + dispatched_to_completed);
+		q2f = drm_histogram_slot(queued_to_dispatched
+					 + dispatched_to_completed
+					 + completed_to_freed);
+		
+		atomic_inc(&dev->histo.total);
+		atomic_inc(&dev->histo.queued_to_dispatched[q2d]);
+		atomic_inc(&dev->histo.dispatched_to_completed[d2c]);
+		atomic_inc(&dev->histo.completed_to_freed[c2f]);
+		
+		atomic_inc(&dev->histo.queued_to_completed[q2c]);
+		atomic_inc(&dev->histo.queued_to_freed[q2f]);
+
+	}
+	buf->time_queued     = 0;
+	buf->time_dispatched = 0;
+	buf->time_completed  = 0;
+	buf->time_freed	     = 0;
+}
+#endif
+
+void drm_free_buffer(drm_device_t *dev, drm_buf_t *buf)
+{
+	drm_device_dma_t *dma = dev->dma;
+
+	if (!buf) return;
+	
+	buf->waiting  = 0;
+	buf->pending  = 0;
+	buf->pid      = 0;
+	buf->used     = 0;
+#if DRM_DMA_HISTOGRAM
+	buf->time_completed = get_cycles();
+#endif
+	if (waitqueue_active(&buf->dma_wait)) {
+		wake_up_interruptible(&buf->dma_wait);
+	} else {
+				/* If processes are waiting, the last one
+				   to wake will put the buffer on the free
+				   list.  If no processes are waiting, we
+				   put the buffer on the freelist here. */
+		drm_freelist_put(dev, &dma->bufs[buf->order].freelist, buf);
+	}
+}
+
+void drm_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	if (!dma) return;
+	for (i = 0; i < dma->buf_count; i++) {
+		if (dma->buflist[i]->pid == pid) {
+			switch (dma->buflist[i]->list) {
+			case DRM_LIST_NONE:
+				drm_free_buffer(dev, dma->buflist[i]);
+				break;
+			case DRM_LIST_WAIT:
+				dma->buflist[i]->list = DRM_LIST_RECLAIM;
+				break;
+			default:
+				/* Buffer already on hardware. */
+				break;
+			}
+		}
+	}
+}
+
+int drm_context_switch(drm_device_t *dev, int old, int new)
+{
+	char	    buf[64];
+	drm_queue_t *q;
+
+	atomic_inc(&dev->total_ctx);
+
+	if (test_and_set_bit(0, &dev->context_flag)) {
+		DRM_ERROR("Reentering -- FIXME\n");
+		return -EBUSY;
+	}
+
+#if DRM_DMA_HISTOGRAM
+	dev->ctx_start = get_cycles();
+#endif
+	
+	DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+	if (new >= dev->queue_count) {
+		clear_bit(0, &dev->context_flag);
+		return -EINVAL;
+	}
+
+	if (new == dev->last_context) {
+		clear_bit(0, &dev->context_flag);
+		return 0;
+	}
+	
+	q = dev->queuelist[new];
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) == 1) {
+		atomic_dec(&q->use_count);
+		clear_bit(0, &dev->context_flag);
+		return -EINVAL;
+	}
+
+	if (drm_flags & DRM_FLAG_NOCTX) {
+		drm_context_switch_complete(dev, new);
+	} else {
+		sprintf(buf, "C %d %d\n", old, new);
+		drm_write_string(dev, buf);
+	}
+	
+	atomic_dec(&q->use_count);
+	
+	return 0;
+}
+
+int drm_context_switch_complete(drm_device_t *dev, int new)
+{
+	drm_device_dma_t *dma = dev->dma;
+	
+	dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+	dev->last_switch  = jiffies;
+	
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("Lock isn't held after context switch\n");
+	}
+
+	if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("Cannot free lock\n");
+		}
+	}
+	
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+						      - dev->ctx_start)]);
+		   
+#endif
+	clear_bit(0, &dev->context_flag);
+	wake_up_interruptible(&dev->context_wait);
+	
+	return 0;
+}
+
+void drm_clear_next_buffer(drm_device_t *dev)
+{
+	drm_device_dma_t *dma = dev->dma;
+	
+	dma->next_buffer = NULL;
+	if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) {
+		wake_up_interruptible(&dma->next_queue->flush_queue);
+	}
+	dma->next_queue	 = NULL;
+}
+
+
+int drm_select_queue(drm_device_t *dev, void (*wrapper)(unsigned long))
+{
+	int	   i;
+	int	   candidate = -1;
+	int	   j	     = jiffies;
+
+	if (!dev) {
+		DRM_ERROR("No device\n");
+		return -1;
+	}
+	if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) {
+				/* This only happens between the time the
+				   interrupt is initialized and the time
+				   the queues are initialized. */
+		return -1;
+	}
+
+				/* Doing "while locked" DMA? */
+	if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) {
+		return DRM_KERNEL_CONTEXT;
+	}
+
+				/* If there are buffers on the last_context
+				   queue, and we have not been executing
+				   this context very long, continue to
+				   execute this context. */
+	if (dev->last_switch <= j
+	    && dev->last_switch + DRM_TIME_SLICE > j
+	    && DRM_WAITCOUNT(dev, dev->last_context)) {
+		return dev->last_context;
+	}
+
+				/* Otherwise, find a candidate */
+	for (i = dev->last_checked + 1; i < dev->queue_count; i++) {
+		if (DRM_WAITCOUNT(dev, i)) {
+			candidate = dev->last_checked = i;
+			break;
+		}
+	}
+
+	if (candidate < 0) {
+		for (i = 0; i < dev->queue_count; i++) {
+			if (DRM_WAITCOUNT(dev, i)) {
+				candidate = dev->last_checked = i;
+				break;
+			}
+		}
+	}
+
+	if (wrapper
+	    && candidate >= 0
+	    && candidate != dev->last_context
+	    && dev->last_switch <= j
+	    && dev->last_switch + DRM_TIME_SLICE > j) {
+		if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) {
+			del_timer(&dev->timer);
+			dev->timer.function = wrapper;
+			dev->timer.data	    = (unsigned long)dev;
+			dev->timer.expires  = dev->last_switch+DRM_TIME_SLICE;
+			add_timer(&dev->timer);
+		}
+		return -1;
+	}
+
+	return candidate;
+}
+
+
+int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d)
+{
+	int		  i;
+	drm_queue_t	  *q;
+	drm_buf_t	  *buf;
+	int		  idx;
+	int		  while_locked = 0;
+	drm_device_dma_t  *dma = dev->dma;
+	DECLARE_WAITQUEUE(entry, current);
+
+	DRM_DEBUG("%d\n", d->send_count);
+
+	if (d->flags & _DRM_DMA_WHILE_LOCKED) {
+		int context = dev->lock.hw_lock->lock;
+		
+		if (!_DRM_LOCK_IS_HELD(context)) {
+			DRM_ERROR("No lock held during \"while locked\""
+				  " request\n");
+			return -EINVAL;
+		}
+		if (d->context != _DRM_LOCKING_CONTEXT(context)
+		    && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) {
+			DRM_ERROR("Lock held by %d while %d makes"
+				  " \"while locked\" request\n",
+				  _DRM_LOCKING_CONTEXT(context),
+				  d->context);
+			return -EINVAL;
+		}
+		q = dev->queuelist[DRM_KERNEL_CONTEXT];
+		while_locked = 1;
+	} else {
+		q = dev->queuelist[d->context];
+	}
+
+
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->block_write)) {
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&q->write_queue, &entry);
+		atomic_inc(&q->block_count);
+		for (;;) {
+			if (!atomic_read(&q->block_write)) break;
+			schedule();
+			if (signal_pending(current)) {
+				atomic_dec(&q->use_count);
+				return -EINTR;
+			}
+		}
+		atomic_dec(&q->block_count);
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&q->write_queue, &entry);
+	}
+	
+	for (i = 0; i < d->send_count; i++) {
+		idx = d->send_indices[i];
+		if (idx < 0 || idx >= dma->buf_count) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Index %d (of %d max)\n",
+				  d->send_indices[i], dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[ idx ];
+		if (buf->pid != current->pid) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Process %d using buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		if (buf->list != DRM_LIST_NONE) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Process %d using buffer %d on list %d\n",
+				  current->pid, buf->idx, buf->list);
+		}
+		buf->used	  = d->send_sizes[i];
+		buf->while_locked = while_locked;
+		buf->context	  = d->context;
+		if (!buf->used) {
+			DRM_ERROR("Queueing 0 length buffer\n");
+		}
+		if (buf->pending) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Queueing pending buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			return -EINVAL;
+		}
+		if (buf->waiting) {
+			atomic_dec(&q->use_count);
+			DRM_ERROR("Queueing waiting buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			return -EINVAL;
+		}
+		buf->waiting = 1;
+		if (atomic_read(&q->use_count) == 1
+		    || atomic_read(&q->finalization)) {
+			drm_free_buffer(dev, buf);
+		} else {
+			drm_waitlist_put(&q->waitlist, buf);
+			atomic_inc(&q->total_queued);
+		}
+	}
+	atomic_dec(&q->use_count);
+	
+	return 0;
+}
+
+static int drm_dma_get_buffers_of_order(drm_device_t *dev, drm_dma_t *d,
+					int order)
+{
+	int		  i;
+	drm_buf_t	  *buf;
+	drm_device_dma_t  *dma = dev->dma;
+	
+	for (i = d->granted_count; i < d->request_count; i++) {
+		buf = drm_freelist_get(&dma->bufs[order].freelist,
+				       d->flags & _DRM_DMA_WAIT);
+		if (!buf) break;
+		if (buf->pending || buf->waiting) {
+			DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n",
+				  buf->idx,
+				  buf->pid,
+				  buf->waiting,
+				  buf->pending);
+		}
+		buf->pid     = current->pid;
+		copy_to_user_ret(&d->request_indices[i],
+				 &buf->idx,
+				 sizeof(buf->idx),
+				 -EFAULT);
+		copy_to_user_ret(&d->request_sizes[i],
+				 &buf->total,
+				 sizeof(buf->total),
+				 -EFAULT);
+		++d->granted_count;
+	}
+	return 0;
+}
+
+
+int drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma)
+{
+	int		  order;
+	int		  retcode = 0;
+	int		  tmp_order;
+	
+	order = drm_order(dma->request_size);
+
+	dma->granted_count = 0;
+	retcode		   = drm_dma_get_buffers_of_order(dev, dma, order);
+
+	if (dma->granted_count < dma->request_count
+	    && (dma->flags & _DRM_DMA_SMALLER_OK)) {
+		for (tmp_order = order - 1;
+		     !retcode
+			     && dma->granted_count < dma->request_count
+			     && tmp_order >= DRM_MIN_ORDER;
+		     --tmp_order) {
+			
+			retcode = drm_dma_get_buffers_of_order(dev, dma,
+							       tmp_order);
+		}
+	}
+
+	if (dma->granted_count < dma->request_count
+	    && (dma->flags & _DRM_DMA_LARGER_OK)) {
+		for (tmp_order = order + 1;
+		     !retcode
+			     && dma->granted_count < dma->request_count
+			     && tmp_order <= DRM_MAX_ORDER;
+		     ++tmp_order) {
+			
+			retcode = drm_dma_get_buffers_of_order(dev, dma,
+							       tmp_order);
+		}
+	}
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/drawable.c linux.18p8/drivers/char/drm/drawable.c
--- linux.vanilla/drivers/char/drm/drawable.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/drawable.c	Fri Sep  1 14:12:32 2000
@@ -0,0 +1,50 @@
+/* drawable.c -- IOCTLs for drawables -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_draw_t draw;
+
+	draw.handle = 0;	/* NOOP */
+	DRM_DEBUG("%d\n", draw.handle);
+	copy_to_user_ret((drm_draw_t *)arg, &draw, sizeof(draw), -EFAULT);
+	return 0;
+}
+
+int drm_rmdraw(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	return 0;		/* NOOP */
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/drm.h linux.18p8/drivers/char/drm/drm.h
--- linux.vanilla/drivers/char/drm/drm.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/drm.h	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,367 @@
+/* drm.h -- Header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ * Acknowledgements:
+ * Dec 1999, Richard Henderson <rth@twiddle.net>, move to generic cmpxchg.
+ *
+ */
+
+#ifndef _DRM_H_
+#define _DRM_H_
+
+#include <asm/ioctl.h>		/* For _IO* macros */
+
+#define DRM_PROC_DEVICES "/proc/devices"
+#define DRM_PROC_MISC	 "/proc/misc"
+#define DRM_PROC_DRM	 "/proc/drm"
+#define DRM_DEV_DRM	 "/dev/drm"
+#define DRM_DEV_MODE	 (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+#define DRM_DEV_UID	 0
+#define DRM_DEV_GID	 0
+
+
+#define DRM_NAME	"drm"	  /* Name in kernel, /dev, and /proc	    */
+#define DRM_MIN_ORDER	5	  /* At least 2^5 bytes = 32 bytes	    */
+#define DRM_MAX_ORDER	22	  /* Up to 2^22 bytes = 4MB		    */
+#define DRM_RAM_PERCENT 10	  /* How much system ram can we lock?	    */
+
+#define _DRM_LOCK_HELD	0x80000000 /* Hardware lock is held		    */
+#define _DRM_LOCK_CONT	0x40000000 /* Hardware lock is contended	    */
+#define _DRM_LOCK_IS_HELD(lock)	   ((lock) & _DRM_LOCK_HELD)
+#define _DRM_LOCK_IS_CONT(lock)	   ((lock) & _DRM_LOCK_CONT)
+#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT))
+
+typedef unsigned long drm_handle_t;
+typedef unsigned int  drm_context_t;
+typedef unsigned int  drm_drawable_t;
+typedef unsigned int  drm_magic_t;
+
+/* Warning: If you change this structure, make sure you change
+ * XF86DRIClipRectRec in the server as well */
+
+typedef struct drm_clip_rect {
+           unsigned short x1;
+           unsigned short y1;
+           unsigned short x2;
+           unsigned short y2;
+} drm_clip_rect_t;
+
+/* Seperate include files for the i810/mga/r128 specific structures */
+#include "mga_drm.h"
+#include "i810_drm.h"
+#include "r128_drm.h"
+
+typedef struct drm_version {
+	int    version_major;	  /* Major version			    */
+	int    version_minor;	  /* Minor version			    */
+	int    version_patchlevel;/* Patch level			    */
+	size_t name_len;	  /* Length of name buffer		    */
+	char   *name;		  /* Name of driver			    */
+	size_t date_len;	  /* Length of date buffer		    */
+	char   *date;		  /* User-space buffer to hold date	    */
+	size_t desc_len;	  /* Length of desc buffer		    */
+	char   *desc;		  /* User-space buffer to hold desc	    */
+} drm_version_t;
+
+typedef struct drm_unique {
+	size_t unique_len;	  /* Length of unique			    */
+	char   *unique;		  /* Unique name for driver instantiation   */
+} drm_unique_t;
+
+typedef struct drm_list {
+	int		 count;	  /* Length of user-space structures	    */
+	drm_version_t	 *version;
+} drm_list_t;
+
+typedef struct drm_block {
+	int		 unused;
+} drm_block_t;
+
+typedef struct drm_control {
+	enum {
+		DRM_ADD_COMMAND,
+		DRM_RM_COMMAND,
+		DRM_INST_HANDLER,
+		DRM_UNINST_HANDLER
+	}		 func;
+	int		 irq;
+} drm_control_t;
+
+typedef enum drm_map_type {
+	_DRM_FRAME_BUFFER = 0,	  /* WC (no caching), no core dump	    */
+	_DRM_REGISTERS	  = 1,	  /* no caching, no core dump		    */
+	_DRM_SHM	  = 2,	  /* shared, cached			    */
+	_DRM_AGP          = 3	  /* AGP/GART                               */
+} drm_map_type_t;
+
+typedef enum drm_map_flags {
+	_DRM_RESTRICTED	     = 0x01, /* Cannot be mapped to user-virtual    */
+	_DRM_READ_ONLY	     = 0x02,
+	_DRM_LOCKED	     = 0x04, /* shared, cached, locked		    */
+	_DRM_KERNEL	     = 0x08, /* kernel requires access		    */
+	_DRM_WRITE_COMBINING = 0x10, /* use write-combining if available    */
+	_DRM_CONTAINS_LOCK   = 0x20  /* SHM page that contains lock	    */
+} drm_map_flags_t;
+
+typedef struct drm_map {
+	unsigned long	offset;	 /* Requested physical address (0 for SAREA)*/
+	unsigned long	size;	 /* Requested physical size (bytes)	    */
+	drm_map_type_t	type;	 /* Type of memory to map		    */
+	drm_map_flags_t flags;	 /* Flags				    */
+	void		*handle; /* User-space: "Handle" to pass to mmap    */
+				 /* Kernel-space: kernel-virtual address    */
+	int		mtrr;	 /* MTRR slot used			    */
+				 /* Private data			    */
+} drm_map_t;
+
+typedef enum drm_lock_flags {
+	_DRM_LOCK_READY	     = 0x01, /* Wait until hardware is ready for DMA */
+	_DRM_LOCK_QUIESCENT  = 0x02, /* Wait until hardware quiescent	     */
+	_DRM_LOCK_FLUSH	     = 0x04, /* Flush this context's DMA queue first */
+	_DRM_LOCK_FLUSH_ALL  = 0x08, /* Flush all DMA queues first	     */
+				/* These *HALT* flags aren't supported yet
+				   -- they will be used to support the
+				   full-screen DGA-like mode. */
+	_DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues   */
+	_DRM_HALT_CUR_QUEUES = 0x20  /* Halt all current queues		     */
+} drm_lock_flags_t;
+
+typedef struct drm_lock {
+	int		 context;
+	drm_lock_flags_t flags;
+} drm_lock_t;
+
+typedef enum drm_dma_flags {	      /* These values *MUST* match xf86drm.h */
+				      /* Flags for DMA buffer dispatch	     */
+	_DRM_DMA_BLOCK	      = 0x01, /* Block until buffer dispatched.
+					 Note, the buffer may not yet have
+					 been processed by the hardware --
+					 getting a hardware lock with the
+					 hardware quiescent will ensure
+					 that the buffer has been
+					 processed.			     */
+	_DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held	     */
+	_DRM_DMA_PRIORITY     = 0x04, /* High priority dispatch		     */
+
+				      /* Flags for DMA buffer request	     */
+	_DRM_DMA_WAIT	      = 0x10, /* Wait for free buffers		     */
+	_DRM_DMA_SMALLER_OK   = 0x20, /* Smaller-than-requested buffers ok   */
+	_DRM_DMA_LARGER_OK    = 0x40  /* Larger-than-requested buffers ok    */
+} drm_dma_flags_t;
+
+typedef struct drm_buf_desc {
+	int	      count;	 /* Number of buffers of this size	     */
+	int	      size;	 /* Size in bytes			     */
+	int	      low_mark;	 /* Low water mark			     */
+	int	      high_mark; /* High water mark			     */
+	enum {
+		_DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA  */
+		_DRM_AGP_BUFFER = 0x02  /* Buffer is in agp space            */
+	}	      flags;
+	unsigned long agp_start; /* Start address of where the agp buffers
+				  * are in the agp aperture */
+} drm_buf_desc_t;
+
+typedef struct drm_buf_info {
+	int	       count;	/* Entries in list			     */
+	drm_buf_desc_t *list;
+} drm_buf_info_t;
+
+typedef struct drm_buf_free {
+	int	       count;
+	int	       *list;
+} drm_buf_free_t;
+
+typedef struct drm_buf_pub {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	void		  *address;    /* Address of buffer		     */
+} drm_buf_pub_t;
+
+typedef struct drm_buf_map {
+	int	      count;	/* Length of buflist			    */
+	void	      *virtual;	/* Mmaped area in user-virtual		    */
+	drm_buf_pub_t *list;	/* Buffer information			    */
+} drm_buf_map_t;
+
+typedef struct drm_dma {
+				/* Indices here refer to the offset into
+				   buflist in drm_buf_get_t.  */
+	int		context;	  /* Context handle		    */
+	int		send_count;	  /* Number of buffers to send	    */
+	int		*send_indices;	  /* List of handles to buffers	    */
+	int		*send_sizes;	  /* Lengths of data to send	    */
+	drm_dma_flags_t flags;		  /* Flags			    */
+	int		request_count;	  /* Number of buffers requested    */
+	int		request_size;	  /* Desired size for buffers	    */
+	int		*request_indices; /* Buffer information		    */
+	int		*request_sizes;
+	int		granted_count;	  /* Number of buffers granted	    */
+} drm_dma_t;
+
+typedef enum {
+	_DRM_CONTEXT_PRESERVED = 0x01,
+	_DRM_CONTEXT_2DONLY    = 0x02
+} drm_ctx_flags_t;
+
+typedef struct drm_ctx {
+	drm_context_t	handle;
+	drm_ctx_flags_t flags;
+} drm_ctx_t;
+
+typedef struct drm_ctx_res {
+	int		count;
+	drm_ctx_t	*contexts;
+} drm_ctx_res_t;
+
+typedef struct drm_draw {
+	drm_drawable_t	handle;
+} drm_draw_t;
+
+typedef struct drm_auth {
+	drm_magic_t	magic;
+} drm_auth_t;
+
+typedef struct drm_irq_busid {
+	int irq;
+	int busnum;
+	int devnum;
+	int funcnum;
+} drm_irq_busid_t;
+
+typedef struct drm_agp_mode {
+	unsigned long mode;
+} drm_agp_mode_t;
+
+				/* For drm_agp_alloc -- allocated a buffer */
+typedef struct drm_agp_buffer {
+	unsigned long size;	/* In bytes -- will round to page boundary */
+	unsigned long handle;	/* Used for BIND/UNBIND ioctls */
+	unsigned long type;     /* Type of memory to allocate  */
+        unsigned long physical; /* Physical used by i810       */
+} drm_agp_buffer_t;
+
+				/* For drm_agp_bind */
+typedef struct drm_agp_binding {
+	unsigned long handle;   /* From drm_agp_buffer */
+	unsigned long offset;	/* In bytes -- will round to page boundary */
+} drm_agp_binding_t;
+
+typedef struct drm_agp_info {
+	int            agp_version_major;
+	int            agp_version_minor;
+	unsigned long  mode;
+	unsigned long  aperture_base;  /* physical address */
+	unsigned long  aperture_size;  /* bytes */
+	unsigned long  memory_allowed; /* bytes */
+	unsigned long  memory_used;
+
+				/* PCI information */
+	unsigned short id_vendor;
+	unsigned short id_device;
+} drm_agp_info_t;
+
+#define DRM_IOCTL_BASE	     'd'
+#define DRM_IOCTL_NR(n)	     _IOC_NR(n)
+#define DRM_IO(nr)	     _IO(DRM_IOCTL_BASE,nr)
+#define DRM_IOR(nr,size)     _IOR(DRM_IOCTL_BASE,nr,size)
+#define DRM_IOW(nr,size)     _IOW(DRM_IOCTL_BASE,nr,size)
+#define DRM_IOWR(nr,size)    _IOWR(DRM_IOCTL_BASE,nr,size)
+
+
+#define DRM_IOCTL_VERSION    DRM_IOWR(0x00, drm_version_t)
+#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t)
+#define DRM_IOCTL_GET_MAGIC  DRM_IOR( 0x02, drm_auth_t)
+#define DRM_IOCTL_IRQ_BUSID  DRM_IOWR(0x03, drm_irq_busid_t)
+
+#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t)
+#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t)
+#define DRM_IOCTL_BLOCK	     DRM_IOWR(0x12, drm_block_t)
+#define DRM_IOCTL_UNBLOCK    DRM_IOWR(0x13, drm_block_t)
+#define DRM_IOCTL_CONTROL    DRM_IOW( 0x14, drm_control_t)
+#define DRM_IOCTL_ADD_MAP    DRM_IOWR(0x15, drm_map_t)
+#define DRM_IOCTL_ADD_BUFS   DRM_IOWR(0x16, drm_buf_desc_t)
+#define DRM_IOCTL_MARK_BUFS  DRM_IOW( 0x17, drm_buf_desc_t)
+#define DRM_IOCTL_INFO_BUFS  DRM_IOWR(0x18, drm_buf_info_t)
+#define DRM_IOCTL_MAP_BUFS   DRM_IOWR(0x19, drm_buf_map_t)
+#define DRM_IOCTL_FREE_BUFS  DRM_IOW( 0x1a, drm_buf_free_t)
+
+#define DRM_IOCTL_ADD_CTX    DRM_IOWR(0x20, drm_ctx_t)
+#define DRM_IOCTL_RM_CTX     DRM_IOWR(0x21, drm_ctx_t)
+#define DRM_IOCTL_MOD_CTX    DRM_IOW( 0x22, drm_ctx_t)
+#define DRM_IOCTL_GET_CTX    DRM_IOWR(0x23, drm_ctx_t)
+#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t)
+#define DRM_IOCTL_NEW_CTX    DRM_IOW( 0x25, drm_ctx_t)
+#define DRM_IOCTL_RES_CTX    DRM_IOWR(0x26, drm_ctx_res_t)
+#define DRM_IOCTL_ADD_DRAW   DRM_IOWR(0x27, drm_draw_t)
+#define DRM_IOCTL_RM_DRAW    DRM_IOWR(0x28, drm_draw_t)
+#define DRM_IOCTL_DMA	     DRM_IOWR(0x29, drm_dma_t)
+#define DRM_IOCTL_LOCK	     DRM_IOW( 0x2a, drm_lock_t)
+#define DRM_IOCTL_UNLOCK     DRM_IOW( 0x2b, drm_lock_t)
+#define DRM_IOCTL_FINISH     DRM_IOW( 0x2c, drm_lock_t)
+
+#define DRM_IOCTL_AGP_ACQUIRE DRM_IO(  0x30)
+#define DRM_IOCTL_AGP_RELEASE DRM_IO(  0x31)
+#define DRM_IOCTL_AGP_ENABLE  DRM_IOW( 0x32, drm_agp_mode_t)
+#define DRM_IOCTL_AGP_INFO    DRM_IOR( 0x33, drm_agp_info_t)
+#define DRM_IOCTL_AGP_ALLOC   DRM_IOWR(0x34, drm_agp_buffer_t)
+#define DRM_IOCTL_AGP_FREE    DRM_IOW( 0x35, drm_agp_buffer_t)
+#define DRM_IOCTL_AGP_BIND    DRM_IOW( 0x36, drm_agp_binding_t)
+#define DRM_IOCTL_AGP_UNBIND  DRM_IOW( 0x37, drm_agp_binding_t)
+
+/* Mga specific ioctls */
+#define DRM_IOCTL_MGA_INIT    DRM_IOW( 0x40, drm_mga_init_t)
+#define DRM_IOCTL_MGA_SWAP    DRM_IOW( 0x41, drm_mga_swap_t)
+#define DRM_IOCTL_MGA_CLEAR   DRM_IOW( 0x42, drm_mga_clear_t)
+#define DRM_IOCTL_MGA_ILOAD   DRM_IOW( 0x43, drm_mga_iload_t)
+#define DRM_IOCTL_MGA_VERTEX  DRM_IOW( 0x44, drm_mga_vertex_t)
+#define DRM_IOCTL_MGA_FLUSH   DRM_IOW( 0x45, drm_lock_t )
+#define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t)
+
+/* I810 specific ioctls */
+#define DRM_IOCTL_I810_INIT    DRM_IOW( 0x40, drm_i810_init_t)
+#define DRM_IOCTL_I810_VERTEX  DRM_IOW( 0x41, drm_i810_vertex_t)
+#define DRM_IOCTL_I810_CLEAR   DRM_IOW( 0x42, drm_i810_clear_t)
+#define DRM_IOCTL_I810_FLUSH   DRM_IO ( 0x43)
+#define DRM_IOCTL_I810_GETAGE  DRM_IO ( 0x44)
+#define DRM_IOCTL_I810_GETBUF  DRM_IOWR(0x45, drm_i810_dma_t)
+#define DRM_IOCTL_I810_SWAP    DRM_IO ( 0x46)
+#define DRM_IOCTL_I810_COPY    DRM_IOW( 0x47, drm_i810_copy_t)
+#define DRM_IOCTL_I810_DOCOPY  DRM_IO ( 0x48)
+
+/* Rage 128 specific ioctls */
+#define DRM_IOCTL_R128_INIT	DRM_IOW( 0x40, drm_r128_init_t)
+#define DRM_IOCTL_R128_RESET	DRM_IO(  0x41)
+#define DRM_IOCTL_R128_FLUSH	DRM_IO(  0x42)
+#define DRM_IOCTL_R128_IDLE	DRM_IO(  0x43)
+#define DRM_IOCTL_R128_PACKET	DRM_IOW( 0x44, drm_r128_packet_t)
+#define DRM_IOCTL_R128_VERTEX	DRM_IOW( 0x45, drm_r128_vertex_t)
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/drmP.h linux.18p8/drivers/char/drm/drmP.h
--- linux.vanilla/drivers/char/drm/drmP.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/drmP.h	Fri Sep 15 15:07:22 2000
@@ -0,0 +1,743 @@
+/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ * 
+ */
+
+#ifndef _DRM_P_H_
+#define _DRM_P_H_
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/pci.h>
+#include <linux/wrapper.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>	/* For (un)lock_kernel */
+#include <asm/io.h>
+#include <asm/mman.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+#include <linux/types.h>
+#include <linux/agp_backend.h>
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#include <linux/tqueue.h>
+#include <linux/poll.h>
+#endif
+#include "drm.h"
+
+#define DRM_DEBUG_CODE 2	  /* Include debugging code (if > 1, then
+				     also include looping detection. */
+#define DRM_DMA_HISTOGRAM 1	  /* Make histogram of DMA latency. */
+
+#define DRM_HASH_SIZE	      16 /* Size of key hash table		  */
+#define DRM_KERNEL_CONTEXT    0	 /* Change drm_resctx if changed	  */
+#define DRM_RESERVED_CONTEXTS 1	 /* Change drm_resctx if changed	  */
+#define DRM_LOOPING_LIMIT     5000000
+#define DRM_BSZ		      1024 /* Buffer size for /dev/drm? output	  */
+#define DRM_TIME_SLICE	      (HZ/20)  /* Time slice for GLXContexts	  */
+#define DRM_LOCK_SLICE	      1	/* Time slice for lock, in jiffies	  */
+
+#define DRM_FLAG_DEBUG	  0x01
+#define DRM_FLAG_NOCTX	  0x02
+
+#define DRM_MEM_DMA	   0
+#define DRM_MEM_SAREA	   1
+#define DRM_MEM_DRIVER	   2
+#define DRM_MEM_MAGIC	   3
+#define DRM_MEM_IOCTLS	   4
+#define DRM_MEM_MAPS	   5
+#define DRM_MEM_VMAS	   6
+#define DRM_MEM_BUFS	   7
+#define DRM_MEM_SEGS	   8
+#define DRM_MEM_PAGES	   9
+#define DRM_MEM_FILES	  10
+#define DRM_MEM_QUEUES	  11
+#define DRM_MEM_CMDS	  12
+#define DRM_MEM_MAPPINGS  13
+#define DRM_MEM_BUFLISTS  14
+#define DRM_MEM_AGPLISTS  15
+#define DRM_MEM_TOTALAGP  16
+#define DRM_MEM_BOUNDAGP  17
+#define DRM_MEM_CTXBITMAP 18
+
+#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
+
+				/* Backward compatibility section */
+				/* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */
+#ifndef _PAGE_PWT
+#define _PAGE_PWT _PAGE_WT
+#endif
+				/* Wait queue declarations changed in 2.3.1 */
+#ifndef DECLARE_WAITQUEUE
+#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = { c, NULL }
+typedef struct wait_queue *wait_queue_head_t;
+#define init_waitqueue_head(q) *q = NULL;
+#endif
+
+				/* _PAGE_4M changed to _PAGE_PSE in 2.3.23 */
+#ifndef _PAGE_PSE
+#define _PAGE_PSE _PAGE_4M
+#endif
+
+				/* vm_offset changed to vm_pgoff in 2.3.25 */
+#if LINUX_VERSION_CODE < 0x020319
+#define VM_OFFSET(vma) ((vma)->vm_offset)
+#else
+#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
+#endif
+
+				/* *_nopage return values defined in 2.3.26 */
+#ifndef NOPAGE_SIGBUS
+#define NOPAGE_SIGBUS 0
+#endif
+#ifndef NOPAGE_OOM
+#define NOPAGE_OOM 0
+#endif
+
+				/* Generic cmpxchg added in 2.3.x */
+#ifndef __HAVE_ARCH_CMPXCHG
+				/* Include this here so that driver can be
+                                   used with older kernels. */
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	unsigned long prev;
+	switch (size) {
+	case 1:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 2:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 4:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	}
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						\
+  ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),		\
+				 (unsigned long)(n),sizeof(*(ptr))))
+#endif
+
+				/* Macros to make printk easier */
+#define DRM_ERROR(fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg)
+#define DRM_MEM_ERROR(area, fmt, arg...) \
+	printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ ":%s] *ERROR* " fmt , \
+	       drm_mem_stats[area].name , ##arg)
+#define DRM_INFO(fmt, arg...)  printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
+
+#if DRM_DEBUG_CODE
+#define DRM_DEBUG(fmt, arg...)						  \
+	do {								  \
+		if (drm_flags&DRM_FLAG_DEBUG)				  \
+			printk(KERN_DEBUG				  \
+			       "[" DRM_NAME ":" __FUNCTION__ "] " fmt ,	  \
+			       ##arg);					  \
+	} while (0)
+#else
+#define DRM_DEBUG(fmt, arg...)		 do { } while (0)
+#endif
+
+#define DRM_PROC_LIMIT (PAGE_SIZE-80)
+
+#define DRM_PROC_PRINT(fmt, arg...)	   \
+   len += sprintf(&buf[len], fmt , ##arg); \
+   if (len > DRM_PROC_LIMIT) return len;
+
+#define DRM_PROC_PRINT_RET(ret, fmt, arg...)	    \
+   len += sprintf(&buf[len], fmt , ##arg);	    \
+   if (len > DRM_PROC_LIMIT) { ret; return len; }
+
+				/* Internal types and structures */
+#define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define DRM_MIN(a,b) ((a)<(b)?(a):(b))
+#define DRM_MAX(a,b) ((a)>(b)?(a):(b))
+
+#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1))
+#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
+#define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist)
+
+typedef int drm_ioctl_t(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+
+typedef struct drm_ioctl_desc {
+	drm_ioctl_t	     *func;
+	int		     auth_needed;
+	int		     root_only;
+} drm_ioctl_desc_t;
+
+typedef struct drm_devstate {
+	pid_t		  owner;	/* X server pid holding x_lock */
+	
+} drm_devstate_t;
+
+typedef struct drm_magic_entry {
+	drm_magic_t	       magic;
+	struct drm_file	       *priv;
+	struct drm_magic_entry *next;
+} drm_magic_entry_t;
+
+typedef struct drm_magic_head {
+	struct drm_magic_entry *head;
+	struct drm_magic_entry *tail;
+} drm_magic_head_t;
+
+typedef struct drm_vma_entry {
+	struct vm_area_struct *vma;
+	struct drm_vma_entry  *next;
+	pid_t		      pid;
+} drm_vma_entry_t;
+
+typedef struct drm_buf {
+	int		  idx;	       /* Index into master buflist	     */
+	int		  total;       /* Buffer size			     */
+	int		  order;       /* log-base-2(total)		     */
+	int		  used;	       /* Amount of buffer in use (for DMA)  */
+	unsigned long	  offset;      /* Byte offset (used internally)	     */
+	void		  *address;    /* Address of buffer		     */
+	unsigned long	  bus_address; /* Bus address of buffer		     */
+	struct drm_buf	  *next;       /* Kernel-only: used for free list    */
+	__volatile__ int  waiting;     /* On kernel DMA queue		     */
+	__volatile__ int  pending;     /* On hardware DMA queue		     */
+	wait_queue_head_t dma_wait;    /* Processes waiting		     */
+	pid_t		  pid;	       /* PID of holding process	     */
+	int		  context;     /* Kernel queue for this buffer	     */
+	int		  while_locked;/* Dispatch this buffer while locked  */
+	enum {
+		DRM_LIST_NONE	 = 0,
+		DRM_LIST_FREE	 = 1,
+		DRM_LIST_WAIT	 = 2,
+		DRM_LIST_PEND	 = 3,
+		DRM_LIST_PRIO	 = 4,
+		DRM_LIST_RECLAIM = 5
+	}		  list;	       /* Which list we're on		     */
+
+#if DRM_DMA_HISTOGRAM
+	cycles_t	  time_queued;	   /* Queued to kernel DMA queue     */
+	cycles_t	  time_dispatched; /* Dispatched to hardware	     */
+	cycles_t	  time_completed;  /* Completed by hardware	     */
+	cycles_t	  time_freed;	   /* Back on freelist		     */
+#endif
+
+	int		  dev_priv_size; /* Size of buffer private stoarge   */
+	void		  *dev_private;  /* Per-buffer private storage       */
+} drm_buf_t;
+
+#if DRM_DMA_HISTOGRAM
+#define DRM_DMA_HISTOGRAM_SLOTS		  9
+#define DRM_DMA_HISTOGRAM_INITIAL	 10
+#define DRM_DMA_HISTOGRAM_NEXT(current)	 ((current)*10)
+typedef struct drm_histogram {
+	atomic_t	  total;
+	
+	atomic_t	  queued_to_dispatched[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  dispatched_to_completed[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  completed_to_freed[DRM_DMA_HISTOGRAM_SLOTS];
+	
+	atomic_t	  queued_to_completed[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  queued_to_freed[DRM_DMA_HISTOGRAM_SLOTS];
+	
+	atomic_t	  dma[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  schedule[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  ctx[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  lacq[DRM_DMA_HISTOGRAM_SLOTS];
+	atomic_t	  lhld[DRM_DMA_HISTOGRAM_SLOTS];
+} drm_histogram_t;
+#endif
+
+				/* bufs is one longer than it has to be */
+typedef struct drm_waitlist {
+	int		  count;	/* Number of possible buffers	   */
+	drm_buf_t	  **bufs;	/* List of pointers to buffers	   */
+	drm_buf_t	  **rp;		/* Read pointer			   */
+	drm_buf_t	  **wp;		/* Write pointer		   */
+	drm_buf_t	  **end;	/* End pointer			   */
+	spinlock_t	  read_lock;
+	spinlock_t	  write_lock;
+} drm_waitlist_t;
+
+typedef struct drm_freelist {
+	int		  initialized; /* Freelist in use		   */
+	atomic_t	  count;       /* Number of free buffers	   */
+	drm_buf_t	  *next;       /* End pointer			   */
+	
+	wait_queue_head_t waiting;     /* Processes waiting on free bufs   */
+	int		  low_mark;    /* Low water mark		   */
+	int		  high_mark;   /* High water mark		   */
+	atomic_t	  wfh;	       /* If waiting for high mark	   */
+} drm_freelist_t;
+
+typedef struct drm_buf_entry {
+	int		  buf_size;
+	int		  buf_count;
+	drm_buf_t	  *buflist;
+	int		  seg_count;
+	int		  page_order;
+	unsigned long	  *seglist;
+
+	drm_freelist_t	  freelist;
+} drm_buf_entry_t;
+
+typedef struct drm_hw_lock {
+	__volatile__ unsigned int lock;
+	char			  padding[60]; /* Pad to cache line */
+} drm_hw_lock_t;
+
+typedef struct drm_file {
+	int		  authenticated;
+	int		  minor;
+	pid_t		  pid;
+	uid_t		  uid;
+	drm_magic_t	  magic;
+	unsigned long	  ioctl_count;
+	struct drm_file	  *next;
+	struct drm_file	  *prev;
+	struct drm_device *dev;
+} drm_file_t;
+
+
+typedef struct drm_queue {
+	atomic_t	  use_count;	/* Outstanding uses (+1)	    */
+	atomic_t	  finalization;	/* Finalization in progress	    */
+	atomic_t	  block_count;	/* Count of processes waiting	    */
+	atomic_t	  block_read;	/* Queue blocked for reads	    */
+	wait_queue_head_t read_queue;	/* Processes waiting on block_read  */
+	atomic_t	  block_write;	/* Queue blocked for writes	    */
+	wait_queue_head_t write_queue;	/* Processes waiting on block_write */
+	atomic_t	  total_queued;	/* Total queued statistic	    */
+	atomic_t	  total_flushed;/* Total flushes statistic	    */
+	atomic_t	  total_locks;	/* Total locks statistics	    */
+	drm_ctx_flags_t	  flags;	/* Context preserving and 2D-only   */
+	drm_waitlist_t	  waitlist;	/* Pending buffers		    */
+	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
+} drm_queue_t;
+
+typedef struct drm_lock_data {
+	drm_hw_lock_t	  *hw_lock;	/* Hardware lock		   */
+	pid_t		  pid;		/* PID of lock holder (0=kernel)   */
+	wait_queue_head_t lock_queue;	/* Queue of blocked processes	   */
+	unsigned long	  lock_time;	/* Time of last lock in jiffies	   */
+} drm_lock_data_t;
+
+typedef struct drm_device_dma {
+				/* Performance Counters */
+	atomic_t	  total_prio;	/* Total DRM_DMA_PRIORITY	   */
+	atomic_t	  total_bytes;	/* Total bytes DMA'd		   */
+	atomic_t	  total_dmas;	/* Total DMA buffers dispatched	   */
+	
+	atomic_t	  total_missed_dma;  /* Missed drm_do_dma	    */
+	atomic_t	  total_missed_lock; /* Missed lock in drm_do_dma   */
+	atomic_t	  total_missed_free; /* Missed drm_free_this_buffer */
+	atomic_t	  total_missed_sched;/* Missed drm_dma_schedule	    */
+
+	atomic_t	  total_tried;	/* Tried next_buffer		    */
+	atomic_t	  total_hit;	/* Sent next_buffer		    */
+	atomic_t	  total_lost;	/* Lost interrupt		    */
+
+	drm_buf_entry_t	  bufs[DRM_MAX_ORDER+1];
+	int		  buf_count;
+	drm_buf_t	  **buflist;	/* Vector of pointers info bufs	   */
+	int		  seg_count; 
+	int		  page_count;
+	unsigned long	  *pagelist;
+	unsigned long	  byte_count;
+	enum {
+	   _DRM_DMA_USE_AGP = 0x01
+	} flags;
+
+				/* DMA support */
+	drm_buf_t	  *this_buffer;	/* Buffer being sent		   */
+	drm_buf_t	  *next_buffer; /* Selected buffer to send	   */
+	drm_queue_t	  *next_queue;	/* Queue from which buffer selected*/
+	wait_queue_head_t waiting;	/* Processes waiting on free bufs  */
+} drm_device_dma_t;
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+typedef struct drm_agp_mem {
+	unsigned long      handle;
+	agp_memory         *memory;
+	unsigned long      bound; /* address */
+	int                pages;
+	struct drm_agp_mem *prev;
+	struct drm_agp_mem *next;
+} drm_agp_mem_t;
+
+typedef struct drm_agp_head {
+	agp_kern_info      agp_info;
+	const char         *chipset;
+	drm_agp_mem_t      *memory;
+	unsigned long      mode;
+	int                enabled;
+	int                acquired;
+	unsigned long      base;
+   	int 		   agp_mtrr;
+} drm_agp_head_t;
+
+typedef struct {
+	void       (*free_memory)(agp_memory *);
+	agp_memory *(*allocate_memory)(size_t, u32);
+	int        (*bind_memory)(agp_memory *, off_t);
+	int        (*unbind_memory)(agp_memory *);
+	void       (*enable)(u32);
+	int        (*acquire)(void);
+	void       (*release)(void);
+	void       (*copy_info)(agp_kern_info *);
+} drm_agp_func_t;
+
+extern drm_agp_func_t drm_agp;
+#endif
+
+typedef struct drm_device {
+	const char	  *name;	/* Simple driver name		   */
+	char		  *unique;	/* Unique identifier: e.g., busid  */
+	int		  unique_len;	/* Length of unique field	   */
+	dev_t		  device;	/* Device number for mknod	   */
+	char		  *devname;	/* For /proc/interrupts		   */
+	
+	int		  blocked;	/* Blocked due to VC switch?	   */
+	struct proc_dir_entry *root;	/* Root for this device's entries  */
+
+				/* Locks */
+	spinlock_t	  count_lock;	/* For inuse, open_count, buf_use  */
+	struct semaphore  struct_sem;	/* For others			   */
+
+				/* Usage Counters */
+	int		  open_count;	/* Outstanding files open	   */
+	atomic_t	  ioctl_count;	/* Outstanding IOCTLs pending	   */
+	atomic_t	  vma_count;	/* Outstanding vma areas open	   */
+	int		  buf_use;	/* Buffers in use -- cannot alloc  */
+	atomic_t	  buf_alloc;	/* Buffer allocation in progress   */
+
+				/* Performance Counters */
+	atomic_t	  total_open;
+	atomic_t	  total_close;
+	atomic_t	  total_ioctl;
+	atomic_t	  total_irq;	/* Total interruptions		   */
+	atomic_t	  total_ctx;	/* Total context switches	   */
+	
+	atomic_t	  total_locks;
+	atomic_t	  total_unlocks;
+	atomic_t	  total_contends;
+	atomic_t	  total_sleeps;
+
+				/* Authentication */
+	drm_file_t	  *file_first;
+	drm_file_t	  *file_last;
+	drm_magic_head_t  magiclist[DRM_HASH_SIZE];
+
+				/* Memory management */
+	drm_map_t	  **maplist;	/* Vector of pointers to regions   */
+	int		  map_count;	/* Number of mappable regions	   */
+
+	drm_vma_entry_t	  *vmalist;	/* List of vmas (for debugging)	   */
+	drm_lock_data_t	  lock;		/* Information on hardware lock	   */
+
+				/* DMA queues (contexts) */
+	int		  queue_count;	/* Number of active DMA queues	   */
+	int		  queue_reserved; /* Number of reserved DMA queues */
+	int		  queue_slots;	/* Actual length of queuelist	   */
+	drm_queue_t	  **queuelist;	/* Vector of pointers to DMA queues */
+	drm_device_dma_t  *dma;		/* Optional pointer for DMA support */
+
+				/* Context support */
+	int		  irq;		/* Interrupt used by board	   */
+	__volatile__ long context_flag;	/* Context swapping flag	   */
+	__volatile__ long interrupt_flag; /* Interruption handler flag	   */
+	__volatile__ long dma_flag;	/* DMA dispatch flag		   */
+	struct timer_list timer;	/* Timer for delaying ctx switch   */
+	wait_queue_head_t context_wait; /* Processes waiting on ctx switch */
+	int		  last_checked;	/* Last context checked for DMA	   */
+	int		  last_context;	/* Last current context		   */
+	unsigned long	  last_switch;	/* jiffies at last context switch  */
+	struct tq_struct  tq;
+	cycles_t	  ctx_start;
+	cycles_t	  lck_start;
+#if DRM_DMA_HISTOGRAM
+	drm_histogram_t	  histo;
+#endif
+	
+				/* Callback to X server for context switch
+				   and for heavy-handed reset. */
+	char		  buf[DRM_BSZ]; /* Output buffer		   */
+	char		  *buf_rp;	/* Read pointer			   */
+	char		  *buf_wp;	/* Write pointer		   */
+	char		  *buf_end;	/* End pointer			   */
+	struct fasync_struct *buf_async;/* Processes waiting for SIGIO	   */
+	wait_queue_head_t buf_readers;	/* Processes waiting to read	   */
+	wait_queue_head_t buf_writers;	/* Processes waiting to ctx switch */
+	
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	drm_agp_head_t    *agp;
+#endif
+	unsigned long     *ctx_bitmap;
+	void		  *dev_private;
+} drm_device_t;
+
+
+				/* Internal function definitions */
+
+				/* Misc. support (init.c) */
+extern int	     drm_flags;
+extern void	     drm_parse_options(char *s);
+extern int           drm_cpu_valid(void);
+
+
+				/* Device support (fops.c) */
+extern int	     drm_open_helper(struct inode *inode, struct file *filp,
+				     drm_device_t *dev);
+extern int	     drm_flush(struct file *filp);
+extern int	     drm_release(struct inode *inode, struct file *filp);
+extern int	     drm_fasync(int fd, struct file *filp, int on);
+extern ssize_t	     drm_read(struct file *filp, char *buf, size_t count,
+			      loff_t *off);
+extern int	     drm_write_string(drm_device_t *dev, const char *s);
+extern unsigned int  drm_poll(struct file *filp, struct poll_table_struct *wait);
+
+				/* Mapping support (vm.c) */
+#if LINUX_VERSION_CODE < 0x020317
+extern unsigned long drm_vm_nopage(struct vm_area_struct *vma,
+				   unsigned long address,
+				   int write_access);
+extern unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
+				       unsigned long address,
+				       int write_access);
+extern unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
+				       unsigned long address,
+				       int write_access);
+#else
+				/* Return type changed in 2.3.23 */
+extern struct page *drm_vm_nopage(struct vm_area_struct *vma,
+				  unsigned long address,
+				  int write_access);
+extern struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
+				      unsigned long address,
+				      int write_access);
+extern struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
+				      unsigned long address,
+				      int write_access);
+#endif
+extern void	     drm_vm_open(struct vm_area_struct *vma);
+extern void	     drm_vm_close(struct vm_area_struct *vma);
+extern int	     drm_mmap_dma(struct file *filp,
+				  struct vm_area_struct *vma);
+extern int	     drm_mmap(struct file *filp, struct vm_area_struct *vma);
+extern struct vm_operations_struct drm_vm_ops;
+extern struct vm_operations_struct drm_vm_shm_ops;
+extern struct vm_operations_struct drm_vm_dma_ops;
+
+				/* Proc support (proc.c) */
+extern int	     drm_proc_init(drm_device_t *dev);
+extern int	     drm_proc_cleanup(void);
+
+				/* Memory management support (memory.c) */
+extern void	     drm_mem_init(void);
+extern int	     drm_mem_info(char *buf, char **start, off_t offset,
+				  int len, int *eof, void *data);
+extern void	     *drm_alloc(size_t size, int area);
+extern void	     *drm_realloc(void *oldpt, size_t oldsize, size_t size,
+				  int area);
+extern char	     *drm_strdup(const char *s, int area);
+extern void	     drm_strfree(const char *s, int area);
+extern void	     drm_free(void *pt, size_t size, int area);
+extern unsigned long drm_alloc_pages(int order, int area);
+extern void	     drm_free_pages(unsigned long address, int order,
+				    int area);
+extern void	     *drm_ioremap(unsigned long offset, unsigned long size);
+extern void	     drm_ioremapfree(void *pt, unsigned long size);
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+extern agp_memory    *drm_alloc_agp(int pages, u32 type);
+extern int           drm_free_agp(agp_memory *handle, int pages);
+extern int           drm_bind_agp(agp_memory *handle, unsigned int start);
+extern int           drm_unbind_agp(agp_memory *handle);
+#endif
+
+
+				/* Buffer management support (bufs.c) */
+extern int	     drm_order(unsigned long size);
+extern int	     drm_addmap(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_addbufs(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+extern int	     drm_infobufs(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_markbufs(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_freebufs(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_mapbufs(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+
+
+				/* Buffer list management support (lists.c) */
+extern int	     drm_waitlist_create(drm_waitlist_t *bl, int count);
+extern int	     drm_waitlist_destroy(drm_waitlist_t *bl);
+extern int	     drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf);
+extern drm_buf_t     *drm_waitlist_get(drm_waitlist_t *bl);
+
+extern int	     drm_freelist_create(drm_freelist_t *bl, int count);
+extern int	     drm_freelist_destroy(drm_freelist_t *bl);
+extern int	     drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl,
+				      drm_buf_t *buf);
+extern drm_buf_t     *drm_freelist_get(drm_freelist_t *bl, int block);
+
+				/* DMA support (gen_dma.c) */
+extern void	     drm_dma_setup(drm_device_t *dev);
+extern void	     drm_dma_takedown(drm_device_t *dev);
+extern void	     drm_free_buffer(drm_device_t *dev, drm_buf_t *buf);
+extern void	     drm_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int	     drm_context_switch(drm_device_t *dev, int old, int new);
+extern int	     drm_context_switch_complete(drm_device_t *dev, int new);
+extern void	     drm_clear_next_buffer(drm_device_t *dev);
+extern int	     drm_select_queue(drm_device_t *dev,
+				      void (*wrapper)(unsigned long));
+extern int	     drm_dma_enqueue(drm_device_t *dev, drm_dma_t *dma);
+extern int	     drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma);
+#if DRM_DMA_HISTOGRAM
+extern int	     drm_histogram_slot(unsigned long count);
+extern void	     drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf);
+#endif
+
+
+				/* Misc. IOCTL support (ioctl.c) */
+extern int	     drm_irq_busid(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int	     drm_getunique(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int	     drm_setunique(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+
+
+				/* Context IOCTL support (context.c) */
+extern int	     drm_resctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_addctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_modctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_getctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_switchctx(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int	     drm_newctx(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_rmctx(struct inode *inode, struct file *filp,
+			       unsigned int cmd, unsigned long arg);
+
+
+				/* Drawable IOCTL support (drawable.c) */
+extern int	     drm_adddraw(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+extern int	     drm_rmdraw(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+
+
+				/* Authentication IOCTL support (auth.c) */
+extern int	     drm_add_magic(drm_device_t *dev, drm_file_t *priv,
+				   drm_magic_t magic);
+extern int	     drm_remove_magic(drm_device_t *dev, drm_magic_t magic);
+extern int	     drm_getmagic(struct inode *inode, struct file *filp,
+				  unsigned int cmd, unsigned long arg);
+extern int	     drm_authmagic(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+
+
+				/* Locking IOCTL support (lock.c) */
+extern int	     drm_block(struct inode *inode, struct file *filp,
+			       unsigned int cmd, unsigned long arg);
+extern int	     drm_unblock(struct inode *inode, struct file *filp,
+				 unsigned int cmd, unsigned long arg);
+extern int	     drm_lock_take(__volatile__ unsigned int *lock,
+				   unsigned int context);
+extern int	     drm_lock_transfer(drm_device_t *dev,
+				       __volatile__ unsigned int *lock,
+				       unsigned int context);
+extern int	     drm_lock_free(drm_device_t *dev,
+				   __volatile__ unsigned int *lock,
+				   unsigned int context);
+extern int	     drm_finish(struct inode *inode, struct file *filp,
+				unsigned int cmd, unsigned long arg);
+extern int	     drm_flush_unblock(drm_device_t *dev, int context,
+				       drm_lock_flags_t flags);
+extern int	     drm_flush_block_and_flush(drm_device_t *dev, int context,
+					       drm_lock_flags_t flags);
+
+				/* Context Bitmap support (ctxbitmap.c) */
+extern int	     drm_ctxbitmap_init(drm_device_t *dev);
+extern void	     drm_ctxbitmap_cleanup(drm_device_t *dev);
+extern int	     drm_ctxbitmap_next(drm_device_t *dev);
+extern void	     drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle);
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+				/* AGP/GART support (agpsupport.c) */
+extern drm_agp_head_t *drm_agp_init(void);
+extern void           drm_agp_uninit(void);
+extern int            drm_agp_acquire(struct inode *inode, struct file *filp,
+				      unsigned int cmd, unsigned long arg);
+extern int            drm_agp_release(struct inode *inode, struct file *filp,
+				      unsigned int cmd, unsigned long arg);
+extern int            drm_agp_enable(struct inode *inode, struct file *filp,
+				     unsigned int cmd, unsigned long arg);
+extern int            drm_agp_info(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int            drm_agp_alloc(struct inode *inode, struct file *filp,
+				    unsigned int cmd, unsigned long arg);
+extern int            drm_agp_free(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+extern int            drm_agp_unbind(struct inode *inode, struct file *filp,
+				     unsigned int cmd, unsigned long arg);
+extern int            drm_agp_bind(struct inode *inode, struct file *filp,
+				   unsigned int cmd, unsigned long arg);
+#endif
+#endif
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/drm_syms.c linux.18p8/drivers/char/drm/drm_syms.c
--- linux.vanilla/drivers/char/drm/drm_syms.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/drm_syms.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,149 @@
+#include <linux/config.h>
+#include "drmP.h"
+
+/* Misc. support (init.c) */
+EXPORT_SYMBOL(drm_flags);
+EXPORT_SYMBOL(drm_parse_options);
+EXPORT_SYMBOL(drm_cpu_valid);
+
+/* Device support (fops.c) */
+EXPORT_SYMBOL(drm_open_helper);
+EXPORT_SYMBOL(drm_flush);
+EXPORT_SYMBOL(drm_release);
+EXPORT_SYMBOL(drm_fasync);
+EXPORT_SYMBOL(drm_read);
+EXPORT_SYMBOL(drm_write_string);
+EXPORT_SYMBOL(drm_poll);
+
+/* Mapping support (vm.c) */
+#if LINUX_VERSION_CODE < 0x020317
+EXPORT_SYMBOL(drm_vm_nopage);
+EXPORT_SYMBOL(drm_vm_shm_nopage);
+EXPORT_SYMBOL(drm_vm_dma_nopage);
+#else
+/* Return type changed in 2.3.23 */
+EXPORT_SYMBOL(drm_vm_nopage);
+EXPORT_SYMBOL(drm_vm_shm_nopage);
+EXPORT_SYMBOL(drm_vm_dma_nopage);
+#endif
+
+EXPORT_SYMBOL(drm_vm_open);
+EXPORT_SYMBOL(drm_vm_close);
+EXPORT_SYMBOL(drm_mmap_dma);
+EXPORT_SYMBOL(drm_mmap);
+EXPORT_SYMBOL(drm_vm_ops);
+EXPORT_SYMBOL(drm_vm_shm_ops);
+EXPORT_SYMBOL(drm_vm_dma_ops);
+
+/* Proc support (proc.c) */
+EXPORT_SYMBOL(drm_proc_init);
+EXPORT_SYMBOL(drm_proc_cleanup);
+
+/* Memory management support (memory.c) */
+EXPORT_SYMBOL(drm_mem_init);
+EXPORT_SYMBOL(drm_mem_info);
+EXPORT_SYMBOL(drm_alloc);
+EXPORT_SYMBOL(drm_realloc);
+EXPORT_SYMBOL(drm_strdup);
+EXPORT_SYMBOL(drm_strfree);
+EXPORT_SYMBOL(drm_free);
+EXPORT_SYMBOL(drm_alloc_pages);
+EXPORT_SYMBOL(drm_free_pages);
+EXPORT_SYMBOL(drm_ioremap);
+EXPORT_SYMBOL(drm_ioremapfree);
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+EXPORT_SYMBOL(drm_alloc_agp);
+EXPORT_SYMBOL(drm_free_agp);
+EXPORT_SYMBOL(drm_bind_agp);
+EXPORT_SYMBOL(drm_unbind_agp);
+#endif
+
+/* Buffer management support (bufs.c) */
+EXPORT_SYMBOL(drm_order);
+EXPORT_SYMBOL(drm_addmap);
+EXPORT_SYMBOL(drm_addbufs);
+EXPORT_SYMBOL(drm_infobufs);
+EXPORT_SYMBOL(drm_markbufs);
+EXPORT_SYMBOL(drm_freebufs);
+EXPORT_SYMBOL(drm_mapbufs);
+
+/* Buffer list management support (lists.c) */
+EXPORT_SYMBOL(drm_waitlist_create);
+EXPORT_SYMBOL(drm_waitlist_destroy);
+EXPORT_SYMBOL(drm_waitlist_put);
+EXPORT_SYMBOL(drm_waitlist_get);
+EXPORT_SYMBOL(drm_freelist_create);
+EXPORT_SYMBOL(drm_freelist_destroy);
+EXPORT_SYMBOL(drm_freelist_put);
+EXPORT_SYMBOL(drm_freelist_get);
+
+/* DMA support (gen_dma.c) */
+EXPORT_SYMBOL(drm_dma_setup);
+EXPORT_SYMBOL(drm_dma_takedown);
+EXPORT_SYMBOL(drm_free_buffer);
+EXPORT_SYMBOL(drm_reclaim_buffers);
+EXPORT_SYMBOL(drm_context_switch);
+EXPORT_SYMBOL(drm_context_switch_complete);
+EXPORT_SYMBOL(drm_clear_next_buffer);
+EXPORT_SYMBOL(drm_select_queue);
+EXPORT_SYMBOL(drm_dma_enqueue);
+EXPORT_SYMBOL(drm_dma_get_buffers);
+#if DRM_DMA_HISTOGRAM
+EXPORT_SYMBOL(drm_histogram_slot);
+EXPORT_SYMBOL(drm_histogram_compute);
+#endif
+
+/* Misc. IOCTL support (ioctl.c) */
+EXPORT_SYMBOL(drm_irq_busid);
+EXPORT_SYMBOL(drm_getunique);
+EXPORT_SYMBOL(drm_setunique);
+
+/* Context IOCTL support (context.c) */
+EXPORT_SYMBOL(drm_resctx);
+EXPORT_SYMBOL(drm_addctx);
+EXPORT_SYMBOL(drm_modctx);
+EXPORT_SYMBOL(drm_getctx);
+EXPORT_SYMBOL(drm_switchctx);
+EXPORT_SYMBOL(drm_newctx);
+EXPORT_SYMBOL(drm_rmctx);
+
+/* Drawable IOCTL support (drawable.c) */
+EXPORT_SYMBOL(drm_adddraw);
+EXPORT_SYMBOL(drm_rmdraw);
+
+/* Authentication IOCTL support (auth.c) */
+EXPORT_SYMBOL(drm_add_magic);
+EXPORT_SYMBOL(drm_remove_magic);
+EXPORT_SYMBOL(drm_getmagic);
+EXPORT_SYMBOL(drm_authmagic);
+
+/* Locking IOCTL support (lock.c) */
+EXPORT_SYMBOL(drm_block);
+EXPORT_SYMBOL(drm_unblock);
+EXPORT_SYMBOL(drm_lock_take);
+EXPORT_SYMBOL(drm_lock_transfer);
+EXPORT_SYMBOL(drm_lock_free);
+EXPORT_SYMBOL(drm_finish);
+EXPORT_SYMBOL(drm_flush_unblock);
+EXPORT_SYMBOL(drm_flush_block_and_flush);
+
+/* Context Bitmap support (ctxbitmap.c) */
+EXPORT_SYMBOL(drm_ctxbitmap_init);
+EXPORT_SYMBOL(drm_ctxbitmap_cleanup);
+EXPORT_SYMBOL(drm_ctxbitmap_next);
+EXPORT_SYMBOL(drm_ctxbitmap_free);
+
+/* AGP/GART support (agpsupport.c) */
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+EXPORT_SYMBOL(drm_agp);
+EXPORT_SYMBOL(drm_agp_init);
+EXPORT_SYMBOL(drm_agp_uninit);
+EXPORT_SYMBOL(drm_agp_acquire);
+EXPORT_SYMBOL(drm_agp_release);
+EXPORT_SYMBOL(drm_agp_enable);
+EXPORT_SYMBOL(drm_agp_info);
+EXPORT_SYMBOL(drm_agp_alloc);
+EXPORT_SYMBOL(drm_agp_free);
+EXPORT_SYMBOL(drm_agp_unbind);
+EXPORT_SYMBOL(drm_agp_bind);
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/ffb_context.c linux.18p8/drivers/char/drm/ffb_context.c
--- linux.vanilla/drivers/char/drm/ffb_context.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/ffb_context.c	Sun Sep 10 14:49:10 2000
@@ -0,0 +1,531 @@
+/* $Id: ffb_context.c,v 1.4.2.1 2000/09/05 00:10:45 davem Exp $
+ * ffb_context.c: Creator/Creator3D DRI/DRM context switching.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ *
+ * Almost entirely stolen from tdfx_context.c, see there
+ * for authors.
+ */
+
+#define __NO_VERSION__
+#include <linux/sched.h>
+#include <asm/upa.h>
+
+#include "drmP.h"
+
+#include "ffb_drv.h"
+
+static int ffb_alloc_queue(drm_device_t *dev, int is_2d_only)
+{
+	ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+	int i;
+
+	for (i = 0; i < FFB_MAX_CTXS; i++) {
+		if (fpriv->hw_state[i] == NULL)
+			break;
+	}
+	if (i == FFB_MAX_CTXS)
+		return -1;
+
+	fpriv->hw_state[i] = kmalloc(sizeof(struct ffb_hw_context), GFP_KERNEL);
+	if (fpriv->hw_state[i] == NULL)
+		return -1;
+
+	fpriv->hw_state[i]->is_2d_only = is_2d_only;
+
+	/* Plus one because 0 is the special DRM_KERNEL_CONTEXT. */
+	return i + 1;
+}
+
+static void ffb_save_context(ffb_dev_priv_t *fpriv, int idx)
+{
+	ffb_fbcPtr ffb = fpriv->regs;
+	struct ffb_hw_context *ctx;
+	int i;
+
+	ctx = fpriv->hw_state[idx - 1];
+	if (idx == 0 || ctx == NULL)
+		return;
+
+	if (ctx->is_2d_only) {
+		/* 2D applications only care about certain pieces
+		 * of state.
+		 */
+		ctx->drawop = upa_readl(&ffb->drawop);
+		ctx->ppc = upa_readl(&ffb->ppc);
+		ctx->wid = upa_readl(&ffb->wid);
+		ctx->fg = upa_readl(&ffb->fg);
+		ctx->bg = upa_readl(&ffb->bg);
+		ctx->xclip = upa_readl(&ffb->xclip);
+		ctx->fbc = upa_readl(&ffb->fbc);
+		ctx->rop = upa_readl(&ffb->rop);
+		ctx->cmp = upa_readl(&ffb->cmp);
+		ctx->matchab = upa_readl(&ffb->matchab);
+		ctx->magnab = upa_readl(&ffb->magnab);
+		ctx->pmask = upa_readl(&ffb->pmask);
+		ctx->xpmask = upa_readl(&ffb->xpmask);
+		ctx->lpat = upa_readl(&ffb->lpat);
+		ctx->fontxy = upa_readl(&ffb->fontxy);
+		ctx->fontw = upa_readl(&ffb->fontw);
+		ctx->fontinc = upa_readl(&ffb->fontinc);
+
+		/* stencil/stencilctl only exists on FFB2+ and later
+		 * due to the introduction of 3DRAM-III.
+		 */
+		if (fpriv->ffb_type == ffb2_vertical_plus ||
+		    fpriv->ffb_type == ffb2_horizontal_plus) {
+			ctx->stencil = upa_readl(&ffb->stencil);
+			ctx->stencilctl = upa_readl(&ffb->stencilctl);
+		}
+
+		for (i = 0; i < 32; i++)
+			ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]);
+		ctx->ucsr = upa_readl(&ffb->ucsr);
+		return;
+	}
+
+	/* Fetch drawop. */
+	ctx->drawop = upa_readl(&ffb->drawop);
+
+	/* If we were saving the vertex registers, this is where
+	 * we would do it.  We would save 32 32-bit words starting
+	 * at ffb->suvtx.
+	 */
+
+	/* Capture rendering attributes. */
+
+	ctx->ppc = upa_readl(&ffb->ppc);		/* Pixel Processor Control */
+	ctx->wid = upa_readl(&ffb->wid);		/* Current WID */
+	ctx->fg = upa_readl(&ffb->fg);			/* Constant FG color */
+	ctx->bg = upa_readl(&ffb->bg);			/* Constant BG color */
+	ctx->consty = upa_readl(&ffb->consty);		/* Constant Y */
+	ctx->constz = upa_readl(&ffb->constz);		/* Constant Z */
+	ctx->xclip = upa_readl(&ffb->xclip);		/* X plane clip */
+	ctx->dcss = upa_readl(&ffb->dcss);		/* Depth Cue Scale Slope */
+	ctx->vclipmin = upa_readl(&ffb->vclipmin);	/* Primary XY clip, minimum */
+	ctx->vclipmax = upa_readl(&ffb->vclipmax);	/* Primary XY clip, maximum */
+	ctx->vclipzmin = upa_readl(&ffb->vclipzmin);	/* Primary Z clip, minimum */
+	ctx->vclipzmax = upa_readl(&ffb->vclipzmax);	/* Primary Z clip, maximum */
+	ctx->dcsf = upa_readl(&ffb->dcsf);		/* Depth Cue Scale Front Bound */
+	ctx->dcsb = upa_readl(&ffb->dcsb);		/* Depth Cue Scale Back Bound */
+	ctx->dczf = upa_readl(&ffb->dczf);		/* Depth Cue Scale Z Front */
+	ctx->dczb = upa_readl(&ffb->dczb);		/* Depth Cue Scale Z Back */
+	ctx->blendc = upa_readl(&ffb->blendc);		/* Alpha Blend Control */
+	ctx->blendc1 = upa_readl(&ffb->blendc1);	/* Alpha Blend Color 1 */
+	ctx->blendc2 = upa_readl(&ffb->blendc2);	/* Alpha Blend Color 2 */
+	ctx->fbc = upa_readl(&ffb->fbc);		/* Frame Buffer Control */
+	ctx->rop = upa_readl(&ffb->rop);		/* Raster Operation */
+	ctx->cmp = upa_readl(&ffb->cmp);		/* Compare Controls */
+	ctx->matchab = upa_readl(&ffb->matchab);	/* Buffer A/B Match Ops */
+	ctx->matchc = upa_readl(&ffb->matchc);		/* Buffer C Match Ops */
+	ctx->magnab = upa_readl(&ffb->magnab);		/* Buffer A/B Magnitude Ops */
+	ctx->magnc = upa_readl(&ffb->magnc);		/* Buffer C Magnitude Ops */
+	ctx->pmask = upa_readl(&ffb->pmask);		/* RGB Plane Mask */
+	ctx->xpmask = upa_readl(&ffb->xpmask);		/* X Plane Mask */
+	ctx->ypmask = upa_readl(&ffb->ypmask);		/* Y Plane Mask */
+	ctx->zpmask = upa_readl(&ffb->zpmask);		/* Z Plane Mask */
+
+	/* Auxiliary Clips. */
+	ctx->auxclip0min = upa_readl(&ffb->auxclip[0].min);
+	ctx->auxclip0max = upa_readl(&ffb->auxclip[0].max);
+	ctx->auxclip1min = upa_readl(&ffb->auxclip[1].min);
+	ctx->auxclip1max = upa_readl(&ffb->auxclip[1].max);
+	ctx->auxclip2min = upa_readl(&ffb->auxclip[2].min);
+	ctx->auxclip2max = upa_readl(&ffb->auxclip[2].max);
+	ctx->auxclip3min = upa_readl(&ffb->auxclip[3].min);
+	ctx->auxclip3max = upa_readl(&ffb->auxclip[3].max);
+
+	ctx->lpat = upa_readl(&ffb->lpat);		/* Line Pattern */
+	ctx->fontxy = upa_readl(&ffb->fontxy);		/* XY Font Coordinate */
+	ctx->fontw = upa_readl(&ffb->fontw);		/* Font Width */
+	ctx->fontinc = upa_readl(&ffb->fontinc);	/* Font X/Y Increment */
+
+	/* These registers/features only exist on FFB2 and later chips. */
+	if (fpriv->ffb_type >= ffb2_prototype) {
+		ctx->dcss1 = upa_readl(&ffb->dcss1);	/* Depth Cue Scale Slope 1 */
+		ctx->dcss2 = upa_readl(&ffb->dcss2);	/* Depth Cue Scale Slope 2 */
+		ctx->dcss2 = upa_readl(&ffb->dcss3);	/* Depth Cue Scale Slope 3 */
+		ctx->dcs2  = upa_readl(&ffb->dcs2);	/* Depth Cue Scale 2 */
+		ctx->dcs3  = upa_readl(&ffb->dcs3);	/* Depth Cue Scale 3 */
+		ctx->dcs4  = upa_readl(&ffb->dcs4);	/* Depth Cue Scale 4 */
+		ctx->dcd2  = upa_readl(&ffb->dcd2);	/* Depth Cue Depth 2 */
+		ctx->dcd3  = upa_readl(&ffb->dcd3);	/* Depth Cue Depth 3 */
+		ctx->dcd4  = upa_readl(&ffb->dcd4);	/* Depth Cue Depth 4 */
+
+		/* And stencil/stencilctl only exists on FFB2+ and later
+		 * due to the introduction of 3DRAM-III.
+		 */
+		if (fpriv->ffb_type == ffb2_vertical_plus ||
+		    fpriv->ffb_type == ffb2_horizontal_plus) {
+			ctx->stencil = upa_readl(&ffb->stencil);
+			ctx->stencilctl = upa_readl(&ffb->stencilctl);
+		}
+	}
+
+	/* Save the 32x32 area pattern. */
+	for (i = 0; i < 32; i++)
+		ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]);
+
+	/* Finally, stash away the User Constol/Status Register. */
+	ctx->ucsr = upa_readl(&ffb->ucsr);
+}
+
+static void ffb_restore_context(ffb_dev_priv_t *fpriv, int old, int idx)
+{
+	ffb_fbcPtr ffb = fpriv->regs;
+	struct ffb_hw_context *ctx;
+	int i;
+
+	ctx = fpriv->hw_state[idx - 1];
+	if (idx == 0 || ctx == NULL)
+		return;
+
+	if (ctx->is_2d_only) {
+		/* 2D applications only care about certain pieces
+		 * of state.
+		 */
+		upa_writel(ctx->drawop, &ffb->drawop);
+
+		/* If we were restoring the vertex registers, this is where
+		 * we would do it.  We would restore 32 32-bit words starting
+		 * at ffb->suvtx.
+		 */
+
+		upa_writel(ctx->ppc, &ffb->ppc);
+		upa_writel(ctx->wid, &ffb->wid);
+		upa_writel(ctx->fg,  &ffb->fg);
+		upa_writel(ctx->bg, &ffb->bg);
+		upa_writel(ctx->xclip, &ffb->xclip);
+		upa_writel(ctx->fbc, &ffb->fbc);
+		upa_writel(ctx->rop, &ffb->rop);
+		upa_writel(ctx->cmp, &ffb->cmp);
+		upa_writel(ctx->matchab, &ffb->matchab);
+		upa_writel(ctx->magnab, &ffb->magnab);
+		upa_writel(ctx->pmask, &ffb->pmask);
+		upa_writel(ctx->xpmask, &ffb->xpmask);
+		upa_writel(ctx->lpat, &ffb->lpat);
+		upa_writel(ctx->fontxy, &ffb->fontxy);
+		upa_writel(ctx->fontw, &ffb->fontw);
+		upa_writel(ctx->fontinc, &ffb->fontinc);
+
+		/* stencil/stencilctl only exists on FFB2+ and later
+		 * due to the introduction of 3DRAM-III.
+		 */
+		if (fpriv->ffb_type == ffb2_vertical_plus ||
+		    fpriv->ffb_type == ffb2_horizontal_plus) {
+			upa_writel(ctx->stencil, &ffb->stencil);
+			upa_writel(ctx->stencilctl, &ffb->stencilctl);
+			upa_writel(0x80000000, &ffb->fbc);
+			upa_writel((ctx->stencilctl | 0x80000),
+				   &ffb->rawstencilctl);
+			upa_writel(ctx->fbc, &ffb->fbc);
+		}
+
+		for (i = 0; i < 32; i++)
+			upa_writel(ctx->area_pattern[i], &ffb->pattern[i]);
+		upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr);
+		return;
+	}
+
+	/* Restore drawop. */
+	upa_writel(ctx->drawop, &ffb->drawop);
+
+	/* If we were restoring the vertex registers, this is where
+	 * we would do it.  We would restore 32 32-bit words starting
+	 * at ffb->suvtx.
+	 */
+
+	/* Restore rendering attributes. */
+
+	upa_writel(ctx->ppc, &ffb->ppc);		/* Pixel Processor Control */
+	upa_writel(ctx->wid, &ffb->wid);		/* Current WID */
+	upa_writel(ctx->fg, &ffb->fg);			/* Constant FG color */
+	upa_writel(ctx->bg, &ffb->bg);			/* Constant BG color */
+	upa_writel(ctx->consty, &ffb->consty);		/* Constant Y */
+	upa_writel(ctx->constz, &ffb->constz);		/* Constant Z */
+	upa_writel(ctx->xclip, &ffb->xclip);		/* X plane clip */
+	upa_writel(ctx->dcss, &ffb->dcss);		/* Depth Cue Scale Slope */
+	upa_writel(ctx->vclipmin, &ffb->vclipmin);	/* Primary XY clip, minimum */
+	upa_writel(ctx->vclipmax, &ffb->vclipmax);	/* Primary XY clip, maximum */
+	upa_writel(ctx->vclipzmin, &ffb->vclipzmin);	/* Primary Z clip, minimum */
+	upa_writel(ctx->vclipzmax, &ffb->vclipzmax);	/* Primary Z clip, maximum */
+	upa_writel(ctx->dcsf, &ffb->dcsf);		/* Depth Cue Scale Front Bound */
+	upa_writel(ctx->dcsb, &ffb->dcsb);		/* Depth Cue Scale Back Bound */
+	upa_writel(ctx->dczf, &ffb->dczf);		/* Depth Cue Scale Z Front */
+	upa_writel(ctx->dczb, &ffb->dczb);		/* Depth Cue Scale Z Back */
+	upa_writel(ctx->blendc, &ffb->blendc);		/* Alpha Blend Control */
+	upa_writel(ctx->blendc1, &ffb->blendc1);	/* Alpha Blend Color 1 */
+	upa_writel(ctx->blendc2, &ffb->blendc2);	/* Alpha Blend Color 2 */
+	upa_writel(ctx->fbc, &ffb->fbc);		/* Frame Buffer Control */
+	upa_writel(ctx->rop, &ffb->rop);		/* Raster Operation */
+	upa_writel(ctx->cmp, &ffb->cmp);		/* Compare Controls */
+	upa_writel(ctx->matchab, &ffb->matchab);	/* Buffer A/B Match Ops */
+	upa_writel(ctx->matchc, &ffb->matchc);		/* Buffer C Match Ops */
+	upa_writel(ctx->magnab, &ffb->magnab);		/* Buffer A/B Magnitude Ops */
+	upa_writel(ctx->magnc, &ffb->magnc);		/* Buffer C Magnitude Ops */
+	upa_writel(ctx->pmask, &ffb->pmask);		/* RGB Plane Mask */
+	upa_writel(ctx->xpmask, &ffb->xpmask);		/* X Plane Mask */
+	upa_writel(ctx->ypmask, &ffb->ypmask);		/* Y Plane Mask */
+	upa_writel(ctx->zpmask, &ffb->zpmask);		/* Z Plane Mask */
+
+	/* Auxiliary Clips. */
+	upa_writel(ctx->auxclip0min, &ffb->auxclip[0].min);
+	upa_writel(ctx->auxclip0max, &ffb->auxclip[0].max);
+	upa_writel(ctx->auxclip1min, &ffb->auxclip[1].min);
+	upa_writel(ctx->auxclip1max, &ffb->auxclip[1].max);
+	upa_writel(ctx->auxclip2min, &ffb->auxclip[2].min);
+	upa_writel(ctx->auxclip2max, &ffb->auxclip[2].max);
+	upa_writel(ctx->auxclip3min, &ffb->auxclip[3].min);
+	upa_writel(ctx->auxclip3max, &ffb->auxclip[3].max);
+
+	upa_writel(ctx->lpat, &ffb->lpat);		/* Line Pattern */
+	upa_writel(ctx->fontxy, &ffb->fontxy);		/* XY Font Coordinate */
+	upa_writel(ctx->fontw, &ffb->fontw);		/* Font Width */
+	upa_writel(ctx->fontinc, &ffb->fontinc);	/* Font X/Y Increment */
+
+	/* These registers/features only exist on FFB2 and later chips. */
+	if (fpriv->ffb_type >= ffb2_prototype) {
+		upa_writel(ctx->dcss1, &ffb->dcss1);	/* Depth Cue Scale Slope 1 */
+		upa_writel(ctx->dcss2, &ffb->dcss2);	/* Depth Cue Scale Slope 2 */
+		upa_writel(ctx->dcss3, &ffb->dcss2);	/* Depth Cue Scale Slope 3 */
+		upa_writel(ctx->dcs2, &ffb->dcs2);	/* Depth Cue Scale 2 */
+		upa_writel(ctx->dcs3, &ffb->dcs3);	/* Depth Cue Scale 3 */
+		upa_writel(ctx->dcs4, &ffb->dcs4);	/* Depth Cue Scale 4 */
+		upa_writel(ctx->dcd2, &ffb->dcd2);	/* Depth Cue Depth 2 */
+		upa_writel(ctx->dcd3, &ffb->dcd3);	/* Depth Cue Depth 3 */
+		upa_writel(ctx->dcd4, &ffb->dcd4);	/* Depth Cue Depth 4 */
+
+		/* And stencil/stencilctl only exists on FFB2+ and later
+		 * due to the introduction of 3DRAM-III.
+		 */
+		if (fpriv->ffb_type == ffb2_vertical_plus ||
+		    fpriv->ffb_type == ffb2_horizontal_plus) {
+			/* Unfortunately, there is a hardware bug on
+			 * the FFB2+ chips which prevents a normal write
+			 * to the stencil control register from working
+			 * as it should.
+			 *
+			 * The state controlled by the FFB stencilctl register
+			 * really gets transferred to the per-buffer instances
+			 * of the stencilctl register in the 3DRAM chips.
+			 *
+			 * The bug is that FFB does not update buffer C correctly,
+			 * so we have to do it by hand for them.
+			 */
+
+			/* This will update buffers A and B. */
+			upa_writel(ctx->stencil, &ffb->stencil);
+			upa_writel(ctx->stencilctl, &ffb->stencilctl);
+
+			/* Force FFB to use buffer C 3dram regs. */
+			upa_writel(0x80000000, &ffb->fbc);
+			upa_writel((ctx->stencilctl | 0x80000),
+				   &ffb->rawstencilctl);
+
+			/* Now restore the correct FBC controls. */
+			upa_writel(ctx->fbc, &ffb->fbc);
+		}
+	}
+
+	/* Restore the 32x32 area pattern. */
+	for (i = 0; i < 32; i++)
+		upa_writel(ctx->area_pattern[i], &ffb->pattern[i]);
+
+	/* Finally, stash away the User Constol/Status Register.
+	 * The only state we really preserve here is the picking
+	 * control.
+	 */
+	upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr);
+}
+
+#define FFB_UCSR_FB_BUSY       0x01000000
+#define FFB_UCSR_RP_BUSY       0x02000000
+#define FFB_UCSR_ALL_BUSY      (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
+
+static void FFBWait(ffb_fbcPtr ffb)
+{
+	int limit = 100000;
+
+	do {
+		u32 regval = upa_readl(&ffb->ucsr);
+
+		if ((regval & FFB_UCSR_ALL_BUSY) == 0)
+			break;
+	} while (--limit);
+}
+
+int ffb_context_switch(drm_device_t *dev, int old, int new)
+{
+	ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+
+        atomic_inc(&dev->total_ctx);
+
+#if DRM_DMA_HISTOGRAM
+        dev->ctx_start = get_cycles();
+#endif
+        
+        DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+        if (new == dev->last_context ||
+	    dev->last_context == 0) {
+		dev->last_context = new;
+                return 0;
+	}
+        
+	FFBWait(fpriv->regs);
+	ffb_save_context(fpriv, old);
+	ffb_restore_context(fpriv, old, new);
+	FFBWait(fpriv->regs);
+        
+	dev->last_context = new;
+
+        return 0;
+}
+
+int ffb_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			copy_to_user_ret(&res.contexts[i],
+					 &i,
+					 sizeof(i),
+					 -EFAULT);
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+	return 0;
+}
+
+
+int ffb_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+	int idx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	idx = ffb_alloc_queue(dev, (ctx.flags & _DRM_CONTEXT_2DONLY));
+	if (idx < 0)
+		return -ENFILE;
+
+	DRM_DEBUG("%d\n", ctx.handle);
+	ctx.handle = idx;
+	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int ffb_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	ffb_dev_priv_t	*fpriv	= (ffb_dev_priv_t *) (dev + 1);
+	struct ffb_hw_context *hwctx;
+	drm_ctx_t ctx;
+	int idx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+
+	idx = ctx.handle;
+	if (idx <= 0 || idx >= FFB_MAX_CTXS)
+		return -EINVAL;
+
+	hwctx = fpriv->hw_state[idx - 1];
+	if (hwctx == NULL)
+		return -EINVAL;
+
+	if ((ctx.flags & _DRM_CONTEXT_2DONLY) == 0)
+		hwctx->is_2d_only = 0;
+	else
+		hwctx->is_2d_only = 1;
+
+	return 0;
+}
+
+int ffb_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	ffb_dev_priv_t	*fpriv	= (ffb_dev_priv_t *) (dev + 1);
+	struct ffb_hw_context *hwctx;
+	drm_ctx_t ctx;
+	int idx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+
+	idx = ctx.handle;
+	if (idx <= 0 || idx >= FFB_MAX_CTXS)
+		return -EINVAL;
+
+	hwctx = fpriv->hw_state[idx - 1];
+	if (hwctx == NULL)
+		return -EINVAL;
+
+	if (hwctx->is_2d_only != 0)
+		ctx.flags = _DRM_CONTEXT_2DONLY;
+	else
+		ctx.flags = 0;
+
+	copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+
+	return 0;
+}
+
+int ffb_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	return ffb_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int ffb_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+
+	return 0;
+}
+
+int ffb_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_t	ctx;
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	ffb_dev_priv_t	*fpriv	= (ffb_dev_priv_t *) (dev + 1);
+	int idx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+
+	idx = ctx.handle - 1;
+	if (idx < 0 || idx >= FFB_MAX_CTXS)
+		return -EINVAL;
+
+	if (fpriv->hw_state[idx] != NULL) {
+		kfree(fpriv->hw_state[idx]);
+		fpriv->hw_state[idx] = NULL;
+	}
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/ffb_drv.c linux.18p8/drivers/char/drm/ffb_drv.c
--- linux.vanilla/drivers/char/drm/ffb_drv.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/ffb_drv.c	Sun Sep 10 14:49:10 2000
@@ -0,0 +1,881 @@
+/* $Id: ffb_drv.c,v 1.6.2.2 2000/09/07 03:51:06 davem Exp $
+ * ffb_drv.c: Creator/Creator3D direct rendering driver.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ */
+
+#include "drmP.h"
+
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <asm/oplib.h>
+#include <asm/upa.h>
+
+#include "ffb_drv.h"
+
+#include <linux/agp_backend.h>
+
+#define FFB_NAME	"ffb"
+#define FFB_DESC	"Creator/Creator3D"
+#define FFB_DATE	"20000517"
+#define FFB_MAJOR	0
+#define FFB_MINOR	0
+#define FFB_PATCHLEVEL	1
+
+/* Forward declarations. */
+int  ffb_init(void);
+void ffb_cleanup(void);
+static int  ffb_version(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+static int  ffb_open(struct inode *inode, struct file *filp);
+static int  ffb_release(struct inode *inode, struct file *filp);
+static int  ffb_ioctl(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+static int  ffb_lock(struct inode *inode, struct file *filp,
+		     unsigned int cmd, unsigned long arg);
+static int  ffb_unlock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+static int ffb_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/* From ffb_context.c */
+extern int ffb_resctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_addctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_modctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_getctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_switchctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_newctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_rmctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_context_switch(drm_device_t *, int, int);
+
+static struct file_operations ffb_fops = {
+#if LINUX_VERSION_CODE >= 0x020322
+				/* This started being used approx. 2.3.34 */
+	owner:		THIS_MODULE,
+#endif
+	open:		ffb_open,
+	flush:		drm_flush,
+	release:	ffb_release,
+	ioctl:		ffb_ioctl,
+	mmap:		ffb_mmap,
+	read:		drm_read,
+	fasync:		drm_fasync,
+	poll:		drm_poll,
+};
+
+/* This is just a template, we make a new copy for each FFB
+ * we discover at init time so that each one gets a unique
+ * misc device minor number.
+ */
+static struct miscdevice ffb_misc = {
+	minor:	MISC_DYNAMIC_MINOR,
+	name:	FFB_NAME,
+	fops:	&ffb_fops,
+};
+
+static drm_ioctl_desc_t ffb_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]    = { ffb_version,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]  = { drm_getmagic,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]  = { drm_irq_busid,	  0, 1 }, /* XXX */
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	     = { drm_block,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]    = { drm_unblock,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]    = { drm_addmap,	  1, 1 },
+	
+	/* The implementation is currently a nop just like on tdfx.
+	 * Later we can do something more clever. -DaveM
+	 */
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]    = { ffb_addctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]     = { ffb_rmctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]    = { ffb_modctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]    = { ffb_getctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { ffb_switchctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]    = { ffb_newctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]    = { ffb_resctx,	  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]   = { drm_adddraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]    = { drm_rmdraw,	  1, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	     = { ffb_lock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]     = { ffb_unlock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]     = { drm_finish,	  1, 0 },
+};
+#define FFB_IOCTL_COUNT DRM_ARRAY_SIZE(ffb_ioctls)
+
+#ifdef MODULE
+static char *ffb = NULL;
+#endif
+
+MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_DESCRIPTION("Sun Creator/Creator3D DRI");
+
+static int ffb_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+	
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+	
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+
+	/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+	
+	/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+	
+	/* Clear map area information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+				drm_ioremapfree(map->handle, map->size);
+				break;
+
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+
+			default:
+				break;
+			};
+
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+	
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+drm_device_t **ffb_dev_table;
+static int ffb_dev_table_size;
+
+static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance)
+{
+	volatile unsigned char *strap_bits;
+	unsigned char val;
+
+#if LINUX_VERSION_CODE < 0x020300
+	strap_bits = (volatile unsigned char *)
+		__va(ffb_priv->card_phys_base + 0x00200000UL);
+#else
+	strap_bits = (volatile unsigned char *)
+		(ffb_priv->card_phys_base + 0x00200000UL);
+#endif
+
+	/* Don't ask, you have to read the value twice for whatever
+	 * reason to get correct contents.
+	 */
+	val = upa_readb(strap_bits);
+	val = upa_readb(strap_bits);
+	switch (val & 0x78) {
+	case (0x0 << 5) | (0x0 << 3):
+		ffb_priv->ffb_type = ffb1_prototype;
+		printk("ffb%d: Detected FFB1 pre-FCS prototype\n", instance);
+		break;
+	case (0x0 << 5) | (0x1 << 3):
+		ffb_priv->ffb_type = ffb1_standard;
+		printk("ffb%d: Detected FFB1\n", instance);
+		break;
+	case (0x0 << 5) | (0x3 << 3):
+		ffb_priv->ffb_type = ffb1_speedsort;
+		printk("ffb%d: Detected FFB1-SpeedSort\n", instance);
+		break;
+	case (0x1 << 5) | (0x0 << 3):
+		ffb_priv->ffb_type = ffb2_prototype;
+		printk("ffb%d: Detected FFB2/vertical pre-FCS prototype\n", instance);
+		break;
+	case (0x1 << 5) | (0x1 << 3):
+		ffb_priv->ffb_type = ffb2_vertical;
+		printk("ffb%d: Detected FFB2/vertical\n", instance);
+		break;
+	case (0x1 << 5) | (0x2 << 3):
+		ffb_priv->ffb_type = ffb2_vertical_plus;
+		printk("ffb%d: Detected FFB2+/vertical\n", instance);
+		break;
+	case (0x2 << 5) | (0x0 << 3):
+		ffb_priv->ffb_type = ffb2_horizontal;
+		printk("ffb%d: Detected FFB2/horizontal\n", instance);
+		break;
+	case (0x2 << 5) | (0x2 << 3):
+		ffb_priv->ffb_type = ffb2_horizontal;
+		printk("ffb%d: Detected FFB2+/horizontal\n", instance);
+		break;
+	default:
+		ffb_priv->ffb_type = ffb2_vertical;
+		printk("ffb%d: Unknown boardID[%08x], assuming FFB2\n", instance, val);
+		break;
+	};
+}
+
+static int ffb_init_one(int prom_node, int instance)
+{
+	struct linux_prom64_registers regs[2*PROMREG_MAX];
+	drm_device_t *dev;
+	ffb_dev_priv_t *ffb_priv;
+	int ret, i;
+
+	dev = kmalloc(sizeof(drm_device_t) + sizeof(ffb_dev_priv_t), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	memset(dev, 0, sizeof(*dev));
+	spin_lock_init(&dev->count_lock);
+	sema_init(&dev->struct_sem, 1);
+
+	ffb_priv = (ffb_dev_priv_t *) (dev + 1);
+	ffb_priv->prom_node = prom_node;
+	if (prom_getproperty(ffb_priv->prom_node, "reg",
+			     (void *)regs, sizeof(regs)) <= 0) {
+		kfree(dev);
+		return -EINVAL;
+	}
+	ffb_priv->card_phys_base = regs[0].phys_addr;
+#if LINUX_VERSION_CODE < 0x020300
+	ffb_priv->regs = (ffb_fbcPtr)
+		__va(regs[0].phys_addr + 0x00600000UL);
+#else
+	ffb_priv->regs = (ffb_fbcPtr)
+		(regs[0].phys_addr + 0x00600000UL);
+#endif
+	get_ffb_type(ffb_priv, instance);
+	for (i = 0; i < FFB_MAX_CTXS; i++)
+		ffb_priv->hw_state[i] = NULL;
+
+	ffb_dev_table[instance] = dev;
+
+#ifdef MODULE
+	drm_parse_options(ffb);
+#endif
+
+	memcpy(&ffb_priv->miscdev, &ffb_misc, sizeof(ffb_misc));
+	ret = misc_register(&ffb_priv->miscdev);
+	if (ret) {
+		ffb_dev_table[instance] = NULL;
+		kfree(dev);
+		return ret;
+	}
+
+	dev->device = MKDEV(MISC_MAJOR, ffb_priv->miscdev.minor);
+	dev->name = FFB_NAME;
+
+	drm_mem_init();
+	drm_proc_init(dev);
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d at %016lx\n",
+		 FFB_NAME,
+		 FFB_MAJOR,
+		 FFB_MINOR,
+		 FFB_PATCHLEVEL,
+		 FFB_DATE,
+		 ffb_priv->miscdev.minor,
+		 ffb_priv->card_phys_base);
+	
+	return 0;
+}
+
+static int ffb_init_dev_table(void)
+{
+	int root, node;
+	int total = 0;
+
+	root = prom_getchild(prom_root_node);
+	for (node = prom_searchsiblings(root, "SUNW,ffb"); node;
+	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
+		total++;
+
+	ffb_dev_table = kmalloc(sizeof(drm_device_t *) * total, GFP_KERNEL);
+	if (!ffb_dev_table)
+		return -ENOMEM;
+
+	ffb_dev_table_size = total;
+
+	return 0;
+}
+
+int ffb_init(void)
+{
+	int root, node, instance, ret;
+
+	ret = ffb_init_dev_table();
+	if (ret)
+		return ret;
+
+	instance = 0;
+	root = prom_getchild(prom_root_node);
+	for (node = prom_searchsiblings(root, "SUNW,ffb"); node;
+	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) {
+		ret = ffb_init_one(node, instance);
+		if (ret)
+			return ret;
+		instance++;
+	}
+
+	return 0;
+}
+
+void ffb_cleanup(void)
+{
+	int instance;
+
+	DRM_DEBUG("\n");
+	
+	drm_proc_cleanup();
+	for (instance = 0; instance < ffb_dev_table_size; instance++) {
+		drm_device_t *dev = ffb_dev_table[instance];
+		ffb_dev_priv_t *ffb_priv;
+
+		if (!dev)
+			continue;
+
+		ffb_priv = (ffb_dev_priv_t *) (dev + 1);
+		if (misc_deregister(&ffb_priv->miscdev)) {
+			DRM_ERROR("Cannot unload module\n");
+		} else {
+			DRM_INFO("Module unloaded\n");
+		}
+		ffb_takedown(dev);
+		kfree(dev);
+		ffb_dev_table[instance] = NULL;
+	}
+	kfree(ffb_dev_table);
+	ffb_dev_table = NULL;
+	ffb_dev_table_size = 0;
+}
+
+static int ffb_version(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	drm_version_t version;
+	int len, ret;
+
+	ret = copy_from_user(&version, (drm_version_t *)arg, sizeof(version));
+	if (ret)
+		return -EFAULT;
+
+	version.version_major		= FFB_MAJOR;
+	version.version_minor		= FFB_MINOR;
+	version.version_patchlevel	= FFB_PATCHLEVEL;
+
+	len = strlen(FFB_NAME);
+	if (len > version.name_len)
+		len = version.name_len;
+	version.name_len = len;
+	if (len && version.name) {
+		ret = copy_to_user(version.name, FFB_NAME, len);
+		if (ret)
+			return -EFAULT;
+	}
+
+	len = strlen(FFB_DATE);
+	if (len > version.date_len)
+		len = version.date_len;
+	version.date_len = len;
+	if (len && version.date) {
+		ret = copy_to_user(version.date, FFB_DATE, len);
+		if (ret)
+			return -EFAULT;
+	}
+
+	len = strlen(FFB_DESC);
+	if (len > version.desc_len)
+		len = version.desc_len;
+	version.desc_len = len;
+	if (len && version.desc) {
+		ret = copy_to_user(version.desc, FFB_DESC, len);
+		if (ret)
+			return -EFAULT;
+	}
+
+	ret = copy_to_user((drm_version_t *) arg, &version, sizeof(version));
+	if (ret)
+		ret = -EFAULT;
+
+	return ret;
+}
+
+static int ffb_setup(drm_device_t *dev)
+{
+	int i;
+
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma            = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+	
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+
+	return 0;
+}
+
+static int ffb_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t *dev;
+	int minor, i;
+	int ret = 0;
+
+	minor = MINOR(inode->i_rdev);
+	for (i = 0; i < ffb_dev_table_size; i++) {
+		ffb_dev_priv_t *ffb_priv;
+
+		ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1);
+
+		if (ffb_priv->miscdev.minor == minor)
+			break;
+	}
+
+	if (i >= ffb_dev_table_size)
+		return -EINVAL;
+
+	dev = ffb_dev_table[i];
+	if (!dev)
+		return -EINVAL;
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	ret = drm_open_helper(inode, filp, dev);
+	if (!ret) {
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return ffb_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+
+	return ret;
+}
+
+static int ffb_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev;
+	int ret = 0;
+
+	lock_kernel();
+	dev = priv->dev;
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (dev->lock.hw_lock != NULL
+	    && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+	    && dev->lock.pid == current->pid) {
+		ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+		int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock);
+		int idx;
+
+		/* We have to free up the rogue hw context state
+		 * holding error or else we will leak it.
+		 */
+		idx = context - 1;
+		if (fpriv->hw_state[idx] != NULL) {
+			kfree(fpriv->hw_state[idx]);
+			fpriv->hw_state[idx] = NULL;
+		}
+	}
+
+	ret = drm_release(inode, filp);
+
+	if (!ret) {
+		atomic_inc(&dev->total_close);
+		spin_lock(&dev->count_lock);
+		if (!--dev->open_count) {
+			if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+				DRM_ERROR("Device busy: %d %d\n",
+					  atomic_read(&dev->ioctl_count),
+					  dev->blocked);
+				spin_unlock(&dev->count_lock);
+				unlock_kernel();
+				return -EBUSY;
+			}
+			spin_unlock(&dev->count_lock);
+			ret = ffb_takedown(dev);
+			unlock_kernel();
+			return ret;
+		}
+		spin_unlock(&dev->count_lock);
+	}
+
+	unlock_kernel();
+	return ret;
+}
+
+static int ffb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+	int		 ret;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+	
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= FFB_IOCTL_COUNT) {
+		ret = -EINVAL;
+	} else {
+		ioctl	  = &ffb_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			ret = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			ret = -EACCES;
+		} else {
+			ret = (func)(inode, filp, cmd, arg);
+		}
+	}
+	
+	atomic_dec(&dev->ioctl_count);
+
+	return ret;
+}
+
+static int ffb_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+        drm_file_t        *priv	= filp->private_data;
+        drm_device_t      *dev	= priv->dev;
+        DECLARE_WAITQUEUE(entry, current);
+        int               ret	= 0;
+        drm_lock_t        lock;
+
+	ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock));
+	if (ret)
+		return -EFAULT;
+
+        if (lock.context == DRM_KERNEL_CONTEXT) {
+                DRM_ERROR("Process %d using kernel context %d\n",
+                          current->pid, lock.context);
+                return -EINVAL;
+        }
+
+        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+                  lock.context, current->pid, dev->lock.hw_lock->lock,
+                  lock.flags);
+
+	add_wait_queue(&dev->lock.lock_queue, &entry);
+	for (;;) {
+		if (!dev->lock.hw_lock) {
+			/* Device has been unregistered */
+			ret = -EINTR;
+			break;
+		}
+		if (drm_lock_take(&dev->lock.hw_lock->lock,
+				  lock.context)) {
+			dev->lock.pid       = current->pid;
+			dev->lock.lock_time = jiffies;
+			atomic_inc(&dev->total_locks);
+			break;  /* Got lock */
+		}
+                        
+		/* Contention */
+		atomic_inc(&dev->total_sleeps);
+		current->state = TASK_INTERRUPTIBLE;
+		current->policy |= SCHED_YIELD;
+		schedule();
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&dev->lock.lock_queue, &entry);
+
+        if (!ret &&
+	    (dev->last_context != lock.context))
+		ffb_context_switch(dev, dev->last_context, lock.context);
+
+        DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+        return ret;
+}
+
+int ffb_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+	unsigned int old, new, prev, ctx;
+	int ret;
+
+	ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock));
+	if (ret)
+		return -EFAULT;
+	
+	if ((ctx = lock.context) == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+
+	/* We no longer really hold it, but if we are the next
+	 * agent to request it then we should just be able to
+	 * take it immediately and not eat the ioctl.
+	 */
+	dev->lock.pid = 0;
+	{
+		__volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;
+
+		do {
+			old  = *plock;
+			new  = ctx;
+			prev = cmpxchg(plock, old, new);
+		} while (prev != old);
+	}
+
+	wake_up_interruptible(&dev->lock.lock_queue);
+	
+	return 0;
+}
+
+static void align_fb_mapping(struct vm_area_struct *vma)
+{
+	unsigned long j, alignment;
+
+	j = vma->vm_end - vma->vm_start;
+	for (alignment = (4 * 1024 * 1024); alignment > PAGE_SIZE; alignment >>= 3)
+		if (j >= alignment)
+			break;
+	if (alignment > PAGE_SIZE) {
+		j = alignment;
+		alignment = j - (vma->vm_start & (j - 1));
+		if (alignment != j) {
+			struct vm_area_struct *vmm = find_vma(current->mm,vma->vm_start);
+
+			if (!vmm || vmm->vm_start >= vma->vm_end + alignment) {
+				vma->vm_start += alignment;
+				vma->vm_end += alignment;
+			}
+		}
+	}
+}
+
+/* The problem here is, due to virtual cache aliasing,
+ * we must make sure the shared memory area lands in the
+ * same dcache line for both the kernel and all drm clients.
+ */
+static void align_shm_mapping(struct vm_area_struct *vma, unsigned long kvirt)
+{
+	kvirt &= PAGE_SIZE;
+	if ((vma->vm_start & PAGE_SIZE) != kvirt) {
+		struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start);
+
+		if (!vmm || vmm->vm_start >= vma->vm_end + PAGE_SIZE) {
+			vma->vm_start += PAGE_SIZE;
+			vma->vm_end += PAGE_SIZE;
+		}
+	}
+}
+
+extern struct vm_operations_struct drm_vm_ops;
+extern struct vm_operations_struct drm_vm_shm_ops;
+
+static int ffb_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_map_t	*map	= NULL;
+	ffb_dev_priv_t	*ffb_priv;
+	int		i, minor;
+	
+	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+		  vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+
+	lock_kernel();
+	minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+	ffb_priv = NULL;
+	for (i = 0; i < ffb_dev_table_size; i++) {
+		ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1);
+		if (ffb_priv->miscdev.minor == minor)
+			break;
+	}
+	if (i >= ffb_dev_table_size) {
+		unlock_kernel();
+		return -EINVAL;
+	}
+	/* We don't support/need dma mappings, so... */
+	if (!VM_OFFSET(vma)) {
+		unlock_kernel();
+		return -EINVAL;
+	}
+	for (i = 0; i < dev->map_count; i++) {
+		unsigned long off;
+
+		map = dev->maplist[i];
+
+		/* Ok, a little hack to make 32-bit apps work. */
+		off = (map->offset & 0xffffffff);
+		if (off == VM_OFFSET(vma))
+			break;
+	}
+
+	if (i >= dev->map_count) {
+		unlock_kernel();
+		return -EINVAL;
+	}
+	if (!map ||
+	    ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) {
+		unlock_kernel();
+		return -EPERM;
+	}
+	if (map->size != (vma->vm_end - vma->vm_start)) {
+		unlock_kernel();
+		return -EINVAL;
+	}
+	/* Set read-only attribute before mappings are created
+	 * so it works for fb/reg maps too.
+	 */
+	if (map->flags & _DRM_READ_ONLY)
+		vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect(
+			__pte(pgprot_val(vma->vm_page_prot)))));
+
+	switch (map->type) {
+	case _DRM_FRAME_BUFFER:
+		align_fb_mapping(vma);
+		/* FALLTHROUGH */
+
+	case _DRM_REGISTERS:
+		/* In order to handle 32-bit drm apps/xserver we
+		 * play a trick.  The mappings only really specify
+		 * the 32-bit offset from the cards 64-bit base
+		 * address, and we just add in the base here.
+		 */
+		vma->vm_flags |= VM_IO;
+		if (io_remap_page_range(vma->vm_start,
+					ffb_priv->card_phys_base + VM_OFFSET(vma),
+					vma->vm_end - vma->vm_start,
+					vma->vm_page_prot, 0)) {
+			unlock_kernel();
+			return -EAGAIN;
+		}
+		vma->vm_ops = &drm_vm_ops;
+		break;
+	case _DRM_SHM:
+		align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock);
+		vma->vm_ops = &drm_vm_shm_ops;
+
+		/* Don't let this area swap.  Change when
+		 * DRM_KERNEL advisory is supported.
+		 */
+		vma->vm_flags |= VM_LOCKED;
+		break;
+	default:
+		unlock_kernel();
+		return -EINVAL;	/* This should never happen. */
+	};
+	unlock_kernel();
+
+	vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+
+#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
+				/* In Linux 2.2.3 and above, this is
+				   handled in do_mmap() in mm/mmap.c. */
+	++filp->f_count;
+#endif
+	vma->vm_file = filp; /* Needed for drm_vm_open() */
+	drm_vm_open(vma);
+	return 0;
+}
+
+module_init(ffb_init);
+module_exit(ffb_cleanup);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/ffb_drv.h linux.18p8/drivers/char/drm/ffb_drv.h
--- linux.vanilla/drivers/char/drm/ffb_drv.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/ffb_drv.h	Sun Sep 10 14:49:10 2000
@@ -0,0 +1,286 @@
+/* $Id: ffb_drv.h,v 1.1.2.1 2000/09/05 00:10:45 davem Exp $
+ * ffb_drv.h: Creator/Creator3D direct rendering driver.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ */
+
+/* 2.2.x compat items. */
+#ifndef upa_readb
+#define upa_readb(x)		(*(volatile u8 *)(x))
+#define upa_readw(x)		(*(volatile u16 *)(x))
+#define upa_readl(x)		(*(volatile u32 *)(x))
+#define upa_writeb(val,x)	((*(volatile u8 *)(x)) = (val))
+#define upa_writew(val,x)	((*(volatile u16 *)(x)) = (val))
+#define upa_writel(val,x)	((*(volatile u32 *)(x)) = (val))
+#endif /* !defined(upa_readb) */
+
+/* Auxilliary clips. */
+typedef struct  {
+	volatile unsigned int min;
+	volatile unsigned int max;
+} ffb_auxclip, *ffb_auxclipPtr;
+
+/* FFB register set. */
+typedef struct _ffb_fbc {
+	/* Next vertex registers, on the right we list which drawops
+	 * use said register and the logical name the register has in
+	 * that context.
+	 */					/* DESCRIPTION		DRAWOP(NAME)	*/
+/*0x00*/unsigned int		pad1[3];	/* Reserved				*/
+/*0x0c*/volatile unsigned int	alpha;		/* ALPHA Transparency			*/
+/*0x10*/volatile unsigned int	red;		/* RED					*/
+/*0x14*/volatile unsigned int	green;		/* GREEN				*/
+/*0x18*/volatile unsigned int	blue;		/* BLUE					*/
+/*0x1c*/volatile unsigned int	z;		/* DEPTH				*/
+/*0x20*/volatile unsigned int	y;		/* Y			triangle(DOYF)	*/
+						/*                      aadot(DYF)	*/
+						/*                      ddline(DYF)	*/
+						/*                      aaline(DYF)	*/
+/*0x24*/volatile unsigned int	x;		/* X			triangle(DOXF)	*/
+						/*                      aadot(DXF)	*/
+						/*                      ddline(DXF)	*/
+						/*                      aaline(DXF)	*/
+/*0x28*/unsigned int		pad2[2];	/* Reserved				*/
+/*0x30*/volatile unsigned int	ryf;		/* Y (alias to DOYF)	ddline(RYF)	*/
+						/*			aaline(RYF)	*/
+						/*			triangle(RYF)	*/
+/*0x34*/volatile unsigned int	rxf;		/* X			ddline(RXF)	*/
+						/*			aaline(RXF)	*/
+						/*			triangle(RXF)	*/
+/*0x38*/unsigned int		pad3[2];	/* Reserved				*/
+/*0x40*/volatile unsigned int	dmyf;		/* Y (alias to DOYF)	triangle(DMYF)	*/
+/*0x44*/volatile unsigned int	dmxf;		/* X			triangle(DMXF)	*/
+/*0x48*/unsigned int		pad4[2];	/* Reserved				*/
+/*0x50*/volatile unsigned int	ebyi;		/* Y (alias to RYI)	polygon(EBYI)	*/
+/*0x54*/volatile unsigned int	ebxi;		/* X			polygon(EBXI)	*/
+/*0x58*/unsigned int		pad5[2];	/* Reserved				*/
+/*0x60*/volatile unsigned int	by;		/* Y			brline(RYI)	*/
+						/*			fastfill(OP)	*/
+						/*			polygon(YI)	*/
+						/*			rectangle(YI)	*/
+						/*			bcopy(SRCY)	*/
+						/*			vscroll(SRCY)	*/
+/*0x64*/volatile unsigned int	bx;		/* X			brline(RXI)	*/
+						/*			polygon(XI)	*/
+						/*			rectangle(XI)	*/
+						/*			bcopy(SRCX)	*/
+						/*			vscroll(SRCX)	*/
+						/*			fastfill(GO)	*/
+/*0x68*/volatile unsigned int	dy;		/* destination Y	fastfill(DSTY)	*/
+						/*			bcopy(DSRY)	*/
+						/*			vscroll(DSRY)	*/
+/*0x6c*/volatile unsigned int	dx;		/* destination X	fastfill(DSTX)	*/
+						/*			bcopy(DSTX)	*/
+						/*			vscroll(DSTX)	*/
+/*0x70*/volatile unsigned int	bh;		/* Y (alias to RYI)	brline(DYI)	*/
+						/*			dot(DYI)	*/
+						/*			polygon(ETYI)	*/
+						/* Height		fastfill(H)	*/
+						/*			bcopy(H)	*/
+						/*			vscroll(H)	*/
+						/* Y count		fastfill(NY)	*/
+/*0x74*/volatile unsigned int	bw;		/* X			dot(DXI)	*/
+						/*			brline(DXI)	*/
+						/*			polygon(ETXI)	*/
+						/*			fastfill(W)	*/
+						/*			bcopy(W)	*/
+						/*			vscroll(W)	*/
+						/*			fastfill(NX)	*/
+/*0x78*/unsigned int		pad6[2];	/* Reserved				*/
+/*0x80*/unsigned int		pad7[32];	/* Reserved				*/
+	
+	/* Setup Unit's vertex state register */
+/*100*/	volatile unsigned int	suvtx;
+/*104*/	unsigned int		pad8[63];	/* Reserved				*/
+	
+	/* Frame Buffer Control Registers */
+/*200*/	volatile unsigned int	ppc;		/* Pixel Processor Control		*/
+/*204*/	volatile unsigned int	wid;		/* Current WID				*/
+/*208*/	volatile unsigned int	fg;		/* FG data				*/
+/*20c*/	volatile unsigned int	bg;		/* BG data				*/
+/*210*/	volatile unsigned int	consty;		/* Constant Y				*/
+/*214*/	volatile unsigned int	constz;		/* Constant Z				*/
+/*218*/	volatile unsigned int	xclip;		/* X Clip				*/
+/*21c*/	volatile unsigned int	dcss;		/* Depth Cue Scale Slope		*/
+/*220*/	volatile unsigned int	vclipmin;	/* Viewclip XY Min Bounds		*/
+/*224*/	volatile unsigned int	vclipmax;	/* Viewclip XY Max Bounds		*/
+/*228*/	volatile unsigned int	vclipzmin;	/* Viewclip Z Min Bounds		*/
+/*22c*/	volatile unsigned int	vclipzmax;	/* Viewclip Z Max Bounds		*/
+/*230*/	volatile unsigned int	dcsf;		/* Depth Cue Scale Front Bound		*/
+/*234*/	volatile unsigned int	dcsb;		/* Depth Cue Scale Back Bound		*/
+/*238*/	volatile unsigned int	dczf;		/* Depth Cue Z Front			*/
+/*23c*/	volatile unsigned int	dczb;		/* Depth Cue Z Back			*/
+/*240*/	unsigned int		pad9;		/* Reserved				*/
+/*244*/	volatile unsigned int	blendc;		/* Alpha Blend Control			*/
+/*248*/	volatile unsigned int	blendc1;	/* Alpha Blend Color 1			*/
+/*24c*/	volatile unsigned int	blendc2;	/* Alpha Blend Color 2			*/
+/*250*/	volatile unsigned int	fbramitc;	/* FB RAM Interleave Test Control	*/
+/*254*/	volatile unsigned int	fbc;		/* Frame Buffer Control			*/
+/*258*/	volatile unsigned int	rop;		/* Raster OPeration			*/
+/*25c*/	volatile unsigned int	cmp;		/* Frame Buffer Compare			*/
+/*260*/	volatile unsigned int	matchab;	/* Buffer AB Match Mask			*/
+/*264*/	volatile unsigned int	matchc;		/* Buffer C(YZ) Match Mask		*/
+/*268*/	volatile unsigned int	magnab;		/* Buffer AB Magnitude Mask		*/
+/*26c*/	volatile unsigned int	magnc;		/* Buffer C(YZ) Magnitude Mask		*/
+/*270*/	volatile unsigned int	fbcfg0;		/* Frame Buffer Config 0		*/
+/*274*/	volatile unsigned int	fbcfg1;		/* Frame Buffer Config 1		*/
+/*278*/	volatile unsigned int	fbcfg2;		/* Frame Buffer Config 2		*/
+/*27c*/	volatile unsigned int	fbcfg3;		/* Frame Buffer Config 3		*/
+/*280*/	volatile unsigned int	ppcfg;		/* Pixel Processor Config		*/
+/*284*/	volatile unsigned int	pick;		/* Picking Control			*/
+/*288*/	volatile unsigned int	fillmode;	/* FillMode				*/
+/*28c*/	volatile unsigned int	fbramwac;	/* FB RAM Write Address Control		*/
+/*290*/	volatile unsigned int	pmask;		/* RGB PlaneMask			*/
+/*294*/	volatile unsigned int	xpmask;		/* X PlaneMask				*/
+/*298*/	volatile unsigned int	ypmask;		/* Y PlaneMask				*/
+/*29c*/	volatile unsigned int	zpmask;		/* Z PlaneMask				*/
+/*2a0*/	ffb_auxclip		auxclip[4]; 	/* Auxilliary Viewport Clip		*/
+	
+	/* New 3dRAM III support regs */
+/*2c0*/	volatile unsigned int	rawblend2;
+/*2c4*/	volatile unsigned int	rawpreblend;
+/*2c8*/	volatile unsigned int	rawstencil;
+/*2cc*/	volatile unsigned int	rawstencilctl;
+/*2d0*/	volatile unsigned int	threedram1;
+/*2d4*/	volatile unsigned int	threedram2;
+/*2d8*/	volatile unsigned int	passin;
+/*2dc*/	volatile unsigned int	rawclrdepth;
+/*2e0*/	volatile unsigned int	rawpmask;
+/*2e4*/	volatile unsigned int	rawcsrc;
+/*2e8*/	volatile unsigned int	rawmatch;
+/*2ec*/	volatile unsigned int	rawmagn;
+/*2f0*/	volatile unsigned int	rawropblend;
+/*2f4*/	volatile unsigned int	rawcmp;
+/*2f8*/	volatile unsigned int	rawwac;
+/*2fc*/	volatile unsigned int	fbramid;
+	
+/*300*/	volatile unsigned int	drawop;		/* Draw OPeration			*/
+/*304*/	unsigned int		pad10[2];	/* Reserved				*/
+/*30c*/	volatile unsigned int	lpat;		/* Line Pattern control			*/
+/*310*/	unsigned int		pad11;		/* Reserved				*/
+/*314*/	volatile unsigned int	fontxy;		/* XY Font coordinate			*/
+/*318*/	volatile unsigned int	fontw;		/* Font Width				*/
+/*31c*/	volatile unsigned int	fontinc;	/* Font Increment			*/
+/*320*/	volatile unsigned int	font;		/* Font bits				*/
+/*324*/	unsigned int		pad12[3];	/* Reserved				*/
+/*330*/	volatile unsigned int	blend2;
+/*334*/	volatile unsigned int	preblend;
+/*338*/	volatile unsigned int	stencil;
+/*33c*/	volatile unsigned int	stencilctl;
+
+/*340*/	unsigned int		pad13[4];	/* Reserved				*/
+/*350*/	volatile unsigned int	dcss1;		/* Depth Cue Scale Slope 1		*/
+/*354*/	volatile unsigned int	dcss2;		/* Depth Cue Scale Slope 2		*/
+/*358*/	volatile unsigned int	dcss3;		/* Depth Cue Scale Slope 3		*/
+/*35c*/	volatile unsigned int	widpmask;
+/*360*/	volatile unsigned int	dcs2;
+/*364*/	volatile unsigned int	dcs3;
+/*368*/	volatile unsigned int	dcs4;
+/*36c*/	unsigned int		pad14;		/* Reserved				*/
+/*370*/	volatile unsigned int	dcd2;
+/*374*/	volatile unsigned int	dcd3;
+/*378*/	volatile unsigned int	dcd4;
+/*37c*/	unsigned int		pad15;		/* Reserved				*/
+/*380*/	volatile unsigned int	pattern[32];	/* area Pattern				*/
+/*400*/	unsigned int		pad16[8];	/* Reserved				*/
+/*420*/	volatile unsigned int	reset;		/* chip RESET				*/
+/*424*/	unsigned int		pad17[247];	/* Reserved				*/
+/*800*/	volatile unsigned int	devid;		/* Device ID				*/
+/*804*/	unsigned int		pad18[63];	/* Reserved				*/
+/*900*/	volatile unsigned int	ucsr;		/* User Control & Status Register	*/
+/*904*/	unsigned int		pad19[31];	/* Reserved				*/
+/*980*/	volatile unsigned int	mer;		/* Mode Enable Register			*/
+/*984*/	unsigned int		pad20[1439];	/* Reserved				*/
+} ffb_fbc, *ffb_fbcPtr;
+
+struct ffb_hw_context {
+	int is_2d_only;
+
+	unsigned int ppc;
+	unsigned int wid;
+	unsigned int fg;
+	unsigned int bg;
+	unsigned int consty;
+	unsigned int constz;
+	unsigned int xclip;
+	unsigned int dcss;
+	unsigned int vclipmin;
+	unsigned int vclipmax;
+	unsigned int vclipzmin;
+	unsigned int vclipzmax;
+	unsigned int dcsf;
+	unsigned int dcsb;
+	unsigned int dczf;
+	unsigned int dczb;
+	unsigned int blendc;
+	unsigned int blendc1;
+	unsigned int blendc2;
+	unsigned int fbc;
+	unsigned int rop;
+	unsigned int cmp;
+	unsigned int matchab;
+	unsigned int matchc;
+	unsigned int magnab;
+	unsigned int magnc;
+	unsigned int pmask;
+	unsigned int xpmask;
+	unsigned int ypmask;
+	unsigned int zpmask;
+	unsigned int auxclip0min;
+	unsigned int auxclip0max;
+	unsigned int auxclip1min;
+	unsigned int auxclip1max;
+	unsigned int auxclip2min;
+	unsigned int auxclip2max;
+	unsigned int auxclip3min;
+	unsigned int auxclip3max;
+	unsigned int drawop;
+	unsigned int lpat;
+	unsigned int fontxy;
+	unsigned int fontw;
+	unsigned int fontinc;
+	unsigned int area_pattern[32];
+	unsigned int ucsr;
+	unsigned int stencil;
+	unsigned int stencilctl;
+	unsigned int dcss1;
+	unsigned int dcss2;
+	unsigned int dcss3;
+	unsigned int dcs2;
+	unsigned int dcs3;
+	unsigned int dcs4;
+	unsigned int dcd2;
+	unsigned int dcd3;
+	unsigned int dcd4;
+	unsigned int mer;
+};
+
+#define FFB_MAX_CTXS	32
+
+enum ffb_chip_type {
+	ffb1_prototype = 0,	/* Early pre-FCS FFB */
+	ffb1_standard,		/* First FCS FFB, 100Mhz UPA, 66MHz gclk */
+	ffb1_speedsort,		/* Second FCS FFB, 100Mhz UPA, 75MHz gclk */
+	ffb2_prototype,		/* Early pre-FCS vertical FFB2 */
+	ffb2_vertical,		/* First FCS FFB2/vertical, 100Mhz UPA, 100MHZ gclk,
+				   75(SingleBuffer)/83(DoubleBuffer) MHz fclk */
+	ffb2_vertical_plus,	/* Second FCS FFB2/vertical, same timings */
+	ffb2_horizontal,	/* First FCS FFB2/horizontal, same timings as FFB2/vert */
+	ffb2_horizontal_plus,	/* Second FCS FFB2/horizontal, same timings */
+	afb_m3,			/* FCS Elite3D, 3 float chips */
+	afb_m6			/* FCS Elite3D, 6 float chips */
+};
+
+typedef struct ffb_dev_priv {
+	/* Misc software state. */
+	int			prom_node;
+	enum ffb_chip_type	ffb_type;
+	u64			card_phys_base;
+	struct miscdevice 	miscdev;
+
+	/* Controller registers. */
+	ffb_fbcPtr		regs;
+
+	/* Context table. */
+	struct ffb_hw_context	*hw_state[FFB_MAX_CTXS];
+} ffb_dev_priv_t;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/fops.c linux.18p8/drivers/char/drm/fops.c
--- linux.vanilla/drivers/char/drm/fops.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/fops.c	Fri Sep  1 14:35:00 2000
@@ -0,0 +1,238 @@
+/* fops.c -- File operations for DRM -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Daryll Strauss <daryll@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include <linux/poll.h>
+
+/* drm_open is called whenever a process opens /dev/drm. */
+
+int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev)
+{
+	kdev_t	     minor = MINOR(inode->i_rdev);
+	drm_file_t   *priv;
+
+	if (filp->f_flags & O_EXCL)   return -EBUSY; /* No exclusive opens */
+	if (!drm_cpu_valid())         return -EINVAL;
+
+	DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor);
+
+	priv		    = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
+	memset(priv, 0, sizeof(*priv));
+	filp->private_data  = priv;
+	priv->uid	    = current->euid;
+	priv->pid	    = current->pid;
+	priv->minor	    = minor;
+	priv->dev	    = dev;
+	priv->ioctl_count   = 0;
+	priv->authenticated = capable(CAP_SYS_ADMIN);
+
+	down(&dev->struct_sem);
+	if (!dev->file_last) {
+		priv->next	= NULL;
+		priv->prev	= NULL;
+		dev->file_first = priv;
+		dev->file_last	= priv;
+	} else {
+		priv->next	     = NULL;
+		priv->prev	     = dev->file_last;
+		dev->file_last->next = priv;
+		dev->file_last	     = priv;
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+int drm_flush(struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+
+	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+		  current->pid, dev->device, dev->open_count);
+	return 0;
+}
+
+/* drm_release is called whenever a process closes /dev/drm*.  Linux calls
+   this only if any mappings have been closed. */
+
+int drm_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+
+	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+		  current->pid, dev->device, dev->open_count);
+
+	if (dev->lock.hw_lock
+	    && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+	    && dev->lock.pid == current->pid) {
+		DRM_ERROR("Process %d dead, freeing lock for context %d\n",
+			  current->pid,
+			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+		drm_lock_free(dev,
+			      &dev->lock.hw_lock->lock,
+			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+		
+				/* FIXME: may require heavy-handed reset of
+                                   hardware at this point, possibly
+                                   processed via a callback to the X
+                                   server. */
+	}
+	drm_reclaim_buffers(dev, priv->pid);
+
+	drm_fasync(-1, filp, 0);
+
+	down(&dev->struct_sem);
+	if (priv->prev) priv->prev->next = priv->next;
+	else		dev->file_first	 = priv->next;
+	if (priv->next) priv->next->prev = priv->prev;
+	else		dev->file_last	 = priv->prev;
+	up(&dev->struct_sem);
+	
+	drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+	
+	return 0;
+}
+
+int drm_fasync(int fd, struct file *filp, int on)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+	int	      retcode;
+	
+	DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device);
+	retcode = fasync_helper(fd, filp, on, &dev->buf_async);
+	if (retcode < 0) return retcode;
+	return 0;
+}
+
+
+/* The drm_read and drm_write_string code (especially that which manages
+   the circular buffer), is based on Alessandro Rubini's LINUX DEVICE
+   DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */
+
+ssize_t drm_read(struct file *filp, char *buf, size_t count, loff_t *off)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev    = priv->dev;
+	int	      left;
+	int	      avail;
+	int	      send;
+	int	      cur;
+
+	DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp);
+	
+	while (dev->buf_rp == dev->buf_wp) {
+		DRM_DEBUG("  sleeping\n");
+		if (filp->f_flags & O_NONBLOCK) {
+			return -EAGAIN;
+		}
+		interruptible_sleep_on(&dev->buf_readers);
+		if (signal_pending(current)) {
+			DRM_DEBUG("  interrupted\n");
+			return -ERESTARTSYS;
+		}
+		DRM_DEBUG("  awake\n");
+	}
+
+	left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+	avail = DRM_BSZ - left;
+	send  = DRM_MIN(avail, count);
+
+	while (send) {
+		if (dev->buf_wp > dev->buf_rp) {
+			cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp);
+		} else {
+			cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
+		}
+		copy_to_user_ret(buf, dev->buf_rp, cur, -EINVAL);
+		dev->buf_rp += cur;
+		if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
+		send -= cur;
+	}
+	
+	wake_up_interruptible(&dev->buf_writers);
+	return DRM_MIN(avail, count);;
+}
+
+int drm_write_string(drm_device_t *dev, const char *s)
+{
+	int left   = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ;
+	int send   = strlen(s);
+	int count;
+
+	DRM_DEBUG("%d left, %d to send (%p, %p)\n",
+		  left, send, dev->buf_rp, dev->buf_wp);
+	
+	if (left == 1 || dev->buf_wp != dev->buf_rp) {
+		DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n",
+			  left,
+			  dev->buf_wp,
+			  dev->buf_rp);
+	}
+
+	while (send) {
+		if (dev->buf_wp >= dev->buf_rp) {
+			count = DRM_MIN(send, dev->buf_end - dev->buf_wp);
+			if (count == left) --count; /* Leave a hole */
+		} else {
+			count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1);
+		}
+		strncpy(dev->buf_wp, s, count);
+		dev->buf_wp += count;
+		if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf;
+		send -= count;
+	}
+
+#if LINUX_VERSION_CODE < 0x020400
+	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
+#else
+				/* Type of first parameter changed in
+                                   Linux 2.4.0-test2... */
+	if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
+#endif
+	DRM_DEBUG("waking\n");
+	wake_up_interruptible(&dev->buf_readers);
+	return 0;
+}
+
+unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
+{
+	drm_file_t   *priv = filp->private_data;
+	drm_device_t *dev  = priv->dev;
+
+	poll_wait(filp, &dev->buf_readers, wait);
+	if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM;
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/gamma_dma.c linux.18p8/drivers/char/drm/gamma_dma.c
--- linux.vanilla/drivers/char/drm/gamma_dma.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/gamma_dma.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,824 @@
+/* gamma_dma.c -- DMA support for GMX 2000 -*- linux-c -*-
+ * Created: Fri Mar 19 14:30:16 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "gamma_drv.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+
+/* WARNING!!! MAGIC NUMBER!!!  The number of regions already added to the
+   kernel must be specified here.  Currently, the number is 2.	This must
+   match the order the X server uses for instantiating register regions ,
+   or must be passed in a new ioctl. */
+#define GAMMA_REG(reg)						   \
+	(2							   \
+	 + ((reg < 0x1000)					   \
+	    ? 0							   \
+	    : ((reg < 0x10000) ? 1 : ((reg < 0x11000) ? 2 : 3))))
+
+#define GAMMA_OFF(reg)						   \
+	((reg < 0x1000)						   \
+	 ? reg							   \
+	 : ((reg < 0x10000)					   \
+	    ? (reg - 0x1000)					   \
+	    : ((reg < 0x11000)					   \
+	       ? (reg - 0x10000)				   \
+	       : (reg - 0x11000))))
+
+#define GAMMA_BASE(reg)	 ((unsigned long)dev->maplist[GAMMA_REG(reg)]->handle)
+#define GAMMA_ADDR(reg)	 (GAMMA_BASE(reg) + GAMMA_OFF(reg))
+#define GAMMA_DEREF(reg) *(__volatile__ int *)GAMMA_ADDR(reg)
+#define GAMMA_READ(reg)	 GAMMA_DEREF(reg)
+#define GAMMA_WRITE(reg,val) do { GAMMA_DEREF(reg) = val; } while (0)
+
+#define GAMMA_BROADCASTMASK    0x9378
+#define GAMMA_COMMANDINTENABLE 0x0c48
+#define GAMMA_DMAADDRESS       0x0028
+#define GAMMA_DMACOUNT	       0x0030
+#define GAMMA_FILTERMODE       0x8c00
+#define GAMMA_GCOMMANDINTFLAGS 0x0c50
+#define GAMMA_GCOMMANDMODE     0x0c40
+#define GAMMA_GCOMMANDSTATUS   0x0c60
+#define GAMMA_GDELAYTIMER      0x0c38
+#define GAMMA_GDMACONTROL      0x0060
+#define GAMMA_GINTENABLE       0x0808
+#define GAMMA_GINTFLAGS	       0x0810
+#define GAMMA_INFIFOSPACE      0x0018
+#define GAMMA_OUTFIFOWORDS     0x0020
+#define GAMMA_OUTPUTFIFO       0x2000
+#define GAMMA_SYNC	       0x8c40
+#define GAMMA_SYNC_TAG	       0x0188
+
+static inline void gamma_dma_dispatch(drm_device_t *dev, unsigned long address,
+				      unsigned long length)
+{
+	GAMMA_WRITE(GAMMA_DMAADDRESS, virt_to_phys((void *)address));
+	while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4)
+		;
+	GAMMA_WRITE(GAMMA_DMACOUNT, length / 4);
+}
+
+static inline void gamma_dma_quiescent_single(drm_device_t *dev)
+{
+	while (GAMMA_READ(GAMMA_DMACOUNT))
+		;
+	while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
+		;
+
+	GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
+	GAMMA_WRITE(GAMMA_SYNC, 0);
+	
+	do {
+		while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
+			;
+	} while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
+}
+
+static inline void gamma_dma_quiescent_dual(drm_device_t *dev)
+{
+	while (GAMMA_READ(GAMMA_DMACOUNT))
+		;
+	while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3)
+		;
+
+	GAMMA_WRITE(GAMMA_BROADCASTMASK, 3);
+
+	GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10);
+	GAMMA_WRITE(GAMMA_SYNC, 0);
+	
+				/* Read from first MX */
+	do {
+		while (!GAMMA_READ(GAMMA_OUTFIFOWORDS))
+			;
+	} while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG);
+	
+				/* Read from second MX */
+	do {
+		while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000))
+			;
+	} while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG);
+}
+
+static inline void gamma_dma_ready(drm_device_t *dev)
+{
+	while (GAMMA_READ(GAMMA_DMACOUNT))
+		;
+}
+
+static inline int gamma_dma_is_ready(drm_device_t *dev)
+{
+	return !GAMMA_READ(GAMMA_DMACOUNT);
+}
+
+static void gamma_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+	drm_device_t	 *dev = (drm_device_t *)device;
+	drm_device_dma_t *dma = dev->dma;
+	
+	atomic_inc(&dev->total_irq);
+	GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */
+	GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8);
+	GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001);
+	if (gamma_dma_is_ready(dev)) {
+				/* Free previous buffer */
+		if (test_and_set_bit(0, &dev->dma_flag)) {
+			atomic_inc(&dma->total_missed_free);
+			return;
+		}
+		if (dma->this_buffer) {
+			drm_free_buffer(dev, dma->this_buffer);
+			dma->this_buffer = NULL;
+		}
+		clear_bit(0, &dev->dma_flag);
+
+				/* Dispatch new buffer */
+		queue_task(&dev->tq, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+}
+
+/* Only called by gamma_dma_schedule. */
+static int gamma_do_dma(drm_device_t *dev, int locked)
+{
+	unsigned long	 address;
+	unsigned long	 length;
+	drm_buf_t	 *buf;
+	int		 retcode = 0;
+	drm_device_dma_t *dma = dev->dma;
+#if DRM_DMA_HISTOGRAM
+	cycles_t	 dma_start, dma_stop;
+#endif
+
+	if (test_and_set_bit(0, &dev->dma_flag)) {
+		atomic_inc(&dma->total_missed_dma);
+		return -EBUSY;
+	}
+	
+#if DRM_DMA_HISTOGRAM
+	dma_start = get_cycles();
+#endif
+
+	if (!dma->next_buffer) {
+		DRM_ERROR("No next_buffer\n");
+		clear_bit(0, &dev->dma_flag);
+		return -EINVAL;
+	}
+
+	buf	= dma->next_buffer;
+	address = (unsigned long)buf->address;
+	length	= buf->used;
+
+	DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
+		  buf->context, buf->idx, length);
+
+	if (buf->list == DRM_LIST_RECLAIM) {
+		drm_clear_next_buffer(dev);
+		drm_free_buffer(dev, buf);
+		clear_bit(0, &dev->dma_flag);
+		return -EINVAL;
+	}
+
+	if (!length) {
+		DRM_ERROR("0 length buffer\n");
+		drm_clear_next_buffer(dev);
+		drm_free_buffer(dev, buf);
+		clear_bit(0, &dev->dma_flag);
+		return 0;
+	}
+	
+	if (!gamma_dma_is_ready(dev)) {
+		clear_bit(0, &dev->dma_flag);
+		return -EBUSY;
+	}
+
+	if (buf->while_locked) {
+		if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+			DRM_ERROR("Dispatching buffer %d from pid %d"
+				  " \"while locked\", but no lock held\n",
+				  buf->idx, buf->pid);
+		}
+	} else {
+		if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock,
+					      DRM_KERNEL_CONTEXT)) {
+			atomic_inc(&dma->total_missed_lock);
+			clear_bit(0, &dev->dma_flag);
+			return -EBUSY;
+		}
+	}
+
+	if (dev->last_context != buf->context
+	    && !(dev->queuelist[buf->context]->flags
+		 & _DRM_CONTEXT_PRESERVED)) {
+				/* PRE: dev->last_context != buf->context */
+		if (drm_context_switch(dev, dev->last_context, buf->context)) {
+			drm_clear_next_buffer(dev);
+			drm_free_buffer(dev, buf);
+		}
+		retcode = -EBUSY;
+		goto cleanup;
+			
+				/* POST: we will wait for the context
+				   switch and will dispatch on a later call
+				   when dev->last_context == buf->context.
+				   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+				   TIME! */
+	}
+
+	drm_clear_next_buffer(dev);
+	buf->pending	 = 1;
+	buf->waiting	 = 0;
+	buf->list	 = DRM_LIST_PEND;
+#if DRM_DMA_HISTOGRAM
+	buf->time_dispatched = get_cycles();
+#endif
+
+	gamma_dma_dispatch(dev, address, length);
+	drm_free_buffer(dev, dma->this_buffer);
+	dma->this_buffer = buf;
+
+	atomic_add(length, &dma->total_bytes);
+	atomic_inc(&dma->total_dmas);
+
+	if (!buf->while_locked && !dev->context_flag && !locked) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+cleanup:
+
+	clear_bit(0, &dev->dma_flag);
+
+#if DRM_DMA_HISTOGRAM
+	dma_stop = get_cycles();
+	atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]);
+#endif
+
+	return retcode;
+}
+
+static void gamma_dma_schedule_timer_wrapper(unsigned long dev)
+{
+	gamma_dma_schedule((drm_device_t *)dev, 0);
+}
+
+static void gamma_dma_schedule_tq_wrapper(void *dev)
+{
+	gamma_dma_schedule(dev, 0);
+}
+
+int gamma_dma_schedule(drm_device_t *dev, int locked)
+{
+	int		 next;
+	drm_queue_t	 *q;
+	drm_buf_t	 *buf;
+	int		 retcode   = 0;
+	int		 processed = 0;
+	int		 missed;
+	int		 expire	   = 20;
+	drm_device_dma_t *dma	   = dev->dma;
+#if DRM_DMA_HISTOGRAM
+	cycles_t	 schedule_start;
+#endif
+
+	if (test_and_set_bit(0, &dev->interrupt_flag)) {
+				/* Not reentrant */
+		atomic_inc(&dma->total_missed_sched);
+		return -EBUSY;
+	}
+	missed = atomic_read(&dma->total_missed_sched);
+
+#if DRM_DMA_HISTOGRAM
+	schedule_start = get_cycles();
+#endif
+
+again:
+	if (dev->context_flag) {
+		clear_bit(0, &dev->interrupt_flag);
+		return -EBUSY;
+	}
+	if (dma->next_buffer) {
+				/* Unsent buffer that was previously
+				   selected, but that couldn't be sent
+				   because the lock could not be obtained
+				   or the DMA engine wasn't ready.  Try
+				   again. */
+		atomic_inc(&dma->total_tried);
+		if (!(retcode = gamma_do_dma(dev, locked))) {
+			atomic_inc(&dma->total_hit);
+			++processed;
+		}
+	} else {
+		do {
+			next = drm_select_queue(dev,
+					     gamma_dma_schedule_timer_wrapper);
+			if (next >= 0) {
+				q   = dev->queuelist[next];
+				buf = drm_waitlist_get(&q->waitlist);
+				dma->next_buffer = buf;
+				dma->next_queue	 = q;
+				if (buf && buf->list == DRM_LIST_RECLAIM) {
+					drm_clear_next_buffer(dev);
+					drm_free_buffer(dev, buf);
+				}
+			}
+		} while (next >= 0 && !dma->next_buffer);
+		if (dma->next_buffer) {
+			if (!(retcode = gamma_do_dma(dev, locked))) {
+				++processed;
+			}
+		}
+	}
+
+	if (--expire) {
+		if (missed != atomic_read(&dma->total_missed_sched)) {
+			atomic_inc(&dma->total_lost);
+			if (gamma_dma_is_ready(dev)) goto again;
+		}
+		if (processed && gamma_dma_is_ready(dev)) {
+			atomic_inc(&dma->total_lost);
+			processed = 0;
+			goto again;
+		}
+	}
+	
+	clear_bit(0, &dev->interrupt_flag);
+	
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles()
+							   - schedule_start)]);
+#endif
+	return retcode;
+}
+
+static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d)
+{
+	unsigned long	  address;
+	unsigned long	  length;
+	int		  must_free = 0;
+	int		  retcode   = 0;
+	int		  i;
+	int		  idx;
+	drm_buf_t	  *buf;
+	drm_buf_t	  *last_buf = NULL;
+	drm_device_dma_t  *dma	    = dev->dma;
+	DECLARE_WAITQUEUE(entry, current);
+
+				/* Turn off interrupt handling */
+	while (test_and_set_bit(0, &dev->interrupt_flag)) {
+		schedule();
+		if (signal_pending(current)) return -EINTR;
+	}
+	if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
+		while (!drm_lock_take(&dev->lock.hw_lock->lock,
+				      DRM_KERNEL_CONTEXT)) {
+			schedule();
+			if (signal_pending(current)) {
+				clear_bit(0, &dev->interrupt_flag);
+				return -EINTR;
+			}
+		}
+		++must_free;
+	}
+	atomic_inc(&dma->total_prio);
+
+	for (i = 0; i < d->send_count; i++) {
+		idx = d->send_indices[i];
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  d->send_indices[i], dma->buf_count - 1);
+			continue;
+		}
+		buf = dma->buflist[ idx ];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d using buffer owned by %d\n",
+				  current->pid, buf->pid);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+		if (buf->list != DRM_LIST_NONE) {
+			DRM_ERROR("Process %d using %d's buffer on list %d\n",
+				  current->pid, buf->pid, buf->list);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+				/* This isn't a race condition on
+				   buf->list, since our concern is the
+				   buffer reclaim during the time the
+				   process closes the /dev/drm? handle, so
+				   it can't also be doing DMA. */
+		buf->list	  = DRM_LIST_PRIO;
+		buf->used	  = d->send_sizes[i];
+		buf->context	  = d->context;
+		buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
+		address		  = (unsigned long)buf->address;
+		length		  = buf->used;
+		if (!length) {
+			DRM_ERROR("0 length buffer\n");
+		}
+		if (buf->pending) {
+			DRM_ERROR("Sending pending buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+		if (buf->waiting) {
+			DRM_ERROR("Sending waiting buffer:"
+				  " buffer %d, offset %d\n",
+				  d->send_indices[i], i);
+			retcode = -EINVAL;
+			goto cleanup;
+		}
+		buf->pending = 1;
+		
+		if (dev->last_context != buf->context
+		    && !(dev->queuelist[buf->context]->flags
+			 & _DRM_CONTEXT_PRESERVED)) {
+			add_wait_queue(&dev->context_wait, &entry);
+			current->state = TASK_INTERRUPTIBLE;
+				/* PRE: dev->last_context != buf->context */
+			drm_context_switch(dev, dev->last_context,
+					   buf->context);
+				/* POST: we will wait for the context
+				   switch and will dispatch on a later call
+				   when dev->last_context == buf->context.
+				   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+				   TIME! */
+			schedule();
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&dev->context_wait, &entry);
+			if (signal_pending(current)) {
+				retcode = -EINTR;
+				goto cleanup;
+			}
+			if (dev->last_context != buf->context) {
+				DRM_ERROR("Context mismatch: %d %d\n",
+					  dev->last_context,
+					  buf->context);
+			}
+		}
+
+#if DRM_DMA_HISTOGRAM
+		buf->time_queued     = get_cycles();
+		buf->time_dispatched = buf->time_queued;
+#endif
+		gamma_dma_dispatch(dev, address, length);
+		atomic_add(length, &dma->total_bytes);
+		atomic_inc(&dma->total_dmas);
+		
+		if (last_buf) {
+			drm_free_buffer(dev, last_buf);
+		}
+		last_buf = buf;
+	}
+
+
+cleanup:
+	if (last_buf) {
+		gamma_dma_ready(dev);
+		drm_free_buffer(dev, last_buf);
+	}
+	
+	if (must_free && !dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+	clear_bit(0, &dev->interrupt_flag);
+	return retcode;
+}
+
+static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
+{
+	DECLARE_WAITQUEUE(entry, current);
+	drm_buf_t	  *last_buf = NULL;
+	int		  retcode   = 0;
+	drm_device_dma_t  *dma	    = dev->dma;
+
+	if (d->flags & _DRM_DMA_BLOCK) {
+		last_buf = dma->buflist[d->send_indices[d->send_count-1]];
+		add_wait_queue(&last_buf->dma_wait, &entry);
+	}
+	
+	if ((retcode = drm_dma_enqueue(dev, d))) {
+		if (d->flags & _DRM_DMA_BLOCK)
+			remove_wait_queue(&last_buf->dma_wait, &entry);
+		return retcode;
+	}
+	
+	gamma_dma_schedule(dev, 0);
+	
+	if (d->flags & _DRM_DMA_BLOCK) {
+		DRM_DEBUG("%d waiting\n", current->pid);
+		current->state = TASK_INTERRUPTIBLE;
+		for (;;) {
+			if (!last_buf->waiting
+			    && !last_buf->pending)
+				break; /* finished */
+			schedule();
+			if (signal_pending(current)) {
+				retcode = -EINTR; /* Can't restart */
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		DRM_DEBUG("%d running\n", current->pid);
+		remove_wait_queue(&last_buf->dma_wait, &entry);
+		if (!retcode
+		    || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {
+			if (!waitqueue_active(&last_buf->dma_wait)) {
+				drm_free_buffer(dev, last_buf);
+			}
+		}
+		if (retcode) {
+			DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n",
+				  d->context,
+				  last_buf->waiting,
+				  last_buf->pending,
+				  DRM_WAITCOUNT(dev, d->context),
+				  last_buf->idx,
+				  last_buf->list,
+				  last_buf->pid,
+				  current->pid);
+		}
+	}
+	return retcode;
+}
+
+int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	drm_device_dma_t  *dma	    = dev->dma;
+	int		  retcode   = 0;
+	drm_dma_t	  d;
+
+	copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT);
+	DRM_DEBUG("%d %d: %d send, %d req\n",
+		  current->pid, d.context, d.send_count, d.request_count);
+
+	if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) {
+		DRM_ERROR("Process %d using context %d\n",
+			  current->pid, d.context);
+		return -EINVAL;
+	}
+	if (d.send_count < 0 || d.send_count > dma->buf_count) {
+		DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
+			  current->pid, d.send_count, dma->buf_count);
+		return -EINVAL;
+	}
+	if (d.request_count < 0 || d.request_count > dma->buf_count) {
+		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+			  current->pid, d.request_count, dma->buf_count);
+		return -EINVAL;
+	}
+
+	if (d.send_count) {
+		if (d.flags & _DRM_DMA_PRIORITY)
+			retcode = gamma_dma_priority(dev, &d);
+		else 
+			retcode = gamma_dma_send_buffers(dev, &d);
+	}
+
+	d.granted_count = 0;
+
+	if (!retcode && d.request_count) {
+		retcode = drm_dma_get_buffers(dev, &d);
+	}
+
+	DRM_DEBUG("%d returning, granted = %d\n",
+		  current->pid, d.granted_count);
+	copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+
+	return retcode;
+}
+
+int gamma_irq_install(drm_device_t *dev, int irq)
+{
+	int retcode;
+
+	if (!irq)     return -EINVAL;
+	
+	down(&dev->struct_sem);
+	if (dev->irq) {
+		up(&dev->struct_sem);
+		return -EBUSY;
+	}
+	dev->irq = irq;
+	up(&dev->struct_sem);
+	
+	DRM_DEBUG("%d\n", irq);
+
+	dev->context_flag     = 0;
+	dev->interrupt_flag   = 0;
+	dev->dma_flag	      = 0;
+	
+	dev->dma->next_buffer = NULL;
+	dev->dma->next_queue  = NULL;
+	dev->dma->this_buffer = NULL;
+
+	dev->tq.next	      = NULL;
+	dev->tq.sync	      = 0;
+	dev->tq.routine	      = gamma_dma_schedule_tq_wrapper;
+	dev->tq.data	      = dev;
+
+
+				/* Before installing handler */
+	GAMMA_WRITE(GAMMA_GCOMMANDMODE, 0);
+	GAMMA_WRITE(GAMMA_GDMACONTROL, 0);
+	
+				/* Install handler */
+	if ((retcode = request_irq(dev->irq,
+				   gamma_dma_service,
+				   0,
+				   dev->devname,
+				   dev))) {
+		down(&dev->struct_sem);
+		dev->irq = 0;
+		up(&dev->struct_sem);
+		return retcode;
+	}
+
+				/* After installing handler */
+	GAMMA_WRITE(GAMMA_GINTENABLE,	    0x2001);
+	GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0x0008);
+	GAMMA_WRITE(GAMMA_GDELAYTIMER,	   0x39090);
+	
+	return 0;
+}
+
+int gamma_irq_uninstall(drm_device_t *dev)
+{
+	int irq;
+
+	down(&dev->struct_sem);
+	irq	 = dev->irq;
+	dev->irq = 0;
+	up(&dev->struct_sem);
+	
+	if (!irq) return -EINVAL;
+	
+	DRM_DEBUG("%d\n", irq);
+	
+	GAMMA_WRITE(GAMMA_GDELAYTIMER,	    0);
+	GAMMA_WRITE(GAMMA_COMMANDINTENABLE, 0);
+	GAMMA_WRITE(GAMMA_GINTENABLE,	    0);
+	free_irq(irq, dev);
+
+	return 0;
+}
+
+
+int gamma_control(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_control_t	ctl;
+	int		retcode;
+	
+	copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
+	
+	switch (ctl.func) {
+	case DRM_INST_HANDLER:
+		if ((retcode = gamma_irq_install(dev, ctl.irq)))
+			return retcode;
+		break;
+	case DRM_UNINST_HANDLER:
+		if ((retcode = gamma_irq_uninstall(dev)))
+			return retcode;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int gamma_lock(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	DECLARE_WAITQUEUE(entry, current);
+	int		  ret	= 0;
+	drm_lock_t	  lock;
+	drm_queue_t	  *q;
+#if DRM_DMA_HISTOGRAM
+	cycles_t	  start;
+
+	dev->lck_start = start = get_cycles();
+#endif
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+		  lock.context, current->pid, dev->lock.hw_lock->lock,
+		  lock.flags);
+
+	if (lock.context < 0 || lock.context >= dev->queue_count)
+		return -EINVAL;
+	q = dev->queuelist[lock.context];
+	
+	ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+
+	if (!ret) {
+		if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+		    != lock.context) {
+			long j = jiffies - dev->lock.lock_time;
+
+			if (j > 0 && j <= DRM_LOCK_SLICE) {
+				/* Can't take lock if we just had it and
+				   there is contention. */
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout(j);
+			}
+		}
+		add_wait_queue(&dev->lock.lock_queue, &entry);
+		for (;;) {
+			if (!dev->lock.hw_lock) {
+				/* Device has been unregistered */
+				ret = -EINTR;
+				break;
+			}
+			if (drm_lock_take(&dev->lock.hw_lock->lock,
+					  lock.context)) {
+				dev->lock.pid	    = current->pid;
+				dev->lock.lock_time = jiffies;
+				atomic_inc(&dev->total_locks);
+				atomic_inc(&q->total_locks);
+				break;	/* Got lock */
+			}
+			
+				/* Contention */
+			atomic_inc(&dev->total_sleeps);
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&dev->lock.lock_queue, &entry);
+	}
+
+	drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */
+	
+	if (!ret) {
+		if (lock.flags & _DRM_LOCK_READY)
+			gamma_dma_ready(dev);
+		if (lock.flags & _DRM_LOCK_QUIESCENT) {
+			if (gamma_found() == 1) {
+				gamma_dma_quiescent_single(dev);
+			} else {
+				gamma_dma_quiescent_dual(dev);
+			}
+		}
+	}
+	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+	
+	return ret;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/gamma_drv.c linux.18p8/drivers/char/drm/gamma_drv.c
--- linux.vanilla/drivers/char/drm/gamma_drv.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/gamma_drv.c	Fri Sep  1 14:14:35 2000
@@ -0,0 +1,575 @@
+/* gamma.c -- 3dlabs GMX 2000 driver -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "gamma_drv.h"
+
+#include <linux/agp_backend.h>
+
+static __attribute__((unused)) void unused(void)
+{
+	agp_enable(0);
+}
+
+#ifndef PCI_DEVICE_ID_3DLABS_GAMMA
+#define PCI_DEVICE_ID_3DLABS_GAMMA 0x0008
+#endif
+#ifndef PCI_DEVICE_ID_3DLABS_MX
+#define PCI_DEVICE_ID_3DLABS_MX 0x0006
+#endif
+
+#define GAMMA_NAME	 "gamma"
+#define GAMMA_DESC	 "3dlabs GMX 2000"
+#define GAMMA_DATE	 "20000719"
+#define GAMMA_MAJOR	 1
+#define GAMMA_MINOR	 0
+#define GAMMA_PATCHLEVEL 0
+
+static drm_device_t	      gamma_device;
+
+static struct file_operations gamma_fops = {
+#if LINUX_VERSION_CODE >= 0x020322
+				/* This started being used approx. 2.3.34 */
+	owner:   THIS_MODULE,
+#endif
+	open:	 gamma_open,
+	flush:	 drm_flush,
+	release: gamma_release,
+	ioctl:	 gamma_ioctl,
+	mmap:	 drm_mmap,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+	poll:	 drm_poll,
+};
+
+static struct miscdevice      gamma_misc = {
+	minor: MISC_DYNAMIC_MINOR,
+	name:  GAMMA_NAME,
+	fops:  &gamma_fops,
+};
+
+static drm_ioctl_desc_t	      gamma_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]    = { gamma_version,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]  = { drm_getmagic,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]  = { drm_irq_busid,	  0, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	     = { drm_block,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]    = { drm_unblock,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]    = { gamma_control,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]    = { drm_addmap,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)]   = { drm_addbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]  = { drm_markbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]  = { drm_infobufs,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]   = { drm_mapbufs,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]  = { drm_freebufs,	  1, 0 },
+	
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]    = { drm_addctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]     = { drm_rmctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]    = { drm_modctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]    = { drm_getctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { drm_switchctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]    = { drm_newctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]    = { drm_resctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]   = { drm_adddraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]    = { drm_rmdraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_DMA)]	     = { gamma_dma,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	     = { gamma_lock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]     = { gamma_unlock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]     = { drm_finish,	  1, 0 },
+};
+#define GAMMA_IOCTL_COUNT DRM_ARRAY_SIZE(gamma_ioctls)
+
+#ifdef MODULE
+static char		      *gamma = NULL;
+#endif
+static int 		      devices = 0;
+
+MODULE_AUTHOR("VA Linux Systems, Inc.");
+MODULE_DESCRIPTION("3dlabs GMX 2000");
+MODULE_PARM(gamma, "s");
+MODULE_PARM(devices, "i");
+MODULE_PARM_DESC(devices,
+		 "devices=x, where x is the number of MX chips on card\n");
+#ifndef MODULE
+/* gamma_options is called by the kernel to parse command-line options
+ * passed via the boot-loader (e.g., LILO).  It calls the insmod option
+ * routine, drm_parse_options.
+ */
+ 
+
+static int __init gamma_options(char *str)
+{
+	drm_parse_options(str);
+	return 1;
+}
+
+__setup("gamma=", gamma_options);
+#endif
+
+static int gamma_setup(drm_device_t *dev)
+{
+	int i;
+	
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use	  = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	drm_dma_setup(dev);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+#if DRM_DMA_HISTO
+	memset(&dev->histo, 0, sizeof(dev->histo));
+#endif
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+	
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+			
+	DRM_DEBUG("\n");
+			
+	/* The kernel's context could be created here, but is now created
+	   in drm_dma_enqueue.	This is more resource-efficient for
+	   hardware that does not do DMA, but may mean that
+	   drm_select_queue fails between the time the interrupt is
+	   initialized and the time the queues are initialized. */
+			
+	return 0;
+}
+
+
+static int gamma_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	if (dev->irq) gamma_irq_uninstall(dev);
+	
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+	
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+	
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+				/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+	
+				/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+	
+				/* Clear map area and mtrr information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+				if (map->mtrr >= 0) {
+					int retcode;
+					retcode = mtrr_del(map->mtrr,
+							   map->offset,
+							   map->size);
+					DRM_DEBUG("mtrr_del = %d\n", retcode);
+				}
+#endif
+				drm_ioremapfree(map->handle, map->size);
+				break;
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+			case _DRM_AGP:
+				/* Do nothing here, because this is all
+                                   handled in the AGP/GART driver. */
+				break;
+			}
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+	
+	if (dev->queuelist) {
+		for (i = 0; i < dev->queue_count; i++) {
+			drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
+			if (dev->queuelist[i]) {
+				drm_free(dev->queuelist[i],
+					 sizeof(*dev->queuelist[0]),
+					 DRM_MEM_QUEUES);
+				dev->queuelist[i] = NULL;
+			}
+		}
+		drm_free(dev->queuelist,
+			 dev->queue_slots * sizeof(*dev->queuelist),
+			 DRM_MEM_QUEUES);
+		dev->queuelist	 = NULL;
+	}
+
+	drm_dma_takedown(dev);
+
+	dev->queue_count     = 0;
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+int gamma_found(void)
+{
+	return devices;
+}
+
+int gamma_find_devices(void)
+{
+	struct pci_dev *d = NULL, *one = NULL, *two = NULL;
+
+	d = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_GAMMA,d);
+	if (!d) return 0;
+
+	one = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_MX,d);
+	if (!one) return 0;
+
+	/* Make sure it's on the same card, if not - no MX's found */
+	if (PCI_SLOT(d->devfn) != PCI_SLOT(one->devfn)) return 0;
+
+	two = pci_find_device(PCI_VENDOR_ID_3DLABS,PCI_DEVICE_ID_3DLABS_MX,one);
+	if (!two) return 1;
+
+	/* Make sure it's on the same card, if not - only 1 MX found */
+	if (PCI_SLOT(d->devfn) != PCI_SLOT(two->devfn)) return 1;
+
+	/* Two MX's found - we don't currently support more than 2 */
+	return 2;
+}
+
+/* gamma_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+static int gamma_init(void)
+{
+	int		      retcode;
+	drm_device_t	      *dev = &gamma_device;
+
+	DRM_DEBUG("\n");
+
+	memset((void *)dev, 0, sizeof(*dev));
+	dev->count_lock	  = SPIN_LOCK_UNLOCKED;
+	sema_init(&dev->struct_sem, 1);
+	
+#ifdef MODULE
+	drm_parse_options(gamma);
+#endif
+	devices = gamma_find_devices();
+	if (devices == 0) return -1;
+
+	if ((retcode = misc_register(&gamma_misc))) {
+		DRM_ERROR("Cannot register \"%s\"\n", GAMMA_NAME);
+		return retcode;
+	}
+	dev->device = MKDEV(MISC_MAJOR, gamma_misc.minor);
+	dev->name   = GAMMA_NAME;
+
+	drm_mem_init();
+	drm_proc_init(dev);
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d with %d MX devices\n",
+		 GAMMA_NAME,
+		 GAMMA_MAJOR,
+		 GAMMA_MINOR,
+		 GAMMA_PATCHLEVEL,
+		 GAMMA_DATE,
+		 gamma_misc.minor,
+		 devices);
+	
+	return 0;
+}
+
+/* gamma_cleanup is called via cleanup_module at module unload time. */
+
+static void gamma_cleanup(void)
+{
+	drm_device_t	      *dev = &gamma_device;
+
+	DRM_DEBUG("\n");
+	
+	drm_proc_cleanup();
+	if (misc_deregister(&gamma_misc)) {
+		DRM_ERROR("Cannot unload module\n");
+	} else {
+		DRM_INFO("Module unloaded\n");
+	}
+	gamma_takedown(dev);
+}
+
+module_init(gamma_init);
+module_exit(gamma_cleanup);
+
+
+int gamma_version(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_version_t version;
+	int	      len;
+
+	copy_from_user_ret(&version,
+			   (drm_version_t *)arg,
+			   sizeof(version),
+			   -EFAULT);
+
+#define DRM_COPY(name,value)				     \
+	len = strlen(value);				     \
+	if (len > name##_len) len = name##_len;		     \
+	name##_len = strlen(value);			     \
+	if (len && name) {				     \
+		copy_to_user_ret(name, value, len, -EFAULT); \
+	}
+
+	version.version_major	   = GAMMA_MAJOR;
+	version.version_minor	   = GAMMA_MINOR;
+	version.version_patchlevel = GAMMA_PATCHLEVEL;
+
+	DRM_COPY(version.name, GAMMA_NAME);
+	DRM_COPY(version.date, GAMMA_DATE);
+	DRM_COPY(version.desc, GAMMA_DESC);
+
+	copy_to_user_ret((drm_version_t *)arg,
+			 &version,
+			 sizeof(version),
+			 -EFAULT);
+	return 0;
+}
+
+int gamma_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t  *dev    = &gamma_device;
+	int	      retcode = 0;
+	
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return gamma_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	return retcode;
+}
+
+int gamma_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev;
+	int	      retcode = 0;
+
+	lock_kernel();
+	dev = priv->dev;
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_release(inode, filp))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_close);
+		spin_lock(&dev->count_lock);
+		if (!--dev->open_count) {
+			if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+				DRM_ERROR("Device busy: %d %d\n",
+					  atomic_read(&dev->ioctl_count),
+					  dev->blocked);
+				spin_unlock(&dev->count_lock);
+				unlock_kernel();
+				return -EBUSY;
+			}
+			spin_unlock(&dev->count_lock);
+			unlock_kernel();
+			return gamma_takedown(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	unlock_kernel();
+	return retcode;
+}
+
+/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int gamma_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int		 retcode = 0;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+	
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= GAMMA_IOCTL_COUNT) {
+		retcode = -EINVAL;
+	} else {
+		ioctl	  = &gamma_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			retcode = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			retcode = -EACCES;
+		} else {
+			retcode = (func)(inode, filp, cmd, arg);
+		}
+	}
+	
+	atomic_dec(&dev->ioctl_count);
+	return retcode;
+}
+
+
+int gamma_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+	
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+	gamma_dma_schedule(dev, 1);
+	if (!dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles()
+						       - dev->lck_start)]);
+#endif
+	
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/gamma_drv.h linux.18p8/drivers/char/drm/gamma_drv.h
--- linux.vanilla/drivers/char/drm/gamma_drv.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/gamma_drv.h	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,58 @@
+/* gamma_drv.h -- Private header for 3dlabs GMX 2000 driver -*- linux-c -*-
+ * Created: Mon Jan  4 10:05:05 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ * 
+ */
+
+#ifndef _GAMMA_DRV_H_
+#define _GAMMA_DRV_H_
+
+				/* gamma_drv.c */
+extern int  gamma_version(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  gamma_open(struct inode *inode, struct file *filp);
+extern int  gamma_release(struct inode *inode, struct file *filp);
+extern int  gamma_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  gamma_lock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  gamma_unlock(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+				/* gamma_dma.c */
+extern int  gamma_dma_schedule(drm_device_t *dev, int locked);
+extern int  gamma_dma(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+extern int  gamma_irq_install(drm_device_t *dev, int irq);
+extern int  gamma_irq_uninstall(drm_device_t *dev);
+extern int  gamma_control(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  gamma_find_devices(void);
+extern int  gamma_found(void);
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/i810_bufs.c linux.18p8/drivers/char/drm/i810_bufs.c
--- linux.vanilla/drivers/char/drm/i810_bufs.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/i810_bufs.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,334 @@
+/* i810_bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Thu Jan 6 01:47:26 2000 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ * 
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "i810_drv.h"
+#include "linux/un.h"
+
+int i810_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_desc_t request;
+	drm_buf_entry_t *entry;
+	drm_buf_t *buf;
+	unsigned long offset;
+	unsigned long agp_offset;
+	int count;
+	int order;
+	int size;
+	int alignment;
+	int page_order;
+	int total;
+	int byte_count;
+	int i;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	count = request.count;
+	order = drm_order(request.size);
+	size	= 1 << order;
+	agp_offset = request.agp_start;
+	alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total = PAGE_SIZE << page_order;
+	byte_count = 0;
+   
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+   
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM; /* May only call once for each order */
+	}
+   
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+   
+	entry->buf_size   = size;
+	entry->page_order = page_order;
+	offset = 0;
+   
+	while(entry->buf_count < count) {
+		buf = &entry->buflist[entry->buf_count];
+		buf->idx = dma->buf_count + entry->buf_count;
+		buf->total = alignment;
+		buf->order = order;
+		buf->used = 0;
+		buf->offset = offset;
+		buf->bus_address = dev->agp->base + agp_offset + offset;
+		buf->address = (void *)(agp_offset + offset + dev->agp->base);
+		buf->next = NULL;
+		buf->waiting = 0;
+		buf->pending = 0;
+		init_waitqueue_head(&buf->dma_wait);
+		buf->pid = 0;
+
+		buf->dev_private = drm_alloc(sizeof(drm_i810_buf_priv_t), 
+					     DRM_MEM_BUFS);
+		buf->dev_priv_size = sizeof(drm_i810_buf_priv_t);
+	   	memset(buf->dev_private, 0, sizeof(drm_i810_buf_priv_t));
+
+#if DRM_DMA_HISTOGRAM
+		buf->time_queued = 0;
+		buf->time_dispatched = 0;
+		buf->time_completed = 0;
+		buf->time_freed = 0;
+#endif
+		offset = offset + alignment;
+		entry->buf_count++;
+		byte_count += PAGE_SIZE << page_order;
+      
+		DRM_DEBUG("buffer %d @ %p\n",
+			  entry->buf_count, buf->address);
+	}
+   
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+   
+	dma->buf_count  += entry->buf_count;
+	dma->byte_count += byte_count;
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+   
+	up(&dev->struct_sem);
+   
+	request.count = entry->buf_count;
+	request.size  = size;
+   
+	copy_to_user_ret((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+   
+	atomic_dec(&dev->buf_alloc);
+	dma->flags = _DRM_DMA_USE_AGP;
+	return 0;
+}
+
+int i810_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_buf_desc_t	 request;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	if(request.flags & _DRM_AGP_BUFFER)
+		return i810_addbufs_agp(inode, filp, cmd, arg);
+	else
+		return -EINVAL;
+}
+
+int i810_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_info_t	 request;
+	int		 i;
+	int		 count;
+
+	if (!dma) return -EINVAL;
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	copy_from_user_ret(&request,
+			   (drm_buf_info_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+		if (dma->bufs[i].buf_count) ++count;
+	}
+	
+	DRM_DEBUG("count = %d\n", count);
+	
+	if (request.count >= count) {
+		for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+			if (dma->bufs[i].buf_count) {
+				copy_to_user_ret(&request.list[count].count,
+						 &dma->bufs[i].buf_count,
+						 sizeof(dma->bufs[0]
+							.buf_count),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count].size,
+						 &dma->bufs[i].buf_size,
+						 sizeof(dma->bufs[0].buf_size),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count].low_mark,
+						 &dma->bufs[i]
+						 .freelist.low_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.low_mark),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count]
+						 .high_mark,
+						 &dma->bufs[i]
+						 .freelist.high_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.high_mark),
+						 -EFAULT);
+				DRM_DEBUG("%d %d %d %d %d\n",
+					  i,
+					  dma->bufs[i].buf_count,
+					  dma->bufs[i].buf_size,
+					  dma->bufs[i].freelist.low_mark,
+					  dma->bufs[i].freelist.high_mark);
+				++count;
+			}
+		}
+	}
+	request.count = count;
+
+	copy_to_user_ret((drm_buf_info_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+	
+	return 0;
+}
+
+int i810_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 order;
+	drm_buf_entry_t	 *entry;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	DRM_DEBUG("%d, %d, %d\n",
+		  request.size, request.low_mark, request.high_mark);
+	order = drm_order(request.size);
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	entry = &dma->bufs[order];
+
+	if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+		return -EINVAL;
+	if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+		return -EINVAL;
+
+	entry->freelist.low_mark  = request.low_mark;
+	entry->freelist.high_mark = request.high_mark;
+	
+	return 0;
+}
+
+int i810_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_free_t	 request;
+	int		 i;
+	int		 idx;
+	drm_buf_t	 *buf;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_free_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	DRM_DEBUG("%d\n", request.count);
+	for (i = 0; i < request.count; i++) {
+		copy_from_user_ret(&idx,
+				   &request.list[i],
+				   sizeof(idx),
+				   -EFAULT);
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  idx, dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[idx];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d freeing buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		drm_free_buffer(dev, buf);
+	}
+	
+	return 0;
+}
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/i810_context.c linux.18p8/drivers/char/drm/i810_context.c
--- linux.vanilla/drivers/char/drm/i810_context.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/i810_context.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,203 @@
+/* i810_context.c -- IOCTLs for i810 contexts -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "i810_drv.h"
+
+static int i810_alloc_queue(drm_device_t *dev)
+{
+   	int temp = drm_ctxbitmap_next(dev);
+   	DRM_DEBUG("i810_alloc_queue: %d\n", temp);
+	return temp;
+}
+
+int i810_context_switch(drm_device_t *dev, int old, int new)
+{
+        char        buf[64];
+
+        atomic_inc(&dev->total_ctx);
+
+        if (test_and_set_bit(0, &dev->context_flag)) {
+                DRM_ERROR("Reentering -- FIXME\n");
+                return -EBUSY;
+        }
+
+#if DRM_DMA_HISTOGRAM
+        dev->ctx_start = get_cycles();
+#endif
+        
+        DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+        if (new == dev->last_context) {
+                clear_bit(0, &dev->context_flag);
+                return 0;
+        }
+        
+        if (drm_flags & DRM_FLAG_NOCTX) {
+                i810_context_switch_complete(dev, new);
+        } else {
+                sprintf(buf, "C %d %d\n", old, new);
+                drm_write_string(dev, buf);
+        }
+        
+        return 0;
+}
+
+int i810_context_switch_complete(drm_device_t *dev, int new)
+{
+        dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+        dev->last_switch  = jiffies;
+        
+        if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+                DRM_ERROR("Lock isn't held after context switch\n");
+        }
+
+				/* If a context switch is ever initiated
+                                   when the kernel holds the lock, release
+                                   that lock here. */
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+                                                      - dev->ctx_start)]);
+                   
+#endif
+        clear_bit(0, &dev->context_flag);
+        wake_up(&dev->context_wait);
+        
+        return 0;
+}
+
+int i810_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			copy_to_user_ret(&res.contexts[i],
+					 &i,
+					 sizeof(i),
+					 -EFAULT);
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+	return 0;
+}
+
+int i810_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	if ((ctx.handle = i810_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+				/* Skip kernel's context and get a new one. */
+		ctx.handle = i810_alloc_queue(dev);
+	}
+        if (ctx.handle == -1) {
+		DRM_DEBUG("Not enough free contexts.\n");
+				/* Should this return -EBUSY instead? */
+		return -ENOMEM;
+	}
+	DRM_DEBUG("%d\n", ctx.handle);
+	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int i810_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+   	/* This does nothing for the i810 */
+	return 0;
+}
+
+int i810_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	drm_ctx_t ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+	/* This is 0, because we don't hanlde any context flags */
+	ctx.flags = 0;
+	copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int i810_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	return i810_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int i810_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	i810_context_switch_complete(dev, ctx.handle);
+
+	return 0;
+}
+
+int i810_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+   	if(ctx.handle != DRM_KERNEL_CONTEXT) {
+	   	drm_ctxbitmap_free(dev, ctx.handle);
+	}
+	
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/i810_dma.c linux.18p8/drivers/char/drm/i810_dma.c
--- linux.vanilla/drivers/char/drm/i810_dma.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/i810_dma.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,1417 @@
+/* i810_dma.c -- DMA support for the i810 -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *          Keith Whitwell <keithw@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "i810_drv.h"
+#include <linux/interrupt.h>	/* For task queue support */
+
+/* in case we don't have a 2.3.99-pre6 kernel or later: */
+#ifndef VM_DONTCOPY
+#define VM_DONTCOPY 0
+#endif
+
+#define I810_BUF_FREE		2
+#define I810_BUF_CLIENT		1
+#define I810_BUF_HARDWARE      	0
+
+#define I810_BUF_UNMAPPED 0
+#define I810_BUF_MAPPED   1
+
+#define I810_REG(reg)		2
+#define I810_BASE(reg)		((unsigned long) \
+				dev->maplist[I810_REG(reg)]->handle)
+#define I810_ADDR(reg)		(I810_BASE(reg) + reg)
+#define I810_DEREF(reg)		*(__volatile__ int *)I810_ADDR(reg)
+#define I810_READ(reg)		I810_DEREF(reg)
+#define I810_WRITE(reg,val) 	do { I810_DEREF(reg) = val; } while (0)
+#define I810_DEREF16(reg)	*(__volatile__ u16 *)I810_ADDR(reg)
+#define I810_READ16(reg)	I810_DEREF16(reg)
+#define I810_WRITE16(reg,val)	do { I810_DEREF16(reg) = val; } while (0)
+
+#define RING_LOCALS	unsigned int outring, ringmask; volatile char *virt;
+
+#define BEGIN_LP_RING(n) do {				\
+	if (I810_VERBOSE)				\
+		DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",	\
+			  n, __FUNCTION__);		\
+	if (dev_priv->ring.space < n*4) 		\
+		i810_wait_ring(dev, n*4);		\
+	dev_priv->ring.space -= n*4;			\
+	outring = dev_priv->ring.tail;			\
+	ringmask = dev_priv->ring.tail_mask;		\
+	virt = dev_priv->ring.virtual_start;		\
+} while (0)
+
+#define ADVANCE_LP_RING() do {					\
+	if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n");	\
+	dev_priv->ring.tail = outring;				\
+	I810_WRITE(LP_RING + RING_TAIL, outring);		\
+} while(0)
+
+#define OUT_RING(n) do {						\
+	if (I810_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\
+	*(volatile unsigned int *)(virt + outring) = n;			\
+	outring += 4;							\
+	outring &= ringmask;						\
+} while (0);
+
+static inline void i810_print_status_page(drm_device_t *dev)
+{
+   	drm_device_dma_t *dma = dev->dma;
+      	drm_i810_private_t *dev_priv = dev->dev_private;
+	u32 *temp = (u32 *)dev_priv->hw_status_page;
+   	int i;
+
+   	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
+   	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
+   	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
+      	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+   	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
+   	for(i = 6; i < dma->buf_count + 6; i++) {
+	   	DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
+	}
+}
+
+static drm_buf_t *i810_freelist_get(drm_device_t *dev)
+{
+   	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+   	int 		 used;
+   
+	/* Linear search might not be the best solution */
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+		/* In use is already a pointer */
+	   	used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, 
+			       I810_BUF_CLIENT);
+	   	if(used == I810_BUF_FREE) {
+			return buf;
+		}
+	}
+   	return NULL;
+}
+
+/* This should only be called if the buffer is not sent to the hardware
+ * yet, the hardware updates in use for us once its on the ring buffer.
+ */
+
+static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
+{
+   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+   	int used;
+   
+   	/* In use is already a pointer */
+   	used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
+   	if(used != I810_BUF_CLIENT) {
+	   	DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
+	   	return -EINVAL;
+	}
+   
+   	return 0;
+}
+
+static struct file_operations i810_buffer_fops = {
+	open:	 i810_open,
+	flush:	 drm_flush,
+	release: i810_release,
+	ioctl:	 i810_ioctl,
+	mmap:	 i810_mmap_buffers,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+      	poll:	 drm_poll,
+};
+
+int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	    *priv	  = filp->private_data;
+	drm_device_t	    *dev;
+	drm_i810_private_t  *dev_priv;
+	drm_buf_t           *buf;
+	drm_i810_buf_priv_t *buf_priv;
+
+	lock_kernel();
+	dev	 = priv->dev;
+	dev_priv = dev->dev_private;
+	buf      = dev_priv->mmap_buffer;
+	buf_priv = buf->dev_private;
+   
+	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
+	vma->vm_file = filp;
+   
+   	buf_priv->currently_mapped = I810_BUF_MAPPED;
+	unlock_kernel();
+
+	if (remap_page_range(vma->vm_start,
+			     VM_OFFSET(vma),
+			     vma->vm_end - vma->vm_start,
+			     vma->vm_page_prot)) return -EAGAIN;
+	return 0;
+}
+
+static int i810_map_buffer(drm_buf_t *buf, struct file *filp)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+      	drm_i810_private_t *dev_priv = dev->dev_private;
+   	struct file_operations *old_fops;
+	int retcode = 0;
+
+	if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL;
+
+	if(VM_DONTCOPY != 0) {
+		down(&current->mm->mmap_sem);
+		old_fops = filp->f_op;
+		filp->f_op = &i810_buffer_fops;
+		dev_priv->mmap_buffer = buf;
+		buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, 
+						    PROT_READ|PROT_WRITE,
+						    MAP_SHARED, 
+						    buf->bus_address);
+		dev_priv->mmap_buffer = NULL;
+   		filp->f_op = old_fops;
+		if ((unsigned long)buf_priv->virtual > -1024UL) {
+			/* Real error */
+			DRM_DEBUG("mmap error\n");
+			retcode = (signed int)buf_priv->virtual;
+			buf_priv->virtual = 0;
+		}
+   		up(&current->mm->mmap_sem);
+	} else {
+		buf_priv->virtual = buf_priv->kernel_virtual;
+   		buf_priv->currently_mapped = I810_BUF_MAPPED;
+	}
+	return retcode;
+}
+
+static int i810_unmap_buffer(drm_buf_t *buf)
+{
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	int retcode = 0;
+
+	if(VM_DONTCOPY != 0) {
+		if(buf_priv->currently_mapped != I810_BUF_MAPPED) 
+			return -EINVAL;
+		down(&current->mm->mmap_sem);
+#if LINUX_VERSION_CODE < 0x020399
+        	retcode = do_munmap((unsigned long)buf_priv->virtual, 
+				    (size_t) buf->total);
+#else
+        	retcode = do_munmap(current->mm, 
+				    (unsigned long)buf_priv->virtual, 
+				    (size_t) buf->total);
+#endif
+   		up(&current->mm->mmap_sem);
+	}
+   	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
+   	buf_priv->virtual = 0;
+
+	return retcode;
+}
+
+static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d, 
+			       struct file *filp)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_buf_t	  *buf;
+	drm_i810_buf_priv_t *buf_priv;
+	int retcode = 0;
+
+	buf = i810_freelist_get(dev);
+	if (!buf) {
+		retcode = -ENOMEM;
+	   	DRM_DEBUG("%s retcode %d\n", __FUNCTION__, retcode);
+		goto out_get_buf;
+	}
+   
+	retcode = i810_map_buffer(buf, filp);
+	if(retcode) {
+		i810_freelist_put(dev, buf);
+	   	DRM_DEBUG("mapbuf failed in %s retcode %d\n", 
+			  __FUNCTION__, retcode);
+	   	goto out_get_buf;
+	}
+	buf->pid     = priv->pid;
+	buf_priv = buf->dev_private;	
+	d->granted = 1;
+   	d->request_idx = buf->idx;
+   	d->request_size = buf->total;
+   	d->virtual = buf_priv->virtual;
+
+out_get_buf:
+	return retcode;
+}
+
+static unsigned long i810_alloc_page(drm_device_t *dev)
+{
+	unsigned long address;
+   
+	address = __get_free_page(GFP_KERNEL);
+	if(address == 0UL) 
+		return 0;
+	
+	atomic_inc(&mem_map[MAP_NR((void *) address)].count);
+	set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags);
+   
+	return address;
+}
+
+static void i810_free_page(drm_device_t *dev, unsigned long page)
+{
+	if(page == 0UL) 
+		return;
+	
+	atomic_dec(&mem_map[MAP_NR((void *) page)].count);
+	clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags);
+	wake_up(&mem_map[MAP_NR((void *) page)].wait);
+	free_page(page);
+	return;
+}
+
+static int i810_dma_cleanup(drm_device_t *dev)
+{
+	drm_device_dma_t *dma = dev->dma;
+
+	if(dev->dev_private) {
+		int i;
+	   	drm_i810_private_t *dev_priv = 
+	     		(drm_i810_private_t *) dev->dev_private;
+	   
+	   	if(dev_priv->ring.virtual_start) {
+		   	drm_ioremapfree((void *) dev_priv->ring.virtual_start,
+					dev_priv->ring.Size);
+		}
+	   	if(dev_priv->hw_status_page != 0UL) {
+		   	i810_free_page(dev, dev_priv->hw_status_page);
+		   	/* Need to rewrite hardware status page */
+		   	I810_WRITE(0x02080, 0x1ffff000);
+		}
+	   	drm_free(dev->dev_private, sizeof(drm_i810_private_t), 
+			 DRM_MEM_DRIVER);
+	   	dev->dev_private = NULL;
+
+		for (i = 0; i < dma->buf_count; i++) {
+			drm_buf_t *buf = dma->buflist[ i ];
+			drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+			drm_ioremapfree(buf_priv->kernel_virtual, buf->total);
+		}
+	}
+   	return 0;
+}
+
+static int i810_wait_ring(drm_device_t *dev, int n)
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+   	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+   	int iters = 0;
+   	unsigned long end;
+	unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+
+	end = jiffies + (HZ*3);
+   	while (ring->space < n) {
+	   	int i;
+	
+	   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+	   	ring->space = ring->head - (ring->tail+8);
+		if (ring->space < 0) ring->space += ring->Size;
+	   
+		if (ring->head != last_head)
+		   end = jiffies + (HZ*3);
+	  
+	   	iters++;
+		if((signed)(end - jiffies) <= 0) {
+		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+		   	DRM_ERROR("lockup\n");
+		   	goto out_wait_ring;
+		}
+
+	   	for (i = 0 ; i < 2000 ; i++) ;
+	}
+
+out_wait_ring:   
+   	return iters;
+}
+
+static void i810_kernel_lost_context(drm_device_t *dev)
+{
+      	drm_i810_private_t *dev_priv = dev->dev_private;
+   	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+      
+   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+     	ring->tail = I810_READ(LP_RING + RING_TAIL);
+     	ring->space = ring->head - (ring->tail+8);
+     	if (ring->space < 0) ring->space += ring->Size;
+}
+
+static int i810_freelist_init(drm_device_t *dev)
+{
+      	drm_device_dma_t *dma = dev->dma;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+   	int my_idx = 24;
+   	u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
+   	int i;
+   
+   	if(dma->buf_count > 1019) {
+	   	/* Not enough space in the status page for the freelist */
+	   	return -EINVAL;
+	}
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	   
+	   	buf_priv->in_use = hw_status++;
+	   	buf_priv->my_use_idx = my_idx;
+	   	my_idx += 4;
+
+	   	*buf_priv->in_use = I810_BUF_FREE;
+
+		buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, 
+						       buf->total);
+	}
+	return 0;
+}
+
+static int i810_dma_initialize(drm_device_t *dev, 
+			       drm_i810_private_t *dev_priv,
+			       drm_i810_init_t *init)
+{
+	drm_map_t *sarea_map;
+
+   	dev->dev_private = (void *) dev_priv;
+   	memset(dev_priv, 0, sizeof(drm_i810_private_t));
+
+   	if (init->ring_map_idx >= dev->map_count ||
+	    init->buffer_map_idx >= dev->map_count) {
+	   	i810_dma_cleanup(dev);
+	   	DRM_ERROR("ring_map or buffer_map are invalid\n");
+	   	return -EINVAL;
+	}
+   
+   	dev_priv->ring_map_idx = init->ring_map_idx;
+   	dev_priv->buffer_map_idx = init->buffer_map_idx;
+	sarea_map = dev->maplist[0];
+	dev_priv->sarea_priv = (drm_i810_sarea_t *) 
+		((u8 *)sarea_map->handle + 
+		 init->sarea_priv_offset);
+
+   	atomic_set(&dev_priv->flush_done, 0);
+	init_waitqueue_head(&dev_priv->flush_queue);
+   	
+   	dev_priv->ring.Start = init->ring_start;
+   	dev_priv->ring.End = init->ring_end;
+   	dev_priv->ring.Size = init->ring_size;
+
+   	dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + 
+						   init->ring_start, 
+						   init->ring_size);
+
+   	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+   
+   	if (dev_priv->ring.virtual_start == NULL) {
+	   	i810_dma_cleanup(dev);
+	   	DRM_ERROR("can not ioremap virtual address for"
+			  " ring buffer\n");
+	   	return -ENOMEM;
+	}
+
+	dev_priv->w = init->w;
+	dev_priv->h = init->h;
+	dev_priv->pitch = init->pitch;
+	dev_priv->back_offset = init->back_offset;
+	dev_priv->depth_offset = init->depth_offset;
+
+	dev_priv->front_di1 = init->front_offset | init->pitch_bits;
+	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
+	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
+	
+   
+   	/* Program Hardware Status Page */
+   	dev_priv->hw_status_page = i810_alloc_page(dev);
+   	memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
+   	if(dev_priv->hw_status_page == 0UL) {
+		i810_dma_cleanup(dev);
+		DRM_ERROR("Can not allocate hardware status page\n");
+		return -ENOMEM;
+	}
+   	DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
+   
+   	I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
+   	DRM_DEBUG("Enabled hardware status page\n");
+   
+   	/* Now we need to init our freelist */
+   	if(i810_freelist_init(dev) != 0) {
+	   	i810_dma_cleanup(dev);
+	   	DRM_ERROR("Not enough space in the status page for"
+			  " the freelist\n");
+	   	return -ENOMEM;
+	}
+   	return 0;
+}
+
+int i810_dma_init(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+   	drm_file_t *priv = filp->private_data;
+   	drm_device_t *dev = priv->dev;
+   	drm_i810_private_t *dev_priv;
+   	drm_i810_init_t init;
+   	int retcode = 0;
+	
+   	copy_from_user_ret(&init, (drm_i810_init_t *)arg, 
+			   sizeof(init), -EFAULT);
+	
+   	switch(init.func) {
+	 	case I810_INIT_DMA:
+	   		dev_priv = drm_alloc(sizeof(drm_i810_private_t), 
+					     DRM_MEM_DRIVER);
+	   		if(dev_priv == NULL) return -ENOMEM;
+	   		retcode = i810_dma_initialize(dev, dev_priv, &init);
+	   	break;
+	 	case I810_CLEANUP_DMA:
+	   		retcode = i810_dma_cleanup(dev);
+	   	break;
+	 	default:
+	   		retcode = -EINVAL;
+	   	break;
+	}
+   
+   	return retcode;
+}
+
+
+
+/* Most efficient way to verify state for the i810 is as it is
+ * emitted.  Non-conformant state is silently dropped.
+ *
+ * Use 'volatile' & local var tmp to force the emitted values to be
+ * identical to the verified ones.
+ */
+static void i810EmitContextVerified( drm_device_t *dev, 
+				     volatile unsigned int *code ) 
+{	
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I810_CTX_SETUP_SIZE );
+
+	OUT_RING( GFX_OP_COLOR_FACTOR );
+	OUT_RING( code[I810_CTXREG_CF1] );
+
+	OUT_RING( GFX_OP_STIPPLE );
+	OUT_RING( code[I810_CTXREG_ST1] );
+
+	for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) {
+		tmp = code[i];
+
+		if ((tmp & (7<<29)) == (3<<29) &&
+		    (tmp & (0x1f<<24)) < (0x1d<<24)) 
+		{
+			OUT_RING( tmp ); 
+			j++;
+		} 
+	}
+
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+static void i810EmitTexVerified( drm_device_t *dev, 
+				 volatile unsigned int *code ) 
+{	
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+	int i, j = 0;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I810_TEX_SETUP_SIZE );
+
+	OUT_RING( GFX_OP_MAP_INFO );
+	OUT_RING( code[I810_TEXREG_MI1] );
+	OUT_RING( code[I810_TEXREG_MI2] );
+	OUT_RING( code[I810_TEXREG_MI3] );
+
+	for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) {
+		tmp = code[i];
+
+		if ((tmp & (7<<29)) == (3<<29) &&
+		    (tmp & (0x1f<<24)) < (0x1d<<24)) 
+		{
+			OUT_RING( tmp ); 
+			j++;
+		}
+	} 
+		
+	if (j & 1) 
+		OUT_RING( 0 ); 
+
+	ADVANCE_LP_RING();
+}
+
+
+/* Need to do some additional checking when setting the dest buffer.
+ */
+static void i810EmitDestVerified( drm_device_t *dev, 
+				  volatile unsigned int *code ) 
+{	
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+	unsigned int tmp;
+	RING_LOCALS;
+
+	BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 );
+
+	tmp = code[I810_DESTREG_DI1];
+	if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
+		OUT_RING( CMD_OP_DESTBUFFER_INFO );
+		OUT_RING( tmp );
+	} else
+	   DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
+		     tmp, dev_priv->front_di1, dev_priv->back_di1);
+
+	/* invarient:
+	 */
+	OUT_RING( CMD_OP_Z_BUFFER_INFO );
+	OUT_RING( dev_priv->zi1 );
+
+	OUT_RING( GFX_OP_DESTBUFFER_VARS );
+	OUT_RING( code[I810_DESTREG_DV1] );
+
+	OUT_RING( GFX_OP_DRAWRECT_INFO );
+	OUT_RING( code[I810_DESTREG_DR1] );
+	OUT_RING( code[I810_DESTREG_DR2] );
+	OUT_RING( code[I810_DESTREG_DR3] );
+	OUT_RING( code[I810_DESTREG_DR4] );
+	OUT_RING( 0 );
+
+	ADVANCE_LP_RING();
+}
+
+
+
+static void i810EmitState( drm_device_t *dev )
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int dirty = sarea_priv->dirty;
+
+	if (dirty & I810_UPLOAD_BUFFERS) {
+		i810EmitDestVerified( dev, sarea_priv->BufferState );
+		sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS;
+	}
+
+	if (dirty & I810_UPLOAD_CTX) {
+		i810EmitContextVerified( dev, sarea_priv->ContextState );
+		sarea_priv->dirty &= ~I810_UPLOAD_CTX;
+	}
+
+	if (dirty & I810_UPLOAD_TEX0) {
+		i810EmitTexVerified( dev, sarea_priv->TexState[0] );
+		sarea_priv->dirty &= ~I810_UPLOAD_TEX0;
+	}
+
+	if (dirty & I810_UPLOAD_TEX1) {
+		i810EmitTexVerified( dev, sarea_priv->TexState[1] );
+		sarea_priv->dirty &= ~I810_UPLOAD_TEX1;
+	}
+}
+
+
+
+/* need to verify 
+ */
+static void i810_dma_dispatch_clear( drm_device_t *dev, int flags, 
+				     unsigned int clear_color,
+				     unsigned int clear_zval )
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	int pitch = dev_priv->pitch;
+	int cpp = 2;
+	int i;
+	RING_LOCALS;
+
+  	i810_kernel_lost_context(dev);
+
+      	if (nbox > I810_NR_SAREA_CLIPRECTS)
+     		nbox = I810_NR_SAREA_CLIPRECTS;
+
+	for (i = 0 ; i < nbox ; i++, pbox++) {
+		unsigned int x = pbox->x1;
+		unsigned int y = pbox->y1;
+		unsigned int width = (pbox->x2 - x) * cpp;
+		unsigned int height = pbox->y2 - y;
+		unsigned int start = y * pitch + x * cpp;
+
+		if (pbox->x1 > pbox->x2 ||
+		    pbox->y1 > pbox->y2 ||
+		    pbox->x2 > dev_priv->w ||
+		    pbox->y2 > dev_priv->h)
+			continue;
+
+	   	if ( flags & I810_FRONT ) {	    
+		   	DRM_DEBUG("clear front\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( BR00_BITBLT_CLIENT | 
+				  BR00_OP_COLOR_BLT | 0x3 );
+			OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
+			OUT_RING( (height << 16) | width );
+			OUT_RING( start );
+			OUT_RING( clear_color );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+		}
+
+		if ( flags & I810_BACK ) {
+			DRM_DEBUG("clear back\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( BR00_BITBLT_CLIENT | 
+				  BR00_OP_COLOR_BLT | 0x3 );
+			OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
+			OUT_RING( (height << 16) | width );
+			OUT_RING( dev_priv->back_offset + start );
+			OUT_RING( clear_color );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+		}
+
+		if ( flags & I810_DEPTH ) {
+			DRM_DEBUG("clear depth\n");
+			BEGIN_LP_RING( 6 );	    
+			OUT_RING( BR00_BITBLT_CLIENT | 
+				  BR00_OP_COLOR_BLT | 0x3 );
+			OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
+			OUT_RING( (height << 16) | width );
+			OUT_RING( dev_priv->depth_offset + start );
+			OUT_RING( clear_zval );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+		}
+	}
+}
+
+static void i810_dma_dispatch_swap( drm_device_t *dev )
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+      	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	int pitch = dev_priv->pitch;
+	int cpp = 2;
+	int ofs = dev_priv->back_offset;
+	int i;
+	RING_LOCALS;
+
+	DRM_DEBUG("swapbuffers\n");
+
+  	i810_kernel_lost_context(dev);
+
+      	if (nbox > I810_NR_SAREA_CLIPRECTS)
+     		nbox = I810_NR_SAREA_CLIPRECTS;
+
+	for (i = 0 ; i < nbox; i++, pbox++) 
+	{
+		unsigned int w = pbox->x2 - pbox->x1;
+		unsigned int h = pbox->y2 - pbox->y1;
+		unsigned int dst = pbox->x1*cpp + pbox->y1*pitch;
+		unsigned int start = ofs + dst;
+
+		if (pbox->x1 > pbox->x2 ||
+		    pbox->y1 > pbox->y2 ||
+		    pbox->x2 > dev_priv->w ||
+		    pbox->y2 > dev_priv->h)
+			continue;
+ 
+	   	DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
+			  pbox[i].x1, pbox[i].y1,
+			  pbox[i].x2, pbox[i].y2);
+
+		BEGIN_LP_RING( 6 );
+		OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 );
+		OUT_RING( pitch | (0xCC << 16));
+		OUT_RING( (h << 16) | (w * cpp));
+		OUT_RING( dst );
+		OUT_RING( pitch );	
+		OUT_RING( start );
+		ADVANCE_LP_RING();
+	}
+}
+
+
+static void i810_dma_dispatch_vertex(drm_device_t *dev, 
+				     drm_buf_t *buf,
+				     int discard,
+				     int used)
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+   	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+   	drm_clip_rect_t *box = sarea_priv->boxes;
+   	int nbox = sarea_priv->nbox;
+	unsigned long address = (unsigned long)buf->bus_address;
+	unsigned long start = address - dev->agp->base;     
+	int i = 0, u;
+   	RING_LOCALS;
+
+   	i810_kernel_lost_context(dev);
+
+   	if (nbox > I810_NR_SAREA_CLIPRECTS) 
+		nbox = I810_NR_SAREA_CLIPRECTS;
+
+	if (discard) {
+		u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, 
+			    I810_BUF_HARDWARE);
+		if(u != I810_BUF_CLIENT) {
+			DRM_DEBUG("xxxx 2\n");
+		}
+	}
+
+	if (used > 4*1024) 
+		used = 0;
+
+	if (sarea_priv->dirty)
+	   i810EmitState( dev );
+
+  	DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", 
+		  address, used, nbox);
+
+   	dev_priv->counter++;
+   	DRM_DEBUG(  "dispatch counter : %ld\n", dev_priv->counter);
+   	DRM_DEBUG(  "i810_dma_dispatch\n");
+   	DRM_DEBUG(  "start : %lx\n", start);
+	DRM_DEBUG(  "used : %d\n", used);
+   	DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4);
+
+	if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
+		*(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |
+					     sarea_priv->vertex_prim |
+					     ((used/4)-2));
+		
+		if (used & 4) {
+			*(u32 *)((u32)buf_priv->virtual + used) = 0;
+			used += 4;
+		}
+
+		i810_unmap_buffer(buf);
+	}
+		   
+	if (used) {
+		do {
+			if (i < nbox) {
+				BEGIN_LP_RING(4);
+				OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR | 
+					  SC_ENABLE );
+				OUT_RING( GFX_OP_SCISSOR_INFO );
+				OUT_RING( box[i].x1 | (box[i].y1<<16) );
+				OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) );
+				ADVANCE_LP_RING();
+			}
+			
+			BEGIN_LP_RING(4);
+			OUT_RING( CMD_OP_BATCH_BUFFER );
+			OUT_RING( start | BB1_PROTECTED );
+			OUT_RING( start + used - 4 );
+			OUT_RING( 0 );
+			ADVANCE_LP_RING();
+			
+		} while (++i < nbox);
+	}
+
+	BEGIN_LP_RING(10);
+	OUT_RING( CMD_STORE_DWORD_IDX );
+	OUT_RING( 20 );
+	OUT_RING( dev_priv->counter );
+	OUT_RING( 0 );
+
+	if (discard) {
+		OUT_RING( CMD_STORE_DWORD_IDX );
+		OUT_RING( buf_priv->my_use_idx );
+		OUT_RING( I810_BUF_FREE );
+		OUT_RING( 0 );
+	}
+
+      	OUT_RING( CMD_REPORT_HEAD );
+	OUT_RING( 0 );
+   	ADVANCE_LP_RING();
+}
+
+
+/* Interrupts are only for flushing */
+static void i810_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+	drm_device_t	 *dev = (drm_device_t *)device;
+   	u16 temp;
+   
+	atomic_inc(&dev->total_irq);
+      	temp = I810_READ16(I810REG_INT_IDENTITY_R);
+   	temp = temp & ~(0x6000);
+   	if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, 
+				   temp); /* Clear all interrupts */
+	else
+	   return;
+ 
+   	queue_task(&dev->tq, &tq_immediate);
+   	mark_bh(IMMEDIATE_BH);
+}
+
+static void i810_dma_task_queue(void *device)
+{
+	drm_device_t *dev = (drm_device_t *) device;
+      	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+   	atomic_set(&dev_priv->flush_done, 1);
+   	wake_up_interruptible(&dev_priv->flush_queue);
+}
+
+int i810_irq_install(drm_device_t *dev, int irq)
+{
+	int retcode;
+	u16 temp;
+   
+	if (!irq)     return -EINVAL;
+	
+	down(&dev->struct_sem);
+	if (dev->irq) {
+		up(&dev->struct_sem);
+		return -EBUSY;
+	}
+	dev->irq = irq;
+	up(&dev->struct_sem);
+	
+   	DRM_DEBUG(  "Interrupt Install : %d\n", irq);
+	DRM_DEBUG("%d\n", irq);
+
+	dev->context_flag     = 0;
+	dev->interrupt_flag   = 0;
+	dev->dma_flag	      = 0;
+	
+	dev->dma->next_buffer = NULL;
+	dev->dma->next_queue  = NULL;
+	dev->dma->this_buffer = NULL;
+
+	dev->tq.next	      = NULL;
+	dev->tq.sync	      = 0;
+	dev->tq.routine	      = i810_dma_task_queue;
+	dev->tq.data	      = dev;
+
+				/* Before installing handler */
+   	temp = I810_READ16(I810REG_HWSTAM);
+   	temp = temp & 0x6000;
+   	I810_WRITE16(I810REG_HWSTAM, temp);
+   	
+      	temp = I810_READ16(I810REG_INT_MASK_R);
+   	temp = temp & 0x6000;
+   	I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */
+   	temp = I810_READ16(I810REG_INT_ENABLE_R);
+   	temp = temp & 0x6000;
+      	I810_WRITE16(I810REG_INT_ENABLE_R, temp); /* Disable all interrupts */
+
+				/* Install handler */
+	if ((retcode = request_irq(dev->irq,
+				   i810_dma_service,
+				   SA_SHIRQ,
+				   dev->devname,
+				   dev))) {
+		down(&dev->struct_sem);
+		dev->irq = 0;
+		up(&dev->struct_sem);
+		return retcode;
+	}
+   	temp = I810_READ16(I810REG_INT_ENABLE_R);
+   	temp = temp & 0x6000;
+   	temp = temp | 0x0003;
+   	I810_WRITE16(I810REG_INT_ENABLE_R, 
+		     temp); /* Enable bp & user interrupts */
+	return 0;
+}
+
+int i810_irq_uninstall(drm_device_t *dev)
+{
+	int irq;
+   	u16 temp;
+
+
+/*  	return 0; */
+
+	down(&dev->struct_sem);
+	irq	 = dev->irq;
+	dev->irq = 0;
+	up(&dev->struct_sem);
+	
+	if (!irq) return -EINVAL;
+
+   	DRM_DEBUG(  "Interrupt UnInstall: %d\n", irq);	
+	DRM_DEBUG("%d\n", irq);
+   
+   	temp = I810_READ16(I810REG_INT_IDENTITY_R);
+   	temp = temp & ~(0x6000);
+   	if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, 
+				   temp); /* Clear all interrupts */
+   
+   	temp = I810_READ16(I810REG_INT_ENABLE_R);
+   	temp = temp & 0x6000;
+   	I810_WRITE16(I810REG_INT_ENABLE_R, 
+		     temp);                     /* Disable all interrupts */
+
+   	free_irq(irq, dev);
+
+	return 0;
+}
+
+int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_control_t	ctl;
+	int		retcode;
+   
+   	DRM_DEBUG(  "i810_control\n");
+
+	copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
+	
+	switch (ctl.func) {
+	case DRM_INST_HANDLER:
+		if ((retcode = i810_irq_install(dev, ctl.irq)))
+			return retcode;
+		break;
+	case DRM_UNINST_HANDLER:
+		if ((retcode = i810_irq_uninstall(dev)))
+			return retcode;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline void i810_dma_emit_flush(drm_device_t *dev)
+{
+   	drm_i810_private_t *dev_priv = dev->dev_private;
+   	RING_LOCALS;
+
+   	i810_kernel_lost_context(dev);
+
+   	BEGIN_LP_RING(2);
+      	OUT_RING( CMD_REPORT_HEAD );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+      	ADVANCE_LP_RING();
+
+/*  	i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */
+/*     	atomic_set(&dev_priv->flush_done, 1); */
+/*     	wake_up_interruptible(&dev_priv->flush_queue); */
+}
+
+static inline void i810_dma_quiescent_emit(drm_device_t *dev)
+{
+      	drm_i810_private_t *dev_priv = dev->dev_private;
+   	RING_LOCALS;
+
+  	i810_kernel_lost_context(dev);
+
+   	BEGIN_LP_RING(4);
+   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
+   	OUT_RING( CMD_REPORT_HEAD );
+      	OUT_RING( 0 );
+      	OUT_RING( GFX_OP_USER_INTERRUPT );
+   	ADVANCE_LP_RING();
+
+/*  	i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */
+/*     	atomic_set(&dev_priv->flush_done, 1); */
+/*     	wake_up_interruptible(&dev_priv->flush_queue); */
+}
+
+static void i810_dma_quiescent(drm_device_t *dev)
+{
+      	DECLARE_WAITQUEUE(entry, current);
+  	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	unsigned long end;      
+
+   	if(dev_priv == NULL) {
+	   	return;
+	}
+      	atomic_set(&dev_priv->flush_done, 0);
+   	current->state = TASK_INTERRUPTIBLE;
+   	add_wait_queue(&dev_priv->flush_queue, &entry);
+   	end = jiffies + (HZ*3);
+   
+   	for (;;) {
+	      	i810_dma_quiescent_emit(dev);
+	   	if (atomic_read(&dev_priv->flush_done) == 1) break;
+		if((signed)(end - jiffies) <= 0) {
+		   	DRM_ERROR("lockup\n");
+		   	break;
+		}	   
+	      	schedule_timeout(HZ*3);
+	      	if (signal_pending(current)) {
+		   	break;
+		}
+	}
+   
+   	current->state = TASK_RUNNING;
+   	remove_wait_queue(&dev_priv->flush_queue, &entry);
+   
+   	return;
+}
+
+static int i810_flush_queue(drm_device_t *dev)
+{
+   	DECLARE_WAITQUEUE(entry, current);
+  	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	unsigned long end;
+   	int i, ret = 0;      
+
+   	if(dev_priv == NULL) {
+	   	return 0;
+	}
+      	atomic_set(&dev_priv->flush_done, 0);
+   	current->state = TASK_INTERRUPTIBLE;
+   	add_wait_queue(&dev_priv->flush_queue, &entry);
+   	end = jiffies + (HZ*3);
+   	for (;;) {
+	      	i810_dma_emit_flush(dev);
+	   	if (atomic_read(&dev_priv->flush_done) == 1) break;
+		if((signed)(end - jiffies) <= 0) {
+		   	DRM_ERROR("lockup\n");
+		   	break;
+		}	   
+	      	schedule_timeout(HZ*3);
+	      	if (signal_pending(current)) {
+		   	ret = -EINTR; /* Can't restart */
+		   	break;
+		}
+	}
+   
+   	current->state = TASK_RUNNING;
+   	remove_wait_queue(&dev_priv->flush_queue, &entry);
+
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	   
+		int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE, 
+				   I810_BUF_FREE);
+
+		if (used == I810_BUF_HARDWARE)
+			DRM_DEBUG("reclaimed from HARDWARE\n");
+		if (used == I810_BUF_CLIENT)
+			DRM_DEBUG("still on client HARDWARE\n");
+	}
+
+   	return ret;
+}
+
+/* Must be called with the lock held */
+void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	if (!dma) return;
+      	if (!dev->dev_private) return;
+	if (!dma->buflist) return;
+
+        i810_flush_queue(dev);
+
+	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+	   
+		if (buf->pid == pid && buf_priv) {
+			int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, 
+					   I810_BUF_FREE);
+
+			if (used == I810_BUF_CLIENT)
+				DRM_DEBUG("reclaimed from client\n");
+		   	if(buf_priv->currently_mapped == I810_BUF_MAPPED)
+		     		buf_priv->currently_mapped = I810_BUF_UNMAPPED;
+		}
+	}
+}
+
+int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+
+	DECLARE_WAITQUEUE(entry, current);
+	int		  ret	= 0;
+	drm_lock_t	  lock;
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+   
+   	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+		  lock.context, current->pid, dev->lock.hw_lock->lock,
+		  lock.flags);
+
+	if (lock.context < 0) {
+		return -EINVAL;
+	}
+	/* Only one queue:
+	 */
+
+	if (!ret) {
+		add_wait_queue(&dev->lock.lock_queue, &entry);
+		for (;;) {
+			if (!dev->lock.hw_lock) {
+				/* Device has been unregistered */
+				ret = -EINTR;
+				break;
+			}
+			if (drm_lock_take(&dev->lock.hw_lock->lock,
+					  lock.context)) {
+				dev->lock.pid	    = current->pid;
+				dev->lock.lock_time = jiffies;
+				atomic_inc(&dev->total_locks);
+				break;	/* Got lock */
+			}
+			
+				/* Contention */
+			atomic_inc(&dev->total_sleeps);
+			current->state = TASK_INTERRUPTIBLE;
+		   	DRM_DEBUG("Calling lock schedule\n");
+			schedule();
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&dev->lock.lock_queue, &entry);
+	}
+	
+	if (!ret) {
+		if (lock.flags & _DRM_LOCK_QUIESCENT) {
+		   DRM_DEBUG("_DRM_LOCK_QUIESCENT\n");
+		   DRM_DEBUG("fred\n");
+		   i810_dma_quiescent(dev);
+		}
+	}
+	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+	return ret;
+}
+
+int i810_flush_ioctl(struct inode *inode, struct file *filp, 
+		     unsigned int cmd, unsigned long arg)
+{
+   	drm_file_t	  *priv	  = filp->private_data;
+   	drm_device_t	  *dev	  = priv->dev;
+   
+   	DRM_DEBUG("i810_flush_ioctl\n");
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_flush_ioctl called without lock held\n");
+		return -EINVAL;
+	}
+
+   	i810_flush_queue(dev);
+   	return 0;
+}
+
+
+int i810_dma_vertex(struct inode *inode, struct file *filp,
+	       unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+      	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+     					dev_priv->sarea_priv; 
+	drm_i810_vertex_t vertex;
+
+	copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex),
+			   -EFAULT);
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_dma_vertex called without lock held\n");
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
+		  vertex.idx, vertex.used, vertex.discard);
+
+	i810_dma_dispatch_vertex( dev, 
+				  dma->buflist[ vertex.idx ], 
+				  vertex.discard, vertex.used );
+
+   	atomic_add(vertex.used, &dma->total_bytes);
+	atomic_inc(&dma->total_dmas);
+	sarea_priv->last_enqueue = dev_priv->counter-1;
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+   
+	return 0;
+}
+
+
+
+int i810_clear_bufs(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_i810_clear_t clear;
+
+   	copy_from_user_ret(&clear, (drm_i810_clear_t *)arg, sizeof(clear), 
+			   -EFAULT);
+   
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_clear_bufs called without lock held\n");
+		return -EINVAL;
+	}
+
+	i810_dma_dispatch_clear( dev, clear.flags, 
+				 clear.clear_color, 
+				 clear.clear_depth );
+   	return 0;
+}
+
+int i810_swap_bufs(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+   
+	DRM_DEBUG("i810_swap_bufs\n");
+
+   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_swap_buf called without lock held\n");
+		return -EINVAL;
+	}
+
+	i810_dma_dispatch_swap( dev );
+   	return 0;
+}
+
+int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+   	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+      	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+     					dev_priv->sarea_priv; 
+
+      	sarea_priv->last_dispatch = (int) hw_status[5];
+	return 0;
+}
+
+int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	int		  retcode   = 0;
+	drm_i810_dma_t	  d;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+   	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+     					dev_priv->sarea_priv; 
+
+	DRM_DEBUG("getbuf\n");
+   	copy_from_user_ret(&d, (drm_i810_dma_t *)arg, sizeof(d), -EFAULT);
+   
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_dma called without lock held\n");
+		return -EINVAL;
+	}
+	
+	d.granted = 0;
+
+	retcode = i810_dma_get_buffer(dev, &d, filp);
+
+	DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
+		  current->pid, retcode, d.granted);
+
+	copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);   
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return retcode;
+}
+
+int i810_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	  *priv	    = filp->private_data;
+	drm_device_t	  *dev	    = priv->dev;
+	drm_i810_copy_t	  d;
+   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+   	u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+     					dev_priv->sarea_priv; 
+	drm_buf_t *buf;
+	drm_i810_buf_priv_t *buf_priv;
+	drm_device_dma_t *dma = dev->dma;
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("i810_dma called without lock held\n");
+		return -EINVAL;
+	}
+   
+   	copy_from_user_ret(&d, (drm_i810_copy_t *)arg, sizeof(d), -EFAULT);
+
+	if(d.idx > dma->buf_count) return -EINVAL;
+	buf = dma->buflist[ d.idx ];
+   	buf_priv = buf->dev_private;
+	if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM;
+
+   	copy_from_user_ret(buf_priv->virtual, d.address, d.used, -EFAULT);
+
+   	sarea_priv->last_dispatch = (int) hw_status[5];
+
+	return 0;
+}
+
+int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	if(VM_DONTCOPY == 0) return 1;
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/i810_drm.h linux.18p8/drivers/char/drm/i810_drm.h
--- linux.vanilla/drivers/char/drm/i810_drm.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/i810_drm.h	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,194 @@
+#ifndef _I810_DRM_H_
+#define _I810_DRM_H_
+
+/* WARNING: These defines must be the same as what the Xserver uses.
+ * if you change them, you must change the defines in the Xserver.
+ */
+
+#ifndef _I810_DEFINES_
+#define _I810_DEFINES_
+
+#define I810_DMA_BUF_ORDER		12
+#define I810_DMA_BUF_SZ 		(1<<I810_DMA_BUF_ORDER)
+#define I810_DMA_BUF_NR 		256
+#define I810_NR_SAREA_CLIPRECTS 	8
+
+/* Each region is a minimum of 64k, and there are at most 64 of them.
+ */
+#define I810_NR_TEX_REGIONS 64
+#define I810_LOG_MIN_TEX_REGION_SIZE 16
+#endif
+
+#define I810_UPLOAD_TEX0IMAGE  0x1 /* handled clientside */
+#define I810_UPLOAD_TEX1IMAGE  0x2 /* handled clientside */
+#define I810_UPLOAD_CTX        0x4
+#define I810_UPLOAD_BUFFERS    0x8
+#define I810_UPLOAD_TEX0       0x10
+#define I810_UPLOAD_TEX1       0x20
+#define I810_UPLOAD_CLIPRECTS  0x40
+
+
+/* Indices into buf.Setup where various bits of state are mirrored per
+ * context and per buffer.  These can be fired at the card as a unit,
+ * or in a piecewise fashion as required.
+ */
+
+/* Destbuffer state 
+ *    - backbuffer linear offset and pitch -- invarient in the current dri
+ *    - zbuffer linear offset and pitch -- also invarient
+ *    - drawing origin in back and depth buffers.
+ *
+ * Keep the depth/back buffer state here to acommodate private buffers
+ * in the future.
+ */
+#define I810_DESTREG_DI0  0	/* CMD_OP_DESTBUFFER_INFO (2 dwords) */
+#define I810_DESTREG_DI1  1
+#define I810_DESTREG_DV0  2	/* GFX_OP_DESTBUFFER_VARS (2 dwords) */
+#define I810_DESTREG_DV1  3
+#define I810_DESTREG_DR0  4	/* GFX_OP_DRAWRECT_INFO (4 dwords) */
+#define I810_DESTREG_DR1  5
+#define I810_DESTREG_DR2  6
+#define I810_DESTREG_DR3  7
+#define I810_DESTREG_DR4  8
+#define I810_DEST_SETUP_SIZE 10
+
+/* Context state
+ */
+#define I810_CTXREG_CF0   0	/* GFX_OP_COLOR_FACTOR */
+#define I810_CTXREG_CF1   1	
+#define I810_CTXREG_ST0   2     /* GFX_OP_STIPPLE */
+#define I810_CTXREG_ST1   3
+#define I810_CTXREG_VF    4	/* GFX_OP_VERTEX_FMT */
+#define I810_CTXREG_MT    5	/* GFX_OP_MAP_TEXELS */
+#define I810_CTXREG_MC0   6	/* GFX_OP_MAP_COLOR_STAGES - stage 0 */
+#define I810_CTXREG_MC1   7     /* GFX_OP_MAP_COLOR_STAGES - stage 1 */
+#define I810_CTXREG_MC2   8	/* GFX_OP_MAP_COLOR_STAGES - stage 2 */
+#define I810_CTXREG_MA0   9	/* GFX_OP_MAP_ALPHA_STAGES - stage 0 */
+#define I810_CTXREG_MA1   10	/* GFX_OP_MAP_ALPHA_STAGES - stage 1 */
+#define I810_CTXREG_MA2   11	/* GFX_OP_MAP_ALPHA_STAGES - stage 2 */
+#define I810_CTXREG_SDM   12	/* GFX_OP_SRC_DEST_MONO */
+#define I810_CTXREG_FOG   13	/* GFX_OP_FOG_COLOR */
+#define I810_CTXREG_B1    14	/* GFX_OP_BOOL_1 */
+#define I810_CTXREG_B2    15	/* GFX_OP_BOOL_2 */
+#define I810_CTXREG_LCS   16	/* GFX_OP_LINEWIDTH_CULL_SHADE_MODE */
+#define I810_CTXREG_PV    17	/* GFX_OP_PV_RULE -- Invarient! */
+#define I810_CTXREG_ZA    18	/* GFX_OP_ZBIAS_ALPHAFUNC */
+#define I810_CTXREG_AA    19	/* GFX_OP_ANTIALIAS */
+#define I810_CTX_SETUP_SIZE 20 
+
+/* Texture state (per tex unit)
+ */
+#define I810_TEXREG_MI0  0	/* GFX_OP_MAP_INFO (4 dwords) */
+#define I810_TEXREG_MI1  1	
+#define I810_TEXREG_MI2  2	
+#define I810_TEXREG_MI3  3	
+#define I810_TEXREG_MF   4	/* GFX_OP_MAP_FILTER */
+#define I810_TEXREG_MLC  5	/* GFX_OP_MAP_LOD_CTL */
+#define I810_TEXREG_MLL  6	/* GFX_OP_MAP_LOD_LIMITS */
+#define I810_TEXREG_MCS  7	/* GFX_OP_MAP_COORD_SETS ??? */
+#define I810_TEX_SETUP_SIZE 8
+
+#define I810_FRONT   0x1
+#define I810_BACK    0x2
+#define I810_DEPTH   0x4
+
+
+typedef struct _drm_i810_init {
+	enum {
+		I810_INIT_DMA = 0x01,
+		I810_CLEANUP_DMA = 0x02
+	} func;
+	int ring_map_idx;
+	int buffer_map_idx;
+	int sarea_priv_offset;
+	unsigned int ring_start;
+	unsigned int ring_end;
+	unsigned int ring_size;
+	unsigned int front_offset;
+	unsigned int back_offset;
+	unsigned int depth_offset;
+	unsigned int w;
+	unsigned int h;
+	unsigned int pitch;
+	unsigned int pitch_bits; 
+} drm_i810_init_t;
+
+/* Warning: If you change the SAREA structure you must change the Xserver
+ * structure as well */
+
+typedef struct _drm_i810_tex_region {
+	unsigned char next, prev; /* indices to form a circular LRU  */
+	unsigned char in_use;	/* owned by a client, or free? */
+	int age;		/* tracked by clients to update local LRU's */
+} drm_i810_tex_region_t;
+
+typedef struct _drm_i810_sarea {
+   	unsigned int ContextState[I810_CTX_SETUP_SIZE];
+   	unsigned int BufferState[I810_DEST_SETUP_SIZE];
+   	unsigned int TexState[2][I810_TEX_SETUP_SIZE];
+   	unsigned int dirty;
+
+	unsigned int nbox;
+	drm_clip_rect_t boxes[I810_NR_SAREA_CLIPRECTS];
+
+	/* Maintain an LRU of contiguous regions of texture space.  If
+	 * you think you own a region of texture memory, and it has an
+	 * age different to the one you set, then you are mistaken and
+	 * it has been stolen by another client.  If global texAge
+	 * hasn't changed, there is no need to walk the list.
+	 *
+	 * These regions can be used as a proxy for the fine-grained
+	 * texture information of other clients - by maintaining them
+	 * in the same lru which is used to age their own textures,
+	 * clients have an approximate lru for the whole of global
+	 * texture space, and can make informed decisions as to which
+	 * areas to kick out.  There is no need to choose whether to
+	 * kick out your own texture or someone else's - simply eject
+	 * them all in LRU order.  
+	 */
+   
+	drm_i810_tex_region_t texList[I810_NR_TEX_REGIONS+1]; 
+				/* Last elt is sentinal */
+        int texAge;		/* last time texture was uploaded */
+        int last_enqueue;	/* last time a buffer was enqueued */
+	int last_dispatch;	/* age of the most recently dispatched buffer */
+	int last_quiescent;     /*  */
+	int ctxOwner;		/* last context to upload state */
+
+	int vertex_prim;
+
+} drm_i810_sarea_t;
+
+typedef struct _drm_i810_clear {
+	int clear_color;
+	int clear_depth;
+	int flags;
+} drm_i810_clear_t;
+
+
+
+/* These may be placeholders if we have more cliprects than
+ * I810_NR_SAREA_CLIPRECTS.  In that case, the client sets discard to
+ * false, indicating that the buffer will be dispatched again with a
+ * new set of cliprects.
+ */
+typedef struct _drm_i810_vertex {
+   	int idx;		/* buffer index */
+	int used;		/* nr bytes in use */
+	int discard;		/* client is finished with the buffer? */
+} drm_i810_vertex_t;
+
+typedef struct _drm_i810_copy_t {
+   	int idx;		/* buffer index */
+	int used;		/* nr bytes in use */
+	void *address;		/* Address to copy from */
+} drm_i810_copy_t;
+
+typedef struct drm_i810_dma {
+	void *virtual;
+	int request_idx;
+	int request_size;
+	int granted;
+} drm_i810_dma_t;
+
+#endif /* _I810_DRM_H_ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/i810_drv.c linux.18p8/drivers/char/drm/i810_drv.c
--- linux.vanilla/drivers/char/drm/i810_drv.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/i810_drv.c	Fri Sep  1 14:14:35 2000
@@ -0,0 +1,653 @@
+/* i810_drv.c -- I810 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
+ * 
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "i810_drv.h"
+
+#include <linux/agp_backend.h>
+
+static __attribute__((unused)) void unused(void)
+{
+	agp_enable(0);
+}
+
+#define I810_NAME	 "i810"
+#define I810_DESC	 "Intel I810"
+#define I810_DATE	 "20000719"
+#define I810_MAJOR	 1
+#define I810_MINOR	 1
+#define I810_PATCHLEVEL	 0
+
+static drm_device_t	      i810_device;
+drm_ctx_t		      i810_res_ctx;
+
+static struct file_operations i810_fops = {
+#if LINUX_VERSION_CODE >= 0x020322
+				/* This started being used approx. 2.3.34 */
+	owner:   THIS_MODULE,
+#endif
+	open:	 i810_open,
+	flush:	 drm_flush,
+	release: i810_release,
+	ioctl:	 i810_ioctl,
+	mmap:	 drm_mmap,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+      	poll:	 drm_poll,
+};
+
+static struct miscdevice      i810_misc = {
+	minor: MISC_DYNAMIC_MINOR,
+	name:  I810_NAME,
+	fops:  &i810_fops,
+};
+
+static drm_ioctl_desc_t	      i810_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]     = { i810_version,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]  = { drm_getunique,  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]   = { drm_getmagic,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]   = { drm_irq_busid,  0, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)]  = { drm_setunique,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	      = { drm_block,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]     = { drm_unblock,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]     = { i810_control,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)]  = { drm_authmagic,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]     = { drm_addmap,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)]    = { i810_addbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]   = { i810_markbufs,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]   = { i810_infobufs,  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]   = { i810_freebufs,  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]     = { i810_addctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]      = { i810_rmctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]     = { i810_modctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]     = { i810_getctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]  = { i810_switchctx,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]     = { i810_newctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]     = { i810_resctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]    = { drm_adddraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]     = { drm_rmdraw,	  1, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	      = { i810_lock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]      = { i810_unlock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]      = { drm_finish,	  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]  = { drm_agp_enable,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]    = { drm_agp_info,    1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)]   = { drm_agp_alloc,   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)]    = { drm_agp_free,    1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)]    = { drm_agp_bind,    1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)]  = { drm_agp_unbind,  1, 1 },
+
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)]   = { i810_dma_init,   1, 1 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex, 1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_CLEAR)]  = { i810_clear_bufs, 1, 0 },
+      	[DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)]  = { i810_flush_ioctl,1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage,     1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf,     1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)]   = { i810_swap_bufs,  1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)]   = { i810_copybuf,    1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy,     1, 0 },
+};
+
+#define I810_IOCTL_COUNT DRM_ARRAY_SIZE(i810_ioctls)
+
+#ifdef MODULE
+static char		      *i810 = NULL;
+#endif
+
+MODULE_AUTHOR("VA Linux Systems, Inc.");
+MODULE_DESCRIPTION("Intel I810");
+MODULE_PARM(i810, "s");
+
+#ifndef MODULE
+/* i810_options is called by the kernel to parse command-line options
+ * passed via the boot-loader (e.g., LILO).  It calls the insmod option
+ * routine, drm_parse_drm.
+ */
+
+static int __init i810_options(char *str)
+{
+	drm_parse_options(str);
+	return 1;
+}
+
+__setup("i810=", i810_options);
+#endif
+
+static int i810_setup(drm_device_t *dev)
+{
+	int i;
+	
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use	  = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	drm_dma_setup(dev);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+#if DRM_DMA_HISTO
+	memset(&dev->histo, 0, sizeof(dev->histo));
+#endif
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+	
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+			
+	DRM_DEBUG("\n");
+			
+	/* The kernel's context could be created here, but is now created
+	   in drm_dma_enqueue.	This is more resource-efficient for
+	   hardware that does not do DMA, but may mean that
+	   drm_select_queue fails between the time the interrupt is
+	   initialized and the time the queues are initialized. */
+			
+	return 0;
+}
+
+
+static int i810_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	if (dev->irq) i810_irq_uninstall(dev);
+	
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+	
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+	
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+				/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+   				/* Clear AGP information */
+	if (dev->agp) {
+		drm_agp_mem_t *entry;
+		drm_agp_mem_t *nexte;
+		
+				/* Remove AGP resources, but leave dev->agp
+                                   intact until r128_cleanup is called. */
+		for (entry = dev->agp->memory; entry; entry = nexte) {
+			nexte = entry->next;
+			if (entry->bound) drm_unbind_agp(entry->memory);
+			drm_free_agp(entry->memory, entry->pages);
+			drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+		}
+		dev->agp->memory = NULL;
+		
+		if (dev->agp->acquired && drm_agp.release)
+			(*drm_agp.release)();
+		
+		dev->agp->acquired = 0;
+		dev->agp->enabled  = 0;
+	}
+				/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+	
+				/* Clear map area and mtrr information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+				if (map->mtrr >= 0) {
+					int retcode;
+					retcode = mtrr_del(map->mtrr,
+							   map->offset,
+							   map->size);
+					DRM_DEBUG("mtrr_del = %d\n", retcode);
+				}
+#endif
+				drm_ioremapfree(map->handle, map->size);
+				break;
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+			case _DRM_AGP:
+				break;
+			}
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+	
+	if (dev->queuelist) {
+		for (i = 0; i < dev->queue_count; i++) {
+			drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
+			if (dev->queuelist[i]) {
+				drm_free(dev->queuelist[i],
+					 sizeof(*dev->queuelist[0]),
+					 DRM_MEM_QUEUES);
+				dev->queuelist[i] = NULL;
+			}
+		}
+		drm_free(dev->queuelist,
+			 dev->queue_slots * sizeof(*dev->queuelist),
+			 DRM_MEM_QUEUES);
+		dev->queuelist	 = NULL;
+	}
+
+	drm_dma_takedown(dev);
+
+	dev->queue_count     = 0;
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+/* i810_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+static int i810_init(void)
+{
+	int		      retcode;
+	drm_device_t	      *dev = &i810_device;
+
+	DRM_DEBUG("\n");
+
+	memset((void *)dev, 0, sizeof(*dev));
+	dev->count_lock	  = SPIN_LOCK_UNLOCKED;
+	sema_init(&dev->struct_sem, 1);
+	
+#ifdef MODULE
+	drm_parse_options(i810);
+#endif
+	DRM_DEBUG("doing misc_register\n");
+	if ((retcode = misc_register(&i810_misc))) {
+		DRM_ERROR("Cannot register \"%s\"\n", I810_NAME);
+		return retcode;
+	}
+	dev->device = MKDEV(MISC_MAJOR, i810_misc.minor);
+	dev->name   = I810_NAME;
+
+   	DRM_DEBUG("doing mem init\n");
+	drm_mem_init();
+	DRM_DEBUG("doing proc init\n");
+	drm_proc_init(dev);
+	DRM_DEBUG("doing agp init\n");
+	dev->agp    = drm_agp_init();
+   	if(dev->agp == NULL) {
+	   	DRM_INFO("The i810 drm module requires the agpgart module"
+			 " to function correctly\nPlease load the agpgart"
+			 " module before you load the i810 module\n");
+	   	drm_proc_cleanup();
+	   	misc_deregister(&i810_misc);
+	   	i810_takedown(dev);
+	   	return -ENOMEM;
+	}
+	DRM_DEBUG("doing ctxbitmap init\n");
+	if((retcode = drm_ctxbitmap_init(dev))) {
+		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+		drm_proc_cleanup();
+		misc_deregister(&i810_misc);
+		i810_takedown(dev);
+		return retcode;
+	}
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+		 I810_NAME,
+		 I810_MAJOR,
+		 I810_MINOR,
+		 I810_PATCHLEVEL,
+		 I810_DATE,
+		 i810_misc.minor);
+
+	return 0;
+}
+
+/* i810_cleanup is called via cleanup_module at module unload time. */
+
+static void i810_cleanup(void)
+{
+	drm_device_t	      *dev = &i810_device;
+
+	DRM_DEBUG("\n");
+	
+	drm_proc_cleanup();
+	if (misc_deregister(&i810_misc)) {
+		DRM_ERROR("Cannot unload module\n");
+	} else {
+		DRM_INFO("Module unloaded\n");
+	}
+	drm_ctxbitmap_cleanup(dev);
+	i810_takedown(dev);
+	if (dev->agp) {
+		drm_agp_uninit();
+		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+		dev->agp = NULL;
+	}
+}
+
+module_init(i810_init);
+module_exit(i810_cleanup);
+
+
+int i810_version(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_version_t version;
+	int	      len;
+
+	copy_from_user_ret(&version,
+			   (drm_version_t *)arg,
+			   sizeof(version),
+			   -EFAULT);
+
+#define DRM_COPY(name,value)				     \
+	len = strlen(value);				     \
+	if (len > name##_len) len = name##_len;		     \
+	name##_len = strlen(value);			     \
+	if (len && name) {				     \
+		copy_to_user_ret(name, value, len, -EFAULT); \
+	}
+
+	version.version_major	   = I810_MAJOR;
+	version.version_minor	   = I810_MINOR;
+	version.version_patchlevel = I810_PATCHLEVEL;
+
+	DRM_COPY(version.name, I810_NAME);
+	DRM_COPY(version.date, I810_DATE);
+	DRM_COPY(version.desc, I810_DESC);
+
+	copy_to_user_ret((drm_version_t *)arg,
+			 &version,
+			 sizeof(version),
+			 -EFAULT);
+	return 0;
+}
+
+int i810_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t  *dev    = &i810_device;
+	int	      retcode = 0;
+	
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return i810_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	return retcode;
+}
+
+int i810_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev;
+	int	      retcode = 0;
+
+	lock_kernel();
+	dev    = priv->dev;
+	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+		  current->pid, dev->device, dev->open_count);
+
+	if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+	    && dev->lock.pid == current->pid) {
+	      	i810_reclaim_buffers(dev, priv->pid);
+		DRM_ERROR("Process %d dead, freeing lock for context %d\n",
+			  current->pid,
+			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+		drm_lock_free(dev,
+			      &dev->lock.hw_lock->lock,
+			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+		
+				/* FIXME: may require heavy-handed reset of
+                                   hardware at this point, possibly
+                                   processed via a callback to the X
+                                   server. */
+	} else if (dev->lock.hw_lock) {
+	   	/* The lock is required to reclaim buffers */
+	   	DECLARE_WAITQUEUE(entry, current);
+	   	add_wait_queue(&dev->lock.lock_queue, &entry);
+		for (;;) {
+			if (!dev->lock.hw_lock) {
+				/* Device has been unregistered */
+				retcode = -EINTR;
+				break;
+			}
+			if (drm_lock_take(&dev->lock.hw_lock->lock,
+					  DRM_KERNEL_CONTEXT)) {
+				dev->lock.pid	    = priv->pid;
+				dev->lock.lock_time = jiffies;
+				atomic_inc(&dev->total_locks);
+				break;	/* Got lock */
+			}			
+				/* Contention */
+			atomic_inc(&dev->total_sleeps);
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				retcode = -ERESTARTSYS;
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&dev->lock.lock_queue, &entry);
+	   	if(!retcode) {
+		   	i810_reclaim_buffers(dev, priv->pid);
+		   	drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				      DRM_KERNEL_CONTEXT);
+		}
+	}
+	drm_fasync(-1, filp, 0);
+
+	down(&dev->struct_sem);
+	if (priv->prev) priv->prev->next = priv->next;
+	else		dev->file_first	 = priv->next;
+	if (priv->next) priv->next->prev = priv->prev;
+	else		dev->file_last	 = priv->prev;
+	up(&dev->struct_sem);
+	
+	drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+#if LINUX_VERSION_CODE < 0x020333
+	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+   	atomic_inc(&dev->total_close);
+   	spin_lock(&dev->count_lock);
+   	if (!--dev->open_count) {
+	   	if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+		   	DRM_ERROR("Device busy: %d %d\n",
+				  atomic_read(&dev->ioctl_count),
+				  dev->blocked);
+		   	spin_unlock(&dev->count_lock);
+			unlock_kernel();
+		   	return -EBUSY;
+		}
+	   	spin_unlock(&dev->count_lock);
+		unlock_kernel();
+		return i810_takedown(dev);
+	}
+	spin_unlock(&dev->count_lock);
+	unlock_kernel();
+	return retcode;
+}
+
+/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int i810_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int		 retcode = 0;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+	
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= I810_IOCTL_COUNT) {
+		retcode = -EINVAL;
+	} else {
+		ioctl	  = &i810_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			retcode = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			retcode = -EACCES;
+		} else {
+			retcode = (func)(inode, filp, cmd, arg);
+		}
+	}
+	
+	atomic_dec(&dev->ioctl_count);
+	return retcode;
+}
+
+int i810_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+	
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+   	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+	if (!dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+#if DRM_DMA_HISTOGRAM
+	atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles()
+						       - dev->lck_start)]);
+#endif
+	
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/i810_drv.h linux.18p8/drivers/char/drm/i810_drv.h
--- linux.vanilla/drivers/char/drm/i810_drv.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/i810_drv.h	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,225 @@
+/* i810_drv.h -- Private header for the Matrox g200/g400 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ * 	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#ifndef _I810_DRV_H_
+#define _I810_DRV_H_
+
+typedef struct drm_i810_buf_priv {
+   	u32 *in_use;
+   	int my_use_idx;
+	int currently_mapped;
+	void *virtual;
+	void *kernel_virtual;
+	int map_count;
+   	struct vm_area_struct *vma;
+} drm_i810_buf_priv_t;
+
+typedef struct _drm_i810_ring_buffer{
+	int tail_mask;
+	unsigned long Start;
+	unsigned long End;
+	unsigned long Size;
+	u8 *virtual_start;
+	int head;
+	int tail;
+	int space;
+} drm_i810_ring_buffer_t;
+
+typedef struct drm_i810_private {
+   	int ring_map_idx;
+   	int buffer_map_idx;
+
+   	drm_i810_ring_buffer_t ring;
+	drm_i810_sarea_t *sarea_priv;
+
+      	unsigned long hw_status_page;
+   	unsigned long counter;
+
+   	atomic_t flush_done;
+   	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
+	drm_buf_t *mmap_buffer;
+
+	
+	u32 front_di1, back_di1, zi1;
+	
+	int back_offset;
+	int depth_offset;
+	int w, h;
+	int pitch;
+} drm_i810_private_t;
+
+				/* i810_drv.c */
+extern int  i810_version(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i810_open(struct inode *inode, struct file *filp);
+extern int  i810_release(struct inode *inode, struct file *filp);
+extern int  i810_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  i810_unlock(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+				/* i810_dma.c */
+extern int  i810_dma_schedule(drm_device_t *dev, int locked);
+extern int  i810_getbuf(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  i810_irq_install(drm_device_t *dev, int irq);
+extern int  i810_irq_uninstall(drm_device_t *dev);
+extern int  i810_control(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i810_lock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_dma_init(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i810_flush_ioctl(struct inode *inode, struct file *filp,
+			     unsigned int cmd, unsigned long arg);
+extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid);
+extern int  i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+			unsigned long arg);
+extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
+extern int i810_copybuf(struct inode *inode, struct file *filp, 
+			unsigned int cmd, unsigned long arg);
+extern int i810_docopy(struct inode *inode, struct file *filp, 
+		       unsigned int cmd, unsigned long arg);
+
+				/* i810_bufs.c */
+extern int  i810_addbufs(struct inode *inode, struct file *filp, 
+			unsigned int cmd, unsigned long arg);
+extern int  i810_infobufs(struct inode *inode, struct file *filp, 
+			 unsigned int cmd, unsigned long arg);
+extern int  i810_markbufs(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+extern int  i810_freebufs(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+extern int  i810_addmap(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+
+				/* i810_context.c */
+extern int  i810_resctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_addctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_modctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_getctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_switchctx(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  i810_newctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  i810_rmctx(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+
+extern int  i810_context_switch(drm_device_t *dev, int old, int new);
+extern int  i810_context_switch_complete(drm_device_t *dev, int new);
+
+#define I810_VERBOSE 0
+
+
+int i810_dma_vertex(struct inode *inode, struct file *filp,
+		    unsigned int cmd, unsigned long arg);
+
+int i810_swap_bufs(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg);
+
+int i810_clear_bufs(struct inode *inode, struct file *filp,
+		    unsigned int cmd, unsigned long arg);
+
+#define GFX_OP_USER_INTERRUPT 		((0<<29)|(2<<23))
+#define GFX_OP_BREAKPOINT_INTERRUPT	((0<<29)|(1<<23))
+#define CMD_REPORT_HEAD			(7<<23)
+#define CMD_STORE_DWORD_IDX		((0x21<<23) | 0x1)
+#define CMD_OP_BATCH_BUFFER  ((0x0<<29)|(0x30<<23)|0x1)
+
+#define INST_PARSER_CLIENT   0x00000000
+#define INST_OP_FLUSH        0x02000000
+#define INST_FLUSH_MAP_CACHE 0x00000001
+
+
+#define BB1_START_ADDR_MASK   (~0x7)
+#define BB1_PROTECTED         (1<<0)
+#define BB1_UNPROTECTED       (0<<0)
+#define BB2_END_ADDR_MASK     (~0x7)
+
+#define I810REG_HWSTAM		0x02098
+#define I810REG_INT_IDENTITY_R	0x020a4
+#define I810REG_INT_MASK_R 	0x020a8
+#define I810REG_INT_ENABLE_R	0x020a0
+
+#define LP_RING     		0x2030
+#define HP_RING     		0x2040
+#define RING_TAIL      		0x00
+#define TAIL_ADDR		0x000FFFF8
+#define RING_HEAD      		0x04
+#define HEAD_WRAP_COUNT     	0xFFE00000
+#define HEAD_WRAP_ONE       	0x00200000
+#define HEAD_ADDR           	0x001FFFFC
+#define RING_START     		0x08
+#define START_ADDR          	0x00FFFFF8
+#define RING_LEN       		0x0C
+#define RING_NR_PAGES       	0x000FF000 
+#define RING_REPORT_MASK    	0x00000006
+#define RING_REPORT_64K     	0x00000002
+#define RING_REPORT_128K    	0x00000004
+#define RING_NO_REPORT      	0x00000000
+#define RING_VALID_MASK     	0x00000001
+#define RING_VALID          	0x00000001
+#define RING_INVALID        	0x00000000
+
+#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19))
+#define SC_UPDATE_SCISSOR       (0x1<<1)
+#define SC_ENABLE_MASK          (0x1<<0)
+#define SC_ENABLE               (0x1<<0)
+
+#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1))
+#define SCI_YMIN_MASK      (0xffff<<16)
+#define SCI_XMIN_MASK      (0xffff<<0)
+#define SCI_YMAX_MASK      (0xffff<<16)
+#define SCI_XMAX_MASK      (0xffff<<0)
+
+#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
+#define GFX_OP_MAP_INFO          ((0x3<<29)|(0x1d<<24)|0x2)
+#define GFX_OP_DESTBUFFER_VARS   ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
+#define GFX_OP_DRAWRECT_INFO     ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+#define GFX_OP_PRIMITIVE         ((0x3<<29)|(0x1f<<24))
+
+#define CMD_OP_Z_BUFFER_INFO     ((0x0<<29)|(0x16<<23))
+#define CMD_OP_DESTBUFFER_INFO   ((0x0<<29)|(0x15<<23))
+
+#define BR00_BITBLT_CLIENT   0x40000000
+#define BR00_OP_COLOR_BLT    0x10000000
+#define BR00_OP_SRC_COPY_BLT 0x10C00000
+#define BR13_SOLID_PATTERN   0x80000000
+
+
+
+#endif
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/init.c linux.18p8/drivers/char/drm/init.c
--- linux.vanilla/drivers/char/drm/init.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/init.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,113 @@
+/* init.c -- Setup/Cleanup for DRM -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int			      drm_flags		= 0;
+
+/* drm_parse_option parses a single option.  See description for
+   drm_parse_options for details. */
+
+static void drm_parse_option(char *s)
+{
+	char *c, *r;
+	
+	DRM_DEBUG("\"%s\"\n", s);
+	if (!s || !*s) return;
+	for (c = s; *c && *c != ':'; c++); /* find : or \0 */
+	if (*c) r = c + 1; else r = NULL;  /* remember remainder */
+	*c = '\0';			   /* terminate */
+	if (!strcmp(s, "noctx")) {
+		drm_flags |= DRM_FLAG_NOCTX;
+		DRM_INFO("Server-mediated context switching OFF\n");
+		return;
+	}
+	if (!strcmp(s, "debug")) {
+		drm_flags |= DRM_FLAG_DEBUG;
+		DRM_INFO("Debug messages ON\n");
+		return;
+	}
+	DRM_ERROR("\"%s\" is not a valid option\n", s);
+	return;
+}
+
+/* drm_parse_options parse the insmod "drm=" options, or the command-line
+ * options passed to the kernel via LILO.  The grammar of the format is as
+ * follows:
+ *
+ * drm		::= 'drm=' option_list
+ * option_list	::= option [ ';' option_list ]
+ * option	::= 'device:' major
+ *		|   'debug' 
+ *		|   'noctx'
+ * major	::= INTEGER
+ *
+ * Note that 's' contains option_list without the 'drm=' part.
+ *
+ * device=major,minor specifies the device number used for /dev/drm
+ *	  if major == 0 then the misc device is used
+ *	  if major == 0 and minor == 0 then dynamic misc allocation is used
+ * debug=on specifies that debugging messages will be printk'd
+ * debug=trace specifies that each function call will be logged via printk
+ * debug=off turns off all debugging options
+ *
+ */
+
+void drm_parse_options(char *s)
+{
+	char *h, *t, *n;
+	
+	DRM_DEBUG("\"%s\"\n", s ?: "");
+	if (!s || !*s) return;
+
+	for (h = t = n = s; h && *h; h = n) {
+		for (; *t && *t != ';'; t++);	       /* find ; or \0 */
+		if (*t) n = t + 1; else n = NULL;      /* remember next */
+		*t = '\0';			       /* terminate */
+		drm_parse_option(h);		       /* parse */
+	}
+}
+
+/* drm_cpu_valid returns non-zero if the DRI will run on this CPU, and 0
+ * otherwise. */
+
+int drm_cpu_valid(void)
+{
+#if defined(__i386__)
+	if (boot_cpu_data.x86 == 3) return 0; /* No cmpxchg on a 386 */
+#endif
+#if defined(__sparc__) && !defined(__sparc_v9__)
+	if (1)
+		return 0; /* No cmpxchg before v9 sparc. */
+#endif
+	return 1;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/ioctl.c linux.18p8/drivers/char/drm/ioctl.c
--- linux.vanilla/drivers/char/drm/ioctl.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/ioctl.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,91 @@
+/* ioctl.c -- IOCTL processing for DRM -*- linux-c -*-
+ * Created: Fri Jan  8 09:01:26 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_irq_busid(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_irq_busid_t p;
+	struct pci_dev	*dev;
+
+	copy_from_user_ret(&p, (drm_irq_busid_t *)arg, sizeof(p), -EFAULT);
+	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
+	if (dev) p.irq = dev->irq;
+	else	 p.irq = 0;
+	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
+		  p.busnum, p.devnum, p.funcnum, p.irq);
+	copy_to_user_ret((drm_irq_busid_t *)arg, &p, sizeof(p), -EFAULT);
+	return 0;
+}
+
+int drm_getunique(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_unique_t	 u;
+
+	copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT);
+	if (u.unique_len >= dev->unique_len) {
+		copy_to_user_ret(u.unique, dev->unique, dev->unique_len,
+				 -EFAULT);
+	}
+	u.unique_len = dev->unique_len;
+	copy_to_user_ret((drm_unique_t *)arg, &u, sizeof(u), -EFAULT);
+	return 0;
+}
+
+int drm_setunique(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_unique_t	 u;
+
+	if (dev->unique_len || dev->unique) return -EBUSY;
+
+	copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT);
+	if (!u.unique_len) return -EINVAL;
+	
+	dev->unique_len = u.unique_len;
+	dev->unique	= drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
+	copy_from_user_ret(dev->unique, u.unique, dev->unique_len,
+			   -EFAULT);
+	dev->unique[dev->unique_len] = '\0';
+
+	dev->devname = drm_alloc(strlen(dev->name) + strlen(dev->unique) + 2,
+				 DRM_MEM_DRIVER);
+	sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/lists.c linux.18p8/drivers/char/drm/lists.c
--- linux.vanilla/drivers/char/drm/lists.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/lists.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,245 @@
+/* lists.c -- Buffer list handling routines -*- linux-c -*-
+ * Created: Mon Apr 19 20:54:22 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_waitlist_create(drm_waitlist_t *bl, int count)
+{
+	DRM_DEBUG("%d\n", count);
+	if (bl->count) return -EINVAL;
+	
+	bl->count      = count;
+	bl->bufs       = drm_alloc((bl->count + 2) * sizeof(*bl->bufs),
+				   DRM_MEM_BUFLISTS);
+	bl->rp	       = bl->bufs;
+	bl->wp	       = bl->bufs;
+	bl->end	       = &bl->bufs[bl->count+1];
+	bl->write_lock = SPIN_LOCK_UNLOCKED;
+	bl->read_lock  = SPIN_LOCK_UNLOCKED;
+	return 0;
+}
+
+int drm_waitlist_destroy(drm_waitlist_t *bl)
+{
+	DRM_DEBUG("\n");
+	if (bl->rp != bl->wp) return -EINVAL;
+	if (bl->bufs) drm_free(bl->bufs,
+			       (bl->count + 2) * sizeof(*bl->bufs),
+			       DRM_MEM_BUFLISTS);
+	bl->count = 0;
+	bl->bufs  = NULL;
+	bl->rp	  = NULL;
+	bl->wp	  = NULL;
+	bl->end	  = NULL;
+	return 0;
+}
+
+int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf)
+{							
+	int	      left;
+	unsigned long flags;
+
+	left = DRM_LEFTCOUNT(bl);
+	DRM_DEBUG("put %d (%d left, rp = %p, wp = %p)\n",
+		  buf->idx, left, bl->rp, bl->wp);
+	if (!left) {
+		DRM_ERROR("Overflow while adding buffer %d from pid %d\n",
+			  buf->idx, buf->pid);
+		return -EINVAL;
+	}
+#if DRM_DMA_HISTOGRAM
+	buf->time_queued = get_cycles();
+#endif
+	buf->list	 = DRM_LIST_WAIT;
+	
+	spin_lock_irqsave(&bl->write_lock, flags);
+	*bl->wp = buf;
+	if (++bl->wp >= bl->end) bl->wp = bl->bufs;
+	spin_unlock_irqrestore(&bl->write_lock, flags);
+	
+	return 0;
+}
+
+drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl)
+{
+	drm_buf_t     *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bl->read_lock, flags);
+	buf = *bl->rp;
+	if (bl->rp == bl->wp) {
+		spin_unlock_irqrestore(&bl->read_lock, flags);
+		return NULL;
+	}				     
+	if (++bl->rp >= bl->end) bl->rp = bl->bufs;
+	spin_unlock_irqrestore(&bl->read_lock, flags);
+	
+	DRM_DEBUG("get %d\n", buf->idx);
+	return buf;
+}
+
+int drm_freelist_create(drm_freelist_t *bl, int count)
+{
+	DRM_DEBUG("\n");
+	atomic_set(&bl->count, 0);
+	bl->next      = NULL;
+	init_waitqueue_head(&bl->waiting);
+	bl->low_mark  = 0;
+	bl->high_mark = 0;
+	atomic_set(&bl->wfh,   0);
+	++bl->initialized;
+	return 0;
+}
+
+int drm_freelist_destroy(drm_freelist_t *bl)
+{
+	DRM_DEBUG("\n");
+	atomic_set(&bl->count, 0);
+	bl->next = NULL;
+	return 0;
+}
+
+int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
+{
+	drm_buf_t        *old, *prev;
+	int		 count = 0;
+	drm_device_dma_t *dma  = dev->dma;
+
+	if (!dma) {
+		DRM_ERROR("No DMA support\n");
+		return 1;
+	}
+
+	if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) {
+		DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
+			  buf->idx, buf->waiting, buf->pending, buf->list);
+	}
+	DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
+		  buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
+		  buf->waiting, buf->pending);
+	if (!bl) return 1;
+#if DRM_DMA_HISTOGRAM
+	buf->time_freed = get_cycles();
+	drm_histogram_compute(dev, buf);
+#endif
+	buf->list	= DRM_LIST_FREE;
+	do {
+		old       = bl->next;
+		buf->next = old;
+		prev      = cmpxchg(&bl->next, old, buf);
+		if (++count > DRM_LOOPING_LIMIT) {
+			DRM_ERROR("Looping\n");
+			return 1;
+		}
+	} while (prev != old);
+	atomic_inc(&bl->count);
+	if (atomic_read(&bl->count) > dma->buf_count) {
+		DRM_ERROR("%d of %d buffers free after addition of %d\n",
+			  atomic_read(&bl->count), dma->buf_count, buf->idx);
+		return 1;
+	}
+				/* Check for high water mark */
+	if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) {
+		atomic_set(&bl->wfh, 0);
+		wake_up_interruptible(&bl->waiting);
+	}
+	return 0;
+}
+
+static drm_buf_t *drm_freelist_try(drm_freelist_t *bl)
+{
+	drm_buf_t         *old, *new, *prev;
+	drm_buf_t	  *buf;
+	int		  count = 0;
+
+	if (!bl) return NULL;
+	
+				/* Get buffer */
+	do {
+		old = bl->next;
+		if (!old) return NULL;
+		new  = bl->next->next;
+		prev = cmpxchg(&bl->next, old, new);
+		if (++count > DRM_LOOPING_LIMIT) {
+			DRM_ERROR("Looping\n");
+			return NULL;
+		}
+	} while (prev != old);
+	atomic_dec(&bl->count);
+	
+	buf	  = old;
+	buf->next = NULL;
+	buf->list = DRM_LIST_NONE;
+	DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
+		  buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
+		  buf->waiting, buf->pending);
+	if (buf->waiting || buf->pending) {
+		DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
+			  buf->idx, buf->waiting, buf->pending, buf->list);
+	}
+	
+	return buf;
+}
+
+drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block)
+{
+	drm_buf_t	  *buf	= NULL;
+	DECLARE_WAITQUEUE(entry, current);
+
+	if (!bl || !bl->initialized) return NULL;
+	
+				/* Check for low water mark */
+	if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
+		atomic_set(&bl->wfh, 1);
+	if (atomic_read(&bl->wfh)) {
+		DRM_DEBUG("Block = %d, count = %d, wfh = %d\n",
+			  block, atomic_read(&bl->count),
+			  atomic_read(&bl->wfh));
+		if (block) {
+			add_wait_queue(&bl->waiting, &entry);
+			current->state = TASK_INTERRUPTIBLE;
+			for (;;) {
+				if (!atomic_read(&bl->wfh)
+				    && (buf = drm_freelist_try(bl))) break;
+				schedule();
+				if (signal_pending(current)) break;
+			}
+			current->state = TASK_RUNNING;
+			remove_wait_queue(&bl->waiting, &entry);
+		}
+		return buf;
+	}
+		
+	DRM_DEBUG("Count = %d, wfh = %d\n",
+		  atomic_read(&bl->count), atomic_read(&bl->wfh));
+	return drm_freelist_try(bl);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/lock.c linux.18p8/drivers/char/drm/lock.c
--- linux.vanilla/drivers/char/drm/lock.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/lock.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,225 @@
+/* lock.c -- IOCTLs for locking -*- linux-c -*-
+ * Created: Tue Feb  2 08:37:54 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+int drm_block(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	DRM_DEBUG("\n");
+	return 0;
+}
+
+int drm_unblock(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	DRM_DEBUG("\n");
+	return 0;
+}
+
+int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
+{
+	unsigned int old, new, prev;
+
+	DRM_DEBUG("%d attempts\n", context);
+	do {
+		old = *lock;
+		if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
+		else			  new = context | _DRM_LOCK_HELD;
+		prev = cmpxchg(lock, old, new);
+	} while (prev != old);
+	if (_DRM_LOCKING_CONTEXT(old) == context) {
+		if (old & _DRM_LOCK_HELD) {
+			if (context != DRM_KERNEL_CONTEXT) {
+				DRM_ERROR("%d holds heavyweight lock\n",
+					  context);
+			}
+			return 0;
+		}
+	}
+	if (new == (context | _DRM_LOCK_HELD)) {
+				/* Have lock */
+		DRM_DEBUG("%d\n", context);
+		return 1;
+	}
+	DRM_DEBUG("%d unable to get lock held by %d\n",
+		  context, _DRM_LOCKING_CONTEXT(old));
+	return 0;
+}
+
+/* This takes a lock forcibly and hands it to context.	Should ONLY be used
+   inside *_unlock to give lock to kernel before calling *_dma_schedule. */
+int drm_lock_transfer(drm_device_t *dev,
+		      __volatile__ unsigned int *lock, unsigned int context)
+{
+	unsigned int old, new, prev;
+
+	dev->lock.pid = 0;
+	do {
+		old  = *lock;
+		new  = context | _DRM_LOCK_HELD;
+		prev = cmpxchg(lock, old, new);
+	} while (prev != old);
+	DRM_DEBUG("%d => %d\n", _DRM_LOCKING_CONTEXT(old), context);
+	return 1;
+}
+
+int drm_lock_free(drm_device_t *dev,
+		  __volatile__ unsigned int *lock, unsigned int context)
+{
+	unsigned int old, new, prev;
+	pid_t        pid = dev->lock.pid;
+
+	DRM_DEBUG("%d\n", context);
+	dev->lock.pid = 0;
+	do {
+		old  = *lock;
+		new  = 0;
+		prev = cmpxchg(lock, old, new);
+	} while (prev != old);
+	if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
+		DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n",
+			  context,
+			  _DRM_LOCKING_CONTEXT(old),
+			  pid);
+		return 1;
+	}
+	wake_up_interruptible(&dev->lock.lock_queue);
+	return 0;
+}
+
+static int drm_flush_queue(drm_device_t *dev, int context)
+{
+	DECLARE_WAITQUEUE(entry, current);
+	int		  ret	= 0;
+	drm_queue_t	  *q	= dev->queuelist[context];
+	
+	DRM_DEBUG("\n");
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) > 1) {
+		atomic_inc(&q->block_write);
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&q->flush_queue, &entry);
+		atomic_inc(&q->block_count);
+		for (;;) {
+			if (!DRM_BUFCOUNT(&q->waitlist)) break;
+			schedule();
+			if (signal_pending(current)) {
+				ret = -EINTR; /* Can't restart */
+				break;
+			}
+		}
+		atomic_dec(&q->block_count);
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&q->flush_queue, &entry);
+	}
+	atomic_dec(&q->use_count);
+	atomic_inc(&q->total_flushed);
+		
+				/* NOTE: block_write is still incremented!
+				   Use drm_flush_unlock_queue to decrement. */
+	return ret;
+}
+
+static int drm_flush_unblock_queue(drm_device_t *dev, int context)
+{
+	drm_queue_t	  *q	= dev->queuelist[context];
+	
+	DRM_DEBUG("\n");
+	
+	atomic_inc(&q->use_count);
+	if (atomic_read(&q->use_count) > 1) {
+		if (atomic_read(&q->block_write)) {
+			atomic_dec(&q->block_write);
+			wake_up_interruptible(&q->write_queue);
+		}
+	}
+	atomic_dec(&q->use_count);
+	return 0;
+}
+
+int drm_flush_block_and_flush(drm_device_t *dev, int context,
+			      drm_lock_flags_t flags)
+{
+	int ret = 0;
+	int i;
+	
+	DRM_DEBUG("\n");
+	
+	if (flags & _DRM_LOCK_FLUSH) {
+		ret = drm_flush_queue(dev, DRM_KERNEL_CONTEXT);
+		if (!ret) ret = drm_flush_queue(dev, context);
+	}
+	if (flags & _DRM_LOCK_FLUSH_ALL) {
+		for (i = 0; !ret && i < dev->queue_count; i++) {
+			ret = drm_flush_queue(dev, i);
+		}
+	}
+	return ret;
+}
+
+int drm_flush_unblock(drm_device_t *dev, int context, drm_lock_flags_t flags)
+{
+	int ret = 0;
+	int i;
+	
+	DRM_DEBUG("\n");
+	
+	if (flags & _DRM_LOCK_FLUSH) {
+		ret = drm_flush_unblock_queue(dev, DRM_KERNEL_CONTEXT);
+		if (!ret) ret = drm_flush_unblock_queue(dev, context);
+	}
+	if (flags & _DRM_LOCK_FLUSH_ALL) {
+		for (i = 0; !ret && i < dev->queue_count; i++) {
+			ret = drm_flush_unblock_queue(dev, i);
+		}
+	}
+		
+	return ret;
+}
+
+int drm_finish(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	int		  ret	  = 0;
+	drm_lock_t	  lock;
+
+	DRM_DEBUG("\n");
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+	ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+	drm_flush_unblock(dev, lock.context, lock.flags);
+	return ret;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/memory.c linux.18p8/drivers/char/drm/memory.c
--- linux.vanilla/drivers/char/drm/memory.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/memory.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,449 @@
+/* memory.c -- Memory management wrappers for DRM -*- linux-c -*-
+ * Created: Thu Feb  4 14:00:34 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "drmP.h"
+
+typedef struct drm_mem_stats {
+	const char	  *name;
+	int		  succeed_count;
+	int		  free_count;
+	int		  fail_count;
+	unsigned long	  bytes_allocated;
+	unsigned long	  bytes_freed;
+} drm_mem_stats_t;
+
+static spinlock_t	  drm_mem_lock	    = SPIN_LOCK_UNLOCKED;
+static unsigned long	  drm_ram_available = 0; /* In pages */
+static unsigned long	  drm_ram_used	    = 0;
+static drm_mem_stats_t	  drm_mem_stats[]   = {
+	[DRM_MEM_DMA]	    = { "dmabufs"  },
+	[DRM_MEM_SAREA]	    = { "sareas"   },
+	[DRM_MEM_DRIVER]    = { "driver"   },
+	[DRM_MEM_MAGIC]	    = { "magic"	   },
+	[DRM_MEM_IOCTLS]    = { "ioctltab" },
+	[DRM_MEM_MAPS]	    = { "maplist"  },
+	[DRM_MEM_VMAS]	    = { "vmalist"  },
+	[DRM_MEM_BUFS]	    = { "buflist"  },
+	[DRM_MEM_SEGS]	    = { "seglist"  },
+	[DRM_MEM_PAGES]	    = { "pagelist" },
+	[DRM_MEM_FILES]	    = { "files"	   },
+	[DRM_MEM_QUEUES]    = { "queues"   },
+	[DRM_MEM_CMDS]	    = { "commands" },
+	[DRM_MEM_MAPPINGS]  = { "mappings" },
+	[DRM_MEM_BUFLISTS]  = { "buflists" },
+	[DRM_MEM_AGPLISTS]  = { "agplist"  },
+	[DRM_MEM_TOTALAGP]  = { "totalagp" },
+	[DRM_MEM_BOUNDAGP]  = { "boundagp" },
+	[DRM_MEM_CTXBITMAP] = { "ctxbitmap"},
+	{ NULL, 0, }		/* Last entry must be null */
+};
+
+void drm_mem_init(void)
+{
+	drm_mem_stats_t *mem;
+	struct sysinfo	si;
+	
+	for (mem = drm_mem_stats; mem->name; ++mem) {
+		mem->succeed_count   = 0;
+		mem->free_count	     = 0;
+		mem->fail_count	     = 0;
+		mem->bytes_allocated = 0;
+		mem->bytes_freed     = 0;
+	}
+	
+	si_meminfo(&si);
+#if LINUX_VERSION_CODE < 0x020317
+				/* Changed to page count in 2.3.23 */
+	drm_ram_available = si.totalram >> PAGE_SHIFT;
+#else
+	drm_ram_available = si.totalram;
+#endif
+	drm_ram_used	  = 0;
+}
+
+/* drm_mem_info is called whenever a process reads /dev/drm/mem. */
+
+static int _drm_mem_info(char *buf, char **start, off_t offset, int len,
+			 int *eof, void *data)
+{
+	drm_mem_stats_t *pt;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("		  total counts			"
+		       " |    outstanding  \n");
+	DRM_PROC_PRINT("type	   alloc freed fail	bytes	   freed"
+		       " | allocs      bytes\n\n");
+	DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB         |\n",
+		       "system", 0, 0, 0,
+		       drm_ram_available << (PAGE_SHIFT - 10));
+	DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB         |\n",
+		       "locked", 0, 0, 0, drm_ram_used >> 10);
+	DRM_PROC_PRINT("\n");
+	for (pt = drm_mem_stats; pt->name; pt++) {
+		DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n",
+			       pt->name,
+			       pt->succeed_count,
+			       pt->free_count,
+			       pt->fail_count,
+			       pt->bytes_allocated,
+			       pt->bytes_freed,
+			       pt->succeed_count - pt->free_count,
+			       (long)pt->bytes_allocated
+			       - (long)pt->bytes_freed);
+	}
+	
+	return len;
+}
+
+int drm_mem_info(char *buf, char **start, off_t offset, int len,
+		 int *eof, void *data)
+{
+	int ret;
+	
+	spin_lock(&drm_mem_lock);
+	ret = _drm_mem_info(buf, start, offset, len, eof, data);
+	spin_unlock(&drm_mem_lock);
+	return ret;
+}
+
+void *drm_alloc(size_t size, int area)
+{
+	void *pt;
+	
+	if (!size) {
+		DRM_MEM_ERROR(area, "Allocating 0 bytes\n");
+		return NULL;
+	}
+	
+	if (!(pt = kmalloc(size, GFP_KERNEL))) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[area].fail_count;
+		spin_unlock(&drm_mem_lock);
+		return NULL;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[area].succeed_count;
+	drm_mem_stats[area].bytes_allocated += size;
+	spin_unlock(&drm_mem_lock);
+	return pt;
+}
+
+void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
+{
+	void *pt;
+	
+	if (!(pt = drm_alloc(size, area))) return NULL;
+	if (oldpt && oldsize) {
+		memcpy(pt, oldpt, oldsize);
+		drm_free(oldpt, oldsize, area);
+	}
+	return pt;
+}
+
+char *drm_strdup(const char *s, int area)
+{
+	char *pt;
+	int	 length = s ? strlen(s) : 0;
+	
+	if (!(pt = drm_alloc(length+1, area))) return NULL;
+	strcpy(pt, s);
+	return pt;
+}
+
+void drm_strfree(const char *s, int area)
+{
+	unsigned int size;
+	
+	if (!s) return;
+	
+	size = 1 + (s ? strlen(s) : 0);
+	drm_free((void *)s, size, area);
+}
+
+void drm_free(void *pt, size_t size, int area)
+{
+	int alloc_count;
+	int free_count;
+	
+	if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n");
+	else	 kfree(pt);
+	spin_lock(&drm_mem_lock);
+	drm_mem_stats[area].bytes_freed += size;
+	free_count  = ++drm_mem_stats[area].free_count;
+	alloc_count =	drm_mem_stats[area].succeed_count;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+}
+
+unsigned long drm_alloc_pages(int order, int area)
+{
+	unsigned long address;
+	unsigned long bytes	  = PAGE_SIZE << order;
+	unsigned long addr;
+	unsigned int  sz;
+	
+	spin_lock(&drm_mem_lock);
+	if ((drm_ram_used >> PAGE_SHIFT)
+	    > (DRM_RAM_PERCENT * drm_ram_available) / 100) {
+		spin_unlock(&drm_mem_lock);
+		return 0;
+	}
+	spin_unlock(&drm_mem_lock);
+	
+	address = __get_free_pages(GFP_KERNEL, order);
+	if (!address) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[area].fail_count;
+		spin_unlock(&drm_mem_lock);
+		return 0;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[area].succeed_count;
+	drm_mem_stats[area].bytes_allocated += bytes;
+	drm_ram_used		            += bytes;
+	spin_unlock(&drm_mem_lock);
+	
+	
+				/* Zero outside the lock */
+	memset((void *)address, 0, bytes);
+	
+				/* Reserve */
+	for (addr = address, sz = bytes;
+	     sz > 0;
+	     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+		mem_map_reserve(MAP_NR(addr));
+	}
+	
+	return address;
+}
+
+void drm_free_pages(unsigned long address, int order, int area)
+{
+	unsigned long bytes = PAGE_SIZE << order;
+	int		  alloc_count;
+	int		  free_count;
+	unsigned long addr;
+	unsigned int  sz;
+	
+	if (!address) {
+		DRM_MEM_ERROR(area, "Attempt to free address 0\n");
+	} else {
+				/* Unreserve */
+		for (addr = address, sz = bytes;
+		     sz > 0;
+		     addr += PAGE_SIZE, sz -= PAGE_SIZE) {
+			mem_map_unreserve(MAP_NR(addr));
+		}
+		free_pages(address, order);
+	}
+	
+	spin_lock(&drm_mem_lock);
+	free_count  = ++drm_mem_stats[area].free_count;
+	alloc_count =	drm_mem_stats[area].succeed_count;
+	drm_mem_stats[area].bytes_freed += bytes;
+	drm_ram_used			-= bytes;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(area,
+			      "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+}
+
+void *drm_ioremap(unsigned long offset, unsigned long size)
+{
+	void *pt;
+	
+	if (!size) {
+		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+			      "Mapping 0 bytes at 0x%08lx\n", offset);
+		return NULL;
+	}
+	
+	if (!(pt = ioremap(offset, size))) {
+		spin_lock(&drm_mem_lock);
+		++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
+		spin_unlock(&drm_mem_lock);
+		return NULL;
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+	drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
+	spin_unlock(&drm_mem_lock);
+	return pt;
+}
+
+void drm_ioremapfree(void *pt, unsigned long size)
+{
+	int alloc_count;
+	int free_count;
+	
+	if (!pt)
+		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+			      "Attempt to free NULL pointer\n");
+	else
+		iounmap(pt);
+	
+	spin_lock(&drm_mem_lock);
+	drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
+	free_count  = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
+	alloc_count =	drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
+	spin_unlock(&drm_mem_lock);
+	if (free_count > alloc_count) {
+		DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
+			      "Excess frees: %d frees, %d allocs\n",
+			      free_count, alloc_count);
+	}
+}
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+agp_memory *drm_alloc_agp(int pages, u32 type)
+{
+	agp_memory *handle;
+
+	if (!pages) {
+		DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n");
+		return NULL;
+	}
+	
+	if (drm_agp.allocate_memory) {
+		if ((handle = (*drm_agp.allocate_memory)(pages,
+							 type))) {
+			spin_lock(&drm_mem_lock);
+			++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
+			drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated
+				+= pages << PAGE_SHIFT;
+			spin_unlock(&drm_mem_lock);
+			return handle;
+		}
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count;
+	spin_unlock(&drm_mem_lock);
+	return NULL;
+}
+
+int drm_free_agp(agp_memory *handle, int pages)
+{
+	int           alloc_count;
+	int           free_count;
+	int           retval = -EINVAL;
+
+	if (!handle) {
+		DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
+			      "Attempt to free NULL AGP handle\n");
+		return retval;;
+	}
+	
+	if (drm_agp.free_memory) {
+		(*drm_agp.free_memory)(handle);
+		spin_lock(&drm_mem_lock);
+		free_count  = ++drm_mem_stats[DRM_MEM_TOTALAGP].free_count;
+		alloc_count =   drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count;
+		drm_mem_stats[DRM_MEM_TOTALAGP].bytes_freed
+			+= pages << PAGE_SHIFT;
+		spin_unlock(&drm_mem_lock);
+		if (free_count > alloc_count) {
+			DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
+				      "Excess frees: %d frees, %d allocs\n",
+				      free_count, alloc_count);
+		}
+		return 0;
+	}
+	return retval;
+}
+
+int drm_bind_agp(agp_memory *handle, unsigned int start)
+{
+	int retcode = -EINVAL;
+
+   DRM_DEBUG("drm_bind_agp called\n");
+	if (!handle) {
+		DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+			      "Attempt to bind NULL AGP handle\n");
+		return retcode;
+	}
+
+   DRM_DEBUG("drm_agp.bind_memory : %p\n", drm_agp.bind_memory);
+	if (drm_agp.bind_memory) {
+		if (!(retcode = (*drm_agp.bind_memory)(handle, start))) {
+			spin_lock(&drm_mem_lock);
+			++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
+			drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated
+				+= handle->page_count << PAGE_SHIFT;
+			spin_unlock(&drm_mem_lock);
+		   DRM_DEBUG("drm_agp.bind_memory: retcode %d\n", retcode);
+			return retcode;
+		}
+	}
+	spin_lock(&drm_mem_lock);
+	++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count;
+	spin_unlock(&drm_mem_lock);
+	return retcode;
+}
+
+int drm_unbind_agp(agp_memory *handle)
+{
+	int alloc_count;
+	int free_count;
+	int retcode = -EINVAL;
+	
+	if (!handle) {
+		DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+			      "Attempt to unbind NULL AGP handle\n");
+		return retcode;
+	}
+
+	if (drm_agp.unbind_memory) {
+		int c = handle->page_count;
+		if ((retcode = (*drm_agp.unbind_memory)(handle)))
+			return retcode;
+		spin_lock(&drm_mem_lock);
+		free_count  = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count;
+		alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count;
+		drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed += c << PAGE_SHIFT;
+		spin_unlock(&drm_mem_lock);
+		if (free_count > alloc_count) {
+			DRM_MEM_ERROR(DRM_MEM_BOUNDAGP,
+				      "Excess frees: %d frees, %d allocs\n",
+				      free_count, alloc_count);
+		}
+	}
+	return retcode;
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/mga_bufs.c linux.18p8/drivers/char/drm/mga_bufs.c
--- linux.vanilla/drivers/char/drm/mga_bufs.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/mga_bufs.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,639 @@
+/* mga_bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Thu Jan 6 01:47:26 2000 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "mga_drv.h"
+#include "linux/un.h"
+
+
+int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_desc_t request;
+	drm_buf_entry_t *entry;
+	drm_buf_t *buf;
+	unsigned long offset;
+	unsigned long agp_offset;
+	int count;
+	int order;
+	int size;
+	int alignment;
+	int page_order;
+	int total;
+	int byte_count;
+	int i;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	count = request.count;
+	order = drm_order(request.size);
+	size	= 1 << order;
+	agp_offset = request.agp_start;
+	alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total = PAGE_SIZE << page_order;
+	byte_count = 0;
+
+	DRM_DEBUG("count: %d\n", count);
+	DRM_DEBUG("order: %d\n", order);
+	DRM_DEBUG("size: %d\n", size);
+	DRM_DEBUG("agp_offset: %ld\n", agp_offset);
+	DRM_DEBUG("alignment: %d\n", alignment);
+	DRM_DEBUG("page_order: %d\n", page_order);
+	DRM_DEBUG("total: %d\n", total);
+	DRM_DEBUG("byte_count: %d\n", byte_count);
+
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+   
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM; /* May only call once for each order */
+	}
+   
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+   
+	entry->buf_size   = size;
+	entry->page_order = page_order;
+	offset = 0;
+
+   
+	while(entry->buf_count < count) {
+		buf = &entry->buflist[entry->buf_count];
+		buf->idx = dma->buf_count + entry->buf_count;
+		buf->total = alignment;
+		buf->order = order;
+		buf->used = 0;
+
+		DRM_DEBUG("offset : %ld\n", offset);
+
+		buf->offset = offset; /* Hrm */
+		buf->bus_address = dev->agp->base + agp_offset + offset;
+		buf->address = (void *)(agp_offset + offset + dev->agp->base);
+		buf->next = NULL;
+		buf->waiting = 0;
+		buf->pending = 0;
+		init_waitqueue_head(&buf->dma_wait);
+		buf->pid = 0;
+
+		buf->dev_private = drm_alloc(sizeof(drm_mga_buf_priv_t), DRM_MEM_BUFS);
+		buf->dev_priv_size = sizeof(drm_mga_buf_priv_t);
+
+#if DRM_DMA_HISTOGRAM
+		buf->time_queued = 0;
+		buf->time_dispatched = 0;
+		buf->time_completed = 0;
+		buf->time_freed = 0;
+#endif
+		offset = offset + alignment;
+		entry->buf_count++;
+		byte_count += PAGE_SIZE << page_order;
+      
+		DRM_DEBUG("buffer %d @ %p\n",
+			  entry->buf_count, buf->address);
+	}
+   
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+   
+	dma->buf_count  += entry->buf_count;
+
+	DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
+
+	dma->byte_count += byte_count;
+
+	DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
+
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+   
+	up(&dev->struct_sem);
+   
+	request.count = entry->buf_count;
+	request.size  = size;
+   
+	copy_to_user_ret((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+   
+	atomic_dec(&dev->buf_alloc);
+
+	DRM_DEBUG("count: %d\n", count);
+	DRM_DEBUG("order: %d\n", order);
+	DRM_DEBUG("size: %d\n", size);
+	DRM_DEBUG("agp_offset: %ld\n", agp_offset);
+	DRM_DEBUG("alignment: %d\n", alignment);
+	DRM_DEBUG("page_order: %d\n", page_order);
+	DRM_DEBUG("total: %d\n", total);
+	DRM_DEBUG("byte_count: %d\n", byte_count);
+
+	dma->flags = _DRM_DMA_USE_AGP;
+
+	DRM_DEBUG("dma->flags : %x\n", dma->flags);
+
+	return 0;
+}
+
+int mga_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+   	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 count;
+	int		 order;
+	int		 size;
+	int		 total;
+	int		 page_order;
+	drm_buf_entry_t	 *entry;
+	unsigned long	 page;
+	drm_buf_t	 *buf;
+	int		 alignment;
+	unsigned long	 offset;
+	int		 i;
+	int		 byte_count;
+	int		 page_count;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	count	   = request.count;
+	order	   = drm_order(request.size);
+	size	   = 1 << order;
+	
+	DRM_DEBUG("count = %d, size = %d (%d), order = %d, queue_count = %d\n",
+		  request.count, request.size, size, order, dev->queue_count);
+
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+
+	alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total	   = PAGE_SIZE << page_order;
+
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+	
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;	/* May only call once for each order */
+	}
+	
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+
+	entry->seglist = drm_alloc(count * sizeof(*entry->seglist),
+				   DRM_MEM_SEGS);
+	if (!entry->seglist) {
+		drm_free(entry->buflist,
+			 count * sizeof(*entry->buflist),
+			 DRM_MEM_BUFS);
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->seglist, 0, count * sizeof(*entry->seglist));
+
+	dma->pagelist = drm_realloc(dma->pagelist,
+				    dma->page_count * sizeof(*dma->pagelist),
+				    (dma->page_count + (count << page_order))
+				    * sizeof(*dma->pagelist),
+				    DRM_MEM_PAGES);
+	DRM_DEBUG("pagelist: %d entries\n",
+		  dma->page_count + (count << page_order));
+
+
+	entry->buf_size	  = size;
+	entry->page_order = page_order;
+	byte_count	  = 0;
+	page_count	  = 0;
+	while (entry->buf_count < count) {
+		if (!(page = drm_alloc_pages(page_order, DRM_MEM_DMA))) break;
+		entry->seglist[entry->seg_count++] = page;
+		for (i = 0; i < (1 << page_order); i++) {
+			DRM_DEBUG("page %d @ 0x%08lx\n",
+				  dma->page_count + page_count,
+				  page + PAGE_SIZE * i);
+			dma->pagelist[dma->page_count + page_count++]
+				= page + PAGE_SIZE * i;
+		}
+		for (offset = 0;
+		     offset + size <= total && entry->buf_count < count;
+		     offset += alignment, ++entry->buf_count) {
+			buf	     = &entry->buflist[entry->buf_count];
+			buf->idx     = dma->buf_count + entry->buf_count;
+			buf->total   = alignment;
+			buf->order   = order;
+			buf->used    = 0;
+			buf->offset  = (dma->byte_count + byte_count + offset);
+			buf->address = (void *)(page + offset);
+			buf->next    = NULL;
+			buf->waiting = 0;
+			buf->pending = 0;
+			init_waitqueue_head(&buf->dma_wait);
+			buf->pid     = 0;
+#if DRM_DMA_HISTOGRAM
+			buf->time_queued     = 0;
+			buf->time_dispatched = 0;
+			buf->time_completed  = 0;
+			buf->time_freed	     = 0;
+#endif
+			DRM_DEBUG("buffer %d @ %p\n",
+				  entry->buf_count, buf->address);
+		}
+		byte_count += PAGE_SIZE << page_order;
+	}
+
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+
+	dma->buf_count	+= entry->buf_count;
+	dma->seg_count	+= entry->seg_count;
+	dma->page_count += entry->seg_count << page_order;
+	dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
+	
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+	
+	up(&dev->struct_sem);
+
+	request.count = entry->buf_count;
+	request.size  = size;
+
+	copy_to_user_ret((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+	
+	atomic_dec(&dev->buf_alloc);
+	return 0;
+}
+
+int mga_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_buf_desc_t	 request;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	if(request.flags & _DRM_AGP_BUFFER)
+		return mga_addbufs_agp(inode, filp, cmd, arg);
+	else
+		return mga_addbufs_pci(inode, filp, cmd, arg);
+}
+
+int mga_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_info_t	 request;
+	int		 i;
+	int		 count;
+
+	if (!dma) return -EINVAL;
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	copy_from_user_ret(&request,
+			   (drm_buf_info_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+		if (dma->bufs[i].buf_count) ++count;
+	}
+	
+	DRM_DEBUG("count = %d\n", count);
+	
+	if (request.count >= count) {
+		for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
+			if (dma->bufs[i].buf_count) {
+				copy_to_user_ret(&request.list[count].count,
+						 &dma->bufs[i].buf_count,
+						 sizeof(dma->bufs[0]
+							.buf_count),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count].size,
+						 &dma->bufs[i].buf_size,
+						 sizeof(dma->bufs[0].buf_size),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count].low_mark,
+						 &dma->bufs[i]
+						 .freelist.low_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.low_mark),
+						 -EFAULT);
+				copy_to_user_ret(&request.list[count]
+						 .high_mark,
+						 &dma->bufs[i]
+						 .freelist.high_mark,
+						 sizeof(dma->bufs[0]
+							.freelist.high_mark),
+						 -EFAULT);
+				DRM_DEBUG("%d %d %d %d %d\n",
+					  i,
+					  dma->bufs[i].buf_count,
+					  dma->bufs[i].buf_size,
+					  dma->bufs[i].freelist.low_mark,
+					  dma->bufs[i].freelist.high_mark);
+				++count;
+			}
+		}
+	}
+	request.count = count;
+
+	copy_to_user_ret((drm_buf_info_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+	
+	return 0;
+}
+
+int mga_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_desc_t	 request;
+	int		 order;
+	drm_buf_entry_t	 *entry;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	DRM_DEBUG("%d, %d, %d\n",
+		  request.size, request.low_mark, request.high_mark);
+	order = drm_order(request.size);
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	entry = &dma->bufs[order];
+
+	if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+		return -EINVAL;
+	if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+		return -EINVAL;
+
+	entry->freelist.low_mark  = request.low_mark;
+	entry->freelist.high_mark = request.high_mark;
+	
+	return 0;
+}
+
+int mga_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	drm_buf_free_t	 request;
+	int		 i;
+	int		 idx;
+	drm_buf_t	 *buf;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_free_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	DRM_DEBUG("%d\n", request.count);
+	for (i = 0; i < request.count; i++) {
+		copy_from_user_ret(&idx,
+				   &request.list[i],
+				   sizeof(idx),
+				   -EFAULT);
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  idx, dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[idx];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d freeing buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		drm_free_buffer(dev, buf);
+	}
+	
+	return 0;
+}
+
+int mga_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	int		 retcode = 0;
+	const int	 zero	 = 0;
+	unsigned long	 virtual;
+	unsigned long	 address;
+	drm_buf_map_t	 request;
+	int		 i;
+
+	if (!dma) return -EINVAL;
+	
+	DRM_DEBUG("\n");
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		DRM_DEBUG("Busy\n");
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	copy_from_user_ret(&request,
+			   (drm_buf_map_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	DRM_DEBUG("mga_mapbufs\n");
+   	DRM_DEBUG("dma->flags : %x\n", dma->flags);
+   
+	if (request.count >= dma->buf_count) {
+		if(dma->flags & _DRM_DMA_USE_AGP) {
+			drm_mga_private_t *dev_priv = dev->dev_private;
+			drm_map_t *map = NULL;
+	 
+			map = dev->maplist[dev_priv->buffer_map_idx];
+			if (!map) {
+				DRM_DEBUG("map is null\n");
+				retcode = -EINVAL;
+				goto done;
+			}
+
+			DRM_DEBUG("map->offset : %lx\n", map->offset);
+			DRM_DEBUG("map->size : %lx\n", map->size);
+			DRM_DEBUG("map->type : %d\n", map->type);
+			DRM_DEBUG("map->flags : %x\n", map->flags);
+			DRM_DEBUG("map->handle : %p\n", map->handle);
+			DRM_DEBUG("map->mtrr : %d\n", map->mtrr);
+			down(&current->mm->mmap_sem);
+			virtual = do_mmap(filp, 0, map->size, 
+					  PROT_READ|PROT_WRITE,
+					  MAP_SHARED, 
+					  (unsigned long)map->offset);
+			up(&current->mm->mmap_sem);
+		} else {
+			down(&current->mm->mmap_sem);
+			virtual = do_mmap(filp, 0, dma->byte_count,
+					  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+			up(&current->mm->mmap_sem);
+		}
+		if (virtual > -1024UL) {
+			/* Real error */
+			DRM_DEBUG("mmap error\n");
+			retcode = (signed long)virtual;
+			goto done;
+		}
+		request.virtual = (void *)virtual;
+      
+		for (i = 0; i < dma->buf_count; i++) {
+			if (copy_to_user(&request.list[i].idx,
+					 &dma->buflist[i]->idx,
+					 sizeof(request.list[0].idx))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].total,
+					 &dma->buflist[i]->total,
+					 sizeof(request.list[0].total))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].used,
+					 &zero,
+					 sizeof(zero))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			address = virtual + dma->buflist[i]->offset;
+			if (copy_to_user(&request.list[i].address,
+					 &address,
+					 sizeof(address))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+		}
+	}
+ done:
+	request.count = dma->buf_count;
+	DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
+   
+	copy_to_user_ret((drm_buf_map_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+
+	DRM_DEBUG("retcode : %d\n", retcode);
+
+	return retcode;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/mga_context.c linux.18p8/drivers/char/drm/mga_context.c
--- linux.vanilla/drivers/char/drm/mga_context.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/mga_context.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,203 @@
+/* mga_context.c -- IOCTLs for mga contexts -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	   Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "mga_drv.h"
+
+static int mga_alloc_queue(drm_device_t *dev)
+{
+   	int temp = drm_ctxbitmap_next(dev);
+   	DRM_DEBUG("mga_alloc_queue: %d\n", temp);
+	return temp;
+}
+
+int mga_context_switch(drm_device_t *dev, int old, int new)
+{
+        char        buf[64];
+
+        atomic_inc(&dev->total_ctx);
+
+        if (test_and_set_bit(0, &dev->context_flag)) {
+                DRM_ERROR("Reentering -- FIXME\n");
+                return -EBUSY;
+        }
+
+#if DRM_DMA_HISTOGRAM
+        dev->ctx_start = get_cycles();
+#endif
+        
+        DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+        if (new == dev->last_context) {
+                clear_bit(0, &dev->context_flag);
+                return 0;
+        }
+        
+        if (drm_flags & DRM_FLAG_NOCTX) {
+                mga_context_switch_complete(dev, new);
+        } else {
+                sprintf(buf, "C %d %d\n", old, new);
+                drm_write_string(dev, buf);
+        }
+        
+        return 0;
+}
+
+int mga_context_switch_complete(drm_device_t *dev, int new)
+{
+        dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+        dev->last_switch  = jiffies;
+        
+        if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+                DRM_ERROR("Lock isn't held after context switch\n");
+        }
+
+				/* If a context switch is ever initiated
+                                   when the kernel holds the lock, release
+                                   that lock here. */
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+                                                      - dev->ctx_start)]);
+                   
+#endif
+        clear_bit(0, &dev->context_flag);
+        wake_up(&dev->context_wait);
+        
+        return 0;
+}
+
+int mga_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			copy_to_user_ret(&res.contexts[i],
+					 &i,
+					 sizeof(i),
+					 -EFAULT);
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+	return 0;
+}
+
+int mga_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	if ((ctx.handle = mga_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+				/* Skip kernel's context and get a new one. */
+		ctx.handle = mga_alloc_queue(dev);
+	}
+        if (ctx.handle == -1) {
+		DRM_DEBUG("Not enough free contexts.\n");
+				/* Should this return -EBUSY instead? */
+		return -ENOMEM;
+	}
+	DRM_DEBUG("%d\n", ctx.handle);
+	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int mga_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+   	/* This does nothing for the mga */
+	return 0;
+}
+
+int mga_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	drm_ctx_t ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+	/* This is 0, because we don't hanlde any context flags */
+	ctx.flags = 0;
+	copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int mga_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	return mga_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int mga_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	mga_context_switch_complete(dev, ctx.handle);
+
+	return 0;
+}
+
+int mga_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+      	if(ctx.handle != DRM_KERNEL_CONTEXT) {
+	   	drm_ctxbitmap_free(dev, ctx.handle);
+	}
+	
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/mga_dma.c linux.18p8/drivers/char/drm/mga_dma.c
--- linux.vanilla/drivers/char/drm/mga_dma.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/mga_dma.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,1115 @@
+/* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *	    Keith Whitwell <keithw@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "mga_drv.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+
+#define MGA_REG(reg)		2
+#define MGA_BASE(reg)		((unsigned long) \
+				((drm_device_t *)dev)->maplist[MGA_REG(reg)]->handle)
+#define MGA_ADDR(reg)		(MGA_BASE(reg) + reg)
+#define MGA_DEREF(reg)		*(__volatile__ int *)MGA_ADDR(reg)
+#define MGA_READ(reg)		MGA_DEREF(reg)
+#define MGA_WRITE(reg,val) 	do { MGA_DEREF(reg) = val; } while (0)
+
+#define PDEA_pagpxfer_enable 	     0x2
+
+static int mga_flush_queue(drm_device_t *dev);
+
+static unsigned long mga_alloc_page(drm_device_t *dev)
+{
+	unsigned long address;
+   
+	DRM_DEBUG("%s\n", __FUNCTION__);
+	address = __get_free_page(GFP_KERNEL);
+	if(address == 0UL) {
+		return 0;
+	}
+	atomic_inc(&mem_map[MAP_NR((void *) address)].count);
+	set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags);
+   
+	return address;
+}
+
+static void mga_free_page(drm_device_t *dev, unsigned long page)
+{
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if(page == 0UL) {
+		return;
+	}
+	atomic_dec(&mem_map[MAP_NR((void *) page)].count);
+	clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags);
+	wake_up(&mem_map[MAP_NR((void *) page)].wait);
+	free_page(page);
+	return;
+}
+
+static void mga_delay(void)
+{
+   	return;
+}
+
+void mga_flush_write_combine(void)
+{
+   	int xchangeDummy;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+   	__asm__ volatile(" push %%eax ; xchg %%eax, %0 ; pop %%eax" : : "m" (xchangeDummy));
+   	__asm__ volatile(" push %%eax ; push %%ebx ; push %%ecx ; push %%edx ;"
+			 " movl $0,%%eax ; cpuid ; pop %%edx ; pop %%ecx ; pop %%ebx ;"
+			 " pop %%eax" : /* no outputs */ :  /* no inputs */ );
+}
+
+/* These are two age tags that will never be sent to
+ * the hardware */
+#define MGA_BUF_USED 	0xffffffff
+#define MGA_BUF_FREE	0
+
+static int mga_freelist_init(drm_device_t *dev)
+{
+      	drm_device_dma_t *dma = dev->dma;
+   	drm_buf_t *buf;
+   	drm_mga_buf_priv_t *buf_priv;
+      	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+   	drm_mga_freelist_t *item;
+   	int i;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+   	dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
+	if(dev_priv->head == NULL) return -ENOMEM;
+   	memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t));
+   	dev_priv->head->age = MGA_BUF_USED;
+   
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	buf = dma->buflist[ i ];
+	        buf_priv = buf->dev_private;
+		item = drm_alloc(sizeof(drm_mga_freelist_t),
+				 DRM_MEM_DRIVER);
+	   	if(item == NULL) return -ENOMEM;
+	   	memset(item, 0, sizeof(drm_mga_freelist_t));
+	  	item->age = MGA_BUF_FREE;
+	   	item->prev = dev_priv->head;
+	   	item->next = dev_priv->head->next;
+	   	if(dev_priv->head->next != NULL)
+			dev_priv->head->next->prev = item;
+	   	if(item->next == NULL) dev_priv->tail = item;
+	   	item->buf = buf;
+	   	buf_priv->my_freelist = item;
+		buf_priv->discard = 0;
+		buf_priv->dispatched = 0;
+	   	dev_priv->head->next = item;
+	}
+   
+   	return 0;
+}
+
+static void mga_freelist_cleanup(drm_device_t *dev)
+{
+      	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+   	drm_mga_freelist_t *item;
+   	drm_mga_freelist_t *prev;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+   	item = dev_priv->head;
+   	while(item) {
+	   	prev = item;
+	   	item = item->next;
+	   	drm_free(prev, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
+	}
+   
+   	dev_priv->head = dev_priv->tail = NULL;
+}
+
+/* Frees dispatch lock */
+static inline void mga_dma_quiescent(drm_device_t *dev)
+{
+	drm_device_dma_t  *dma      = dev->dma;
+	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+   	unsigned long end;
+	int i;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+	end = jiffies + (HZ*3);
+    	while(1) {
+		if(!test_and_set_bit(MGA_IN_DISPATCH, 
+				     &dev_priv->dispatch_status)) {
+			break;
+		}
+	   	if((signed)(end - jiffies) <= 0) {
+			DRM_ERROR("irqs: %d wanted %d\n", 
+				  atomic_read(&dev->total_irq), 
+				  atomic_read(&dma->total_lost));
+			DRM_ERROR("lockup\n"); 
+			goto out_nolock;
+		}
+		for (i = 0 ; i < 2000 ; i++) mga_delay();
+	}
+	end = jiffies + (HZ*3);
+    	DRM_DEBUG("quiescent status : %x\n", MGA_READ(MGAREG_STATUS));
+    	while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) {
+		if((signed)(end - jiffies) <= 0) {
+			DRM_ERROR("irqs: %d wanted %d\n", 
+				  atomic_read(&dev->total_irq), 
+				  atomic_read(&dma->total_lost));
+			DRM_ERROR("lockup\n"); 
+			goto out_status;
+		}
+		for (i = 0 ; i < 2000 ; i++) mga_delay();	  
+	}
+    	sarea_priv->dirty |= MGA_DMA_FLUSH;
+
+out_status:
+    	clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status);
+out_nolock:
+}
+
+static void mga_reset_freelist(drm_device_t *dev)
+{
+   	drm_device_dma_t  *dma      = dev->dma;
+   	drm_buf_t *buf;
+   	drm_mga_buf_priv_t *buf_priv;
+	int i;
+
+   	for (i = 0; i < dma->buf_count; i++) {
+	   	buf = dma->buflist[ i ];
+	        buf_priv = buf->dev_private;
+		buf_priv->my_freelist->age = MGA_BUF_FREE;
+	}
+}
+
+/* Least recently used :
+ * These operations are not atomic b/c they are protected by the 
+ * hardware lock */
+
+drm_buf_t *mga_freelist_get(drm_device_t *dev)
+{
+   	DECLARE_WAITQUEUE(entry, current);
+   	drm_mga_private_t *dev_priv = 
+     		(drm_mga_private_t *) dev->dev_private;
+	drm_mga_freelist_t *prev;
+   	drm_mga_freelist_t *next;
+	static int failed = 0;
+
+	DRM_DEBUG("%s : tail->age : %d last_prim_age : %d\n", __FUNCTION__,
+	       dev_priv->tail->age, dev_priv->last_prim_age);
+   
+	if(failed >= 1000 && dev_priv->tail->age >= dev_priv->last_prim_age) {
+		DRM_DEBUG("I'm waiting on the freelist!!! %d\n", 
+		       dev_priv->last_prim_age);
+	   	set_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status);
+		current->state = TASK_INTERRUPTIBLE;
+	   	add_wait_queue(&dev_priv->buf_queue, &entry);
+	   	for (;;) {
+		   	mga_dma_schedule(dev, 0);
+		   	if(!test_bit(MGA_IN_GETBUF, 
+				     &dev_priv->dispatch_status)) 
+				break;
+		   	atomic_inc(&dev->total_sleeps);
+		   	schedule();
+		   	if (signal_pending(current)) {
+				clear_bit(MGA_IN_GETBUF,
+					  &dev_priv->dispatch_status);
+			   	goto failed_getbuf;
+			}
+		}
+	   	current->state = TASK_RUNNING;
+	   	remove_wait_queue(&dev_priv->buf_queue, &entry);
+	}
+   
+   	if(dev_priv->tail->age < dev_priv->last_prim_age) {
+		prev = dev_priv->tail->prev;
+	   	next = dev_priv->tail;
+	   	prev->next = NULL;
+	   	next->prev = next->next = NULL;
+	   	dev_priv->tail = prev;
+	   	next->age = MGA_BUF_USED;
+		failed = 0;
+	   	return next->buf;
+	}
+
+failed_getbuf:
+	failed++;
+   	return NULL;
+}
+
+int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf)
+{
+      	drm_mga_private_t *dev_priv = 
+     		(drm_mga_private_t *) dev->dev_private;
+   	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
+	drm_mga_freelist_t *prev;
+   	drm_mga_freelist_t *head;
+   	drm_mga_freelist_t *next;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+   	if(buf_priv->my_freelist->age == MGA_BUF_USED) {
+		/* Discarded buffer, put it on the tail */
+		next = buf_priv->my_freelist;
+		next->age = MGA_BUF_FREE;
+		prev = dev_priv->tail;
+		prev->next = next;
+		next->prev = prev;
+		next->next = NULL;
+		dev_priv->tail = next;
+		DRM_DEBUG("Discarded\n");
+	} else {
+		/* Normally aged buffer, put it on the head + 1,
+		 * as the real head is a sentinal element
+		 */
+		next = buf_priv->my_freelist;
+		head = dev_priv->head;
+		prev = head->next;
+		head->next = next;
+		prev->prev = next;
+		next->prev = head;
+		next->next = prev;
+	}
+   
+   	return 0;
+}
+
+static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init)
+{
+   	drm_mga_private_t *dev_priv = dev->dev_private;
+	drm_mga_prim_buf_t *prim_buffer;
+   	int i, temp, size_of_buf;
+   	int offset = init->reserved_map_agpstart;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+   	dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / 
+				  PAGE_SIZE) * PAGE_SIZE;
+   	size_of_buf = dev_priv->primary_size / MGA_NUM_PRIM_BUFS;
+	dev_priv->warp_ucode_size = init->warp_ucode_size;
+   	dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) * 
+					(MGA_NUM_PRIM_BUFS + 1), 
+					DRM_MEM_DRIVER);
+   	if(dev_priv->prim_bufs == NULL) {
+		DRM_ERROR("Unable to allocate memory for prim_buf\n");
+		return -ENOMEM;
+	}
+   	memset(dev_priv->prim_bufs, 
+	       0, sizeof(drm_mga_prim_buf_t *) * (MGA_NUM_PRIM_BUFS + 1));
+   
+   	temp = init->warp_ucode_size + dev_priv->primary_size;
+	temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
+	   
+	dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, 
+					temp);
+	if(dev_priv->ioremap == NULL) {
+		DRM_DEBUG("Ioremap failed\n");
+		return -ENOMEM;
+	}
+   	init_waitqueue_head(&dev_priv->wait_queue);
+   
+   	for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) {
+	   	prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t), 
+					DRM_MEM_DRIVER);
+	   	if(prim_buffer == NULL) return -ENOMEM;
+	   	memset(prim_buffer, 0, sizeof(drm_mga_prim_buf_t));
+	   	prim_buffer->phys_head = offset + dev->agp->base;
+	   	prim_buffer->current_dma_ptr = 
+			prim_buffer->head = 
+			(u32 *) (dev_priv->ioremap + 
+				 offset - 
+				 init->reserved_map_agpstart);
+	   	prim_buffer->num_dwords = 0;
+	   	prim_buffer->max_dwords = size_of_buf / sizeof(u32);
+	   	prim_buffer->max_dwords -= 5; /* Leave room for the softrap */
+	   	prim_buffer->sec_used = 0;
+	   	prim_buffer->idx = i;
+		prim_buffer->prim_age = i + 1;
+	   	offset = offset + size_of_buf;
+	   	dev_priv->prim_bufs[i] = prim_buffer;
+	}
+	dev_priv->current_prim_idx = 0;
+        dev_priv->next_prim = 
+		dev_priv->last_prim = 
+		dev_priv->current_prim =
+        	dev_priv->prim_bufs[0];
+	dev_priv->next_prim_age = 2;	
+	dev_priv->last_prim_age = 1;
+   	set_bit(MGA_BUF_IN_USE, &dev_priv->current_prim->buffer_status);
+   	return 0;
+}
+
+void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim)
+{
+       	drm_mga_private_t *dev_priv = dev->dev_private;
+      	drm_device_dma_t  *dma	    = dev->dma;
+       	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ 	int use_agp = PDEA_pagpxfer_enable;
+	unsigned long end;
+   	int i;
+   	int next_idx;
+       	PRIMLOCALS;
+
+   	DRM_DEBUG("%s\n", __FUNCTION__);
+   	dev_priv->last_prim = prim;
+   
+ 	/* We never check for overflow, b/c there is always room */
+    	PRIMPTR(prim);
+   	if(num_dwords <= 0) {
+		DRM_DEBUG("num_dwords == 0 when dispatched\n");
+		goto out_prim_wait;
+	}
+ 	PRIMOUTREG( MGAREG_DMAPAD, 0);
+ 	PRIMOUTREG( MGAREG_DMAPAD, 0);
+       	PRIMOUTREG( MGAREG_DMAPAD, 0);
+   	PRIMOUTREG( MGAREG_SOFTRAP, 0);
+    	PRIMFINISH(prim);
+
+	end = jiffies + (HZ*3);
+    	if(sarea_priv->dirty & MGA_DMA_FLUSH) {
+		DRM_DEBUG("Dma top flush\n");	   
+		while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) {
+			if((signed)(end - jiffies) <= 0) {
+				DRM_ERROR("irqs: %d wanted %d\n", 
+					  atomic_read(&dev->total_irq), 
+					  atomic_read(&dma->total_lost));
+				DRM_ERROR("lockup in fire primary "
+					  "(Dma Top Flush)\n");
+				goto out_prim_wait;
+			}
+	      
+			for (i = 0 ; i < 4096 ; i++) mga_delay();
+		}
+		sarea_priv->dirty &= ~(MGA_DMA_FLUSH);
+	} else {
+		DRM_DEBUG("Status wait\n");
+		while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) {
+			if((signed)(end - jiffies) <= 0) {
+				DRM_ERROR("irqs: %d wanted %d\n", 
+					  atomic_read(&dev->total_irq), 
+					  atomic_read(&dma->total_lost));
+				DRM_ERROR("lockup in fire primary "
+					  "(Status Wait)\n");
+				goto out_prim_wait;
+			}
+	   
+			for (i = 0 ; i < 4096 ; i++) mga_delay();
+		}
+	}
+
+   	mga_flush_write_combine();
+    	atomic_inc(&dev_priv->pending_bufs);
+       	MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL);
+ 	MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp);
+   	prim->num_dwords = 0;
+	sarea_priv->last_enqueue = prim->prim_age;
+    
+   	next_idx = prim->idx + 1;
+    	if(next_idx >= MGA_NUM_PRIM_BUFS) 
+		next_idx = 0;
+
+    	dev_priv->next_prim = dev_priv->prim_bufs[next_idx];
+	return;
+
+ out_prim_wait:
+	prim->num_dwords = 0;
+	prim->sec_used = 0;
+	clear_bit(MGA_BUF_IN_USE, &prim->buffer_status);
+   	wake_up_interruptible(&dev_priv->wait_queue);
+	clear_bit(MGA_BUF_SWAP_PENDING, &prim->buffer_status);
+	clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status);
+}
+
+int mga_advance_primary(drm_device_t *dev)
+{
+   	DECLARE_WAITQUEUE(entry, current);
+   	drm_mga_private_t *dev_priv = dev->dev_private;
+   	drm_mga_prim_buf_t *prim_buffer;
+   	drm_device_dma_t  *dma      = dev->dma;
+   	int next_prim_idx;
+   	int ret = 0;
+   
+   	/* This needs to reset the primary buffer if available,
+	 * we should collect stats on how many times it bites
+	 * it's tail */
+	DRM_DEBUG("%s\n", __FUNCTION__);
+   
+   	next_prim_idx = dev_priv->current_prim_idx + 1;
+   	if(next_prim_idx >= MGA_NUM_PRIM_BUFS)
+     		next_prim_idx = 0;
+   	prim_buffer = dev_priv->prim_bufs[next_prim_idx];
+	set_bit(MGA_IN_WAIT, &dev_priv->dispatch_status);
+   
+      	/* In use is cleared in interrupt handler */
+   
+   	if(test_and_set_bit(MGA_BUF_IN_USE, &prim_buffer->buffer_status)) {
+	   	add_wait_queue(&dev_priv->wait_queue, &entry);
+		current->state = TASK_INTERRUPTIBLE;
+
+	   	for (;;) {
+		   	mga_dma_schedule(dev, 0);
+		   	if(!test_and_set_bit(MGA_BUF_IN_USE, 
+					     &prim_buffer->buffer_status)) 
+				break;
+		   	atomic_inc(&dev->total_sleeps);
+		   	atomic_inc(&dma->total_missed_sched);
+		   	schedule();
+		   	if (signal_pending(current)) {
+			   	ret = -ERESTARTSYS;
+			   	break;
+			}
+		}
+	   	current->state = TASK_RUNNING;
+	   	remove_wait_queue(&dev_priv->wait_queue, &entry);
+	   	if(ret) return ret;
+	}
+	clear_bit(MGA_IN_WAIT, &dev_priv->dispatch_status);
+
+   	/* This primary buffer is now free to use */
+   	prim_buffer->current_dma_ptr = prim_buffer->head;
+   	prim_buffer->num_dwords = 0;
+   	prim_buffer->sec_used = 0;
+	prim_buffer->prim_age = dev_priv->next_prim_age++;
+	if(prim_buffer->prim_age == 0 || prim_buffer->prim_age == 0xffffffff) {
+	   mga_flush_queue(dev);
+	   mga_dma_quiescent(dev);
+	   mga_reset_freelist(dev);
+	   prim_buffer->prim_age = (dev_priv->next_prim_age += 2);
+	}
+
+	/* Reset all buffer status stuff */
+	clear_bit(MGA_BUF_NEEDS_OVERFLOW, &prim_buffer->buffer_status);
+	clear_bit(MGA_BUF_FORCE_FIRE, &prim_buffer->buffer_status);
+	clear_bit(MGA_BUF_SWAP_PENDING, &prim_buffer->buffer_status);
+
+   	dev_priv->current_prim = prim_buffer;
+   	dev_priv->current_prim_idx = next_prim_idx;
+   	return 0;
+}
+
+/* More dynamic performance decisions */
+static inline int mga_decide_to_fire(drm_device_t *dev)
+{
+   	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+      	drm_device_dma_t  *dma	    = dev->dma;
+
+   	DRM_DEBUG("%s\n", __FUNCTION__);
+
+   	if(test_bit(MGA_BUF_FORCE_FIRE, &dev_priv->next_prim->buffer_status)) {
+	   	atomic_inc(&dma->total_prio);
+	   	return 1;
+	}
+
+	if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) &&
+	    dev_priv->next_prim->num_dwords) {
+	   	atomic_inc(&dma->total_prio);
+	   	return 1;
+	}
+
+	if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) &&
+	    dev_priv->next_prim->num_dwords) {
+	   	atomic_inc(&dma->total_prio);
+	   	return 1;
+	}
+   
+   	if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS - 1) {
+		if(test_bit(MGA_BUF_SWAP_PENDING, 
+			    &dev_priv->next_prim->buffer_status)) {
+			atomic_inc(&dma->total_dmas);
+			return 1;
+		}
+	}
+
+   	if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS / 2) {
+		if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 8) {
+			atomic_inc(&dma->total_hit);
+			return 1;
+		}
+	}
+
+   	if(atomic_read(&dev_priv->pending_bufs) >= MGA_NUM_PRIM_BUFS / 2) {
+		if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 4) {
+			atomic_inc(&dma->total_missed_free);
+			return 1;
+		}
+	}
+
+   	atomic_inc(&dma->total_tried);
+   	return 0;
+}
+
+int mga_dma_schedule(drm_device_t *dev, int locked)
+{
+      	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+      	drm_device_dma_t  *dma	    = dev->dma;
+	int retval = 0;
+
+   	if (test_and_set_bit(0, &dev->dma_flag)) {
+		atomic_inc(&dma->total_missed_dma);
+		retval = -EBUSY;
+		goto sch_out_wakeup;
+	}
+   
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+   	if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) || 
+	   test_bit(MGA_IN_WAIT, &dev_priv->dispatch_status) ||
+	   test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) {
+		locked = 1;
+	}
+   
+   	if (!locked && 
+	    !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) {
+	   	atomic_inc(&dma->total_missed_lock);
+	   	clear_bit(0, &dev->dma_flag);
+		DRM_DEBUG("Not locked\n");
+		retval = -EBUSY;
+		goto sch_out_wakeup;
+	}
+   	DRM_DEBUG("I'm locked\n");
+
+   	if(!test_and_set_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status)) {
+	   	/* Fire dma buffer */
+	   	if(mga_decide_to_fire(dev)) {
+		   	DRM_DEBUG("idx :%d\n", dev_priv->next_prim->idx);
+			clear_bit(MGA_BUF_FORCE_FIRE, 
+				  &dev_priv->next_prim->buffer_status);
+		   	if(dev_priv->current_prim == dev_priv->next_prim) {
+				/* Schedule overflow for a later time */
+				set_bit(MGA_BUF_NEEDS_OVERFLOW,
+					&dev_priv->next_prim->buffer_status);
+			}
+		   	mga_fire_primary(dev, dev_priv->next_prim);
+		} else {
+			clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status);
+		}
+	} else {
+		DRM_DEBUG("I can't get the dispatch lock\n");
+	}
+   	
+	if (!locked) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+
+sch_out_wakeup:
+      	if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) &&
+	   atomic_read(&dev_priv->pending_bufs) == 0) {
+		/* Everything has been processed by the hardware */
+		clear_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status);
+		wake_up_interruptible(&dev_priv->flush_queue);
+	}
+
+	if(test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) &&
+	   dev_priv->tail->age < dev_priv->last_prim_age) {
+		clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status);
+		DRM_DEBUG("Waking up buf queue\n");
+		wake_up_interruptible(&dev_priv->buf_queue);
+	} else if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) {
+	   	DRM_DEBUG("Not waking buf_queue on %d %d\n", 
+			  atomic_read(&dev->total_irq), 
+			  dev_priv->last_prim_age);
+	}
+
+   	clear_bit(0, &dev->dma_flag);
+	return retval;
+}
+
+static void mga_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+    	drm_device_t	 *dev = (drm_device_t *)device;
+    	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+    	drm_mga_prim_buf_t *last_prim_buffer;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+    	atomic_inc(&dev->total_irq);
+	if((MGA_READ(MGAREG_STATUS) & 0x00000001) != 0x00000001) return;
+      	MGA_WRITE(MGAREG_ICLEAR, 0x00000001);
+   	last_prim_buffer = dev_priv->last_prim;
+    	last_prim_buffer->num_dwords = 0;
+    	last_prim_buffer->sec_used = 0;
+	dev_priv->sarea_priv->last_dispatch = 
+		dev_priv->last_prim_age = last_prim_buffer->prim_age;
+      	clear_bit(MGA_BUF_IN_USE, &last_prim_buffer->buffer_status);
+   	wake_up_interruptible(&dev_priv->wait_queue);
+      	clear_bit(MGA_BUF_SWAP_PENDING, &last_prim_buffer->buffer_status);
+      	clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status);
+      	atomic_dec(&dev_priv->pending_bufs);
+   	queue_task(&dev->tq, &tq_immediate);
+   	mark_bh(IMMEDIATE_BH);
+}
+
+static void mga_dma_task_queue(void *device)
+{
+	DRM_DEBUG("%s\n", __FUNCTION__);
+	mga_dma_schedule((drm_device_t *)device, 0);
+}
+
+int mga_dma_cleanup(drm_device_t *dev)
+{
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if(dev->dev_private) {
+		drm_mga_private_t *dev_priv = 
+			(drm_mga_private_t *) dev->dev_private;
+      
+		if(dev_priv->ioremap) {
+			int temp = (dev_priv->warp_ucode_size + 
+				    dev_priv->primary_size + 
+				    PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE;
+
+			drm_ioremapfree((void *) dev_priv->ioremap, temp);
+		}
+	   	if(dev_priv->status_page != NULL) {
+		   	iounmap(dev_priv->status_page);
+		}
+	   	if(dev_priv->real_status_page != 0UL) {
+		   	mga_free_page(dev, dev_priv->real_status_page);
+		}
+	   	if(dev_priv->prim_bufs != NULL) {
+		   	int i;
+		   	for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) {
+			   	if(dev_priv->prim_bufs[i] != NULL) {
+			     		drm_free(dev_priv->prim_bufs[i],
+						 sizeof(drm_mga_prim_buf_t),
+						 DRM_MEM_DRIVER);
+				}
+			}
+		   	drm_free(dev_priv->prim_bufs, sizeof(void *) *
+				 (MGA_NUM_PRIM_BUFS + 1), 
+				 DRM_MEM_DRIVER);
+		}
+		if(dev_priv->head != NULL) {
+		   	mga_freelist_cleanup(dev);
+		}
+
+
+		drm_free(dev->dev_private, sizeof(drm_mga_private_t), 
+			 DRM_MEM_DRIVER);
+		dev->dev_private = NULL;
+	}
+
+	return 0;
+}
+
+static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) {
+	drm_mga_private_t *dev_priv;
+	drm_map_t *sarea_map = NULL;
+	int i;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
+	if(dev_priv == NULL) return -ENOMEM;
+	dev->dev_private = (void *) dev_priv;
+
+	memset(dev_priv, 0, sizeof(drm_mga_private_t));
+
+	if((init->reserved_map_idx >= dev->map_count) ||
+	   (init->buffer_map_idx >= dev->map_count)) {
+		mga_dma_cleanup(dev);
+		DRM_DEBUG("reserved_map or buffer_map are invalid\n");
+		return -EINVAL;
+	}
+   
+	dev_priv->reserved_map_idx = init->reserved_map_idx;
+	dev_priv->buffer_map_idx = init->buffer_map_idx;
+	sarea_map = dev->maplist[0];
+	dev_priv->sarea_priv = (drm_mga_sarea_t *) 
+		((u8 *)sarea_map->handle + 
+		 init->sarea_priv_offset);
+
+	/* Scale primary size to the next page */
+	dev_priv->chipset = init->chipset;
+	dev_priv->frontOffset = init->frontOffset;
+	dev_priv->backOffset = init->backOffset;
+	dev_priv->depthOffset = init->depthOffset;
+	dev_priv->textureOffset = init->textureOffset;
+	dev_priv->textureSize = init->textureSize;
+	dev_priv->cpp = init->cpp;
+	dev_priv->sgram = init->sgram;
+	dev_priv->stride = init->stride;
+
+	dev_priv->mAccess = init->mAccess;
+   	init_waitqueue_head(&dev_priv->flush_queue);
+	init_waitqueue_head(&dev_priv->buf_queue);
+	dev_priv->WarpPipe = -1;
+
+   	DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n",
+		  dev_priv->chipset, dev_priv->warp_ucode_size, 
+		  dev_priv->backOffset, dev_priv->depthOffset);
+   	DRM_DEBUG("cpp: %d sgram: %d stride: %d maccess: %x\n",
+		  dev_priv->cpp, dev_priv->sgram, dev_priv->stride, 
+		  dev_priv->mAccess);
+   
+	memcpy(&dev_priv->WarpIndex, &init->WarpIndex, 
+	       sizeof(drm_mga_warp_index_t) * MGA_MAX_WARP_PIPES);
+
+   	for (i = 0 ; i < MGA_MAX_WARP_PIPES ; i++) 
+		DRM_DEBUG("warp pipe %d: installed: %d phys: %lx size: %x\n",
+			  i, 
+			  dev_priv->WarpIndex[i].installed,
+			  dev_priv->WarpIndex[i].phys_addr,
+			  dev_priv->WarpIndex[i].size);
+
+   	if(mga_init_primary_bufs(dev, init) != 0) {
+		DRM_ERROR("Can not initialize primary buffers\n");
+		mga_dma_cleanup(dev);
+		return -ENOMEM;
+	}
+   	dev_priv->real_status_page = mga_alloc_page(dev);
+      	if(dev_priv->real_status_page == 0UL) {
+		mga_dma_cleanup(dev);
+		DRM_ERROR("Can not allocate status page\n");
+		return -ENOMEM;
+	}
+
+   	dev_priv->status_page = 
+		ioremap_nocache(virt_to_bus((void *)dev_priv->real_status_page),
+				PAGE_SIZE);
+
+   	if(dev_priv->status_page == NULL) {
+		mga_dma_cleanup(dev);
+		DRM_ERROR("Can not remap status page\n");
+		return -ENOMEM;
+	}
+
+   	/* Write status page when secend or softrap occurs */
+   	MGA_WRITE(MGAREG_PRIMPTR, 
+		  virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003);
+      
+
+	/* Private is now filled in, initialize the hardware */
+	{
+		PRIMLOCALS;
+		PRIMGETPTR( dev_priv );
+	   	   
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+		PRIMOUTREG(MGAREG_DWGSYNC, 0x0100);
+		PRIMOUTREG(MGAREG_SOFTRAP, 0);
+		/* Poll for the first buffer to insure that
+		 * the status register will be correct
+		 */
+	   
+		mga_flush_write_combine();
+	   	MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL);
+
+		MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | 
+					   PDEA_pagpxfer_enable));
+	   
+	   	while(MGA_READ(MGAREG_DWGSYNC) != 0x0100) ;
+	}
+
+	if(mga_freelist_init(dev) != 0) {
+	   	DRM_ERROR("Could not initialize freelist\n");
+	   	mga_dma_cleanup(dev);
+	   	return -ENOMEM;
+	}
+	return 0;
+}
+
+int mga_dma_init(struct inode *inode, struct file *filp,
+		 unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_mga_init_t init;
+   
+   	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT);
+   
+	switch(init.func) {
+	case MGA_INIT_DMA:
+		return mga_dma_initialize(dev, &init);
+	case MGA_CLEANUP_DMA:
+		return mga_dma_cleanup(dev);
+	}
+
+	return -EINVAL;
+}
+
+int mga_irq_install(drm_device_t *dev, int irq)
+{
+	int retcode;
+
+	if (!irq)     return -EINVAL;
+	
+	down(&dev->struct_sem);
+	if (dev->irq) {
+		up(&dev->struct_sem);
+		return -EBUSY;
+	}
+	dev->irq = irq;
+	up(&dev->struct_sem);
+	
+	DRM_DEBUG("install irq handler %d\n", irq);
+
+	dev->context_flag     = 0;
+	dev->interrupt_flag   = 0;
+	dev->dma_flag	      = 0;
+	dev->dma->next_buffer = NULL;
+	dev->dma->next_queue  = NULL;
+	dev->dma->this_buffer = NULL;
+	dev->tq.next	      = NULL;
+	dev->tq.sync	      = 0;
+	dev->tq.routine	      = mga_dma_task_queue;
+	dev->tq.data	      = dev;
+
+				/* Before installing handler */
+	MGA_WRITE(MGAREG_IEN, 0);
+   				/* Install handler */
+	if ((retcode = request_irq(dev->irq,
+				   mga_dma_service,
+				   SA_SHIRQ,
+				   dev->devname,
+				   dev))) {
+		down(&dev->struct_sem);
+		dev->irq = 0;
+		up(&dev->struct_sem);
+		return retcode;
+	}
+				/* After installing handler */
+   	MGA_WRITE(MGAREG_ICLEAR, 0x00000001);
+	MGA_WRITE(MGAREG_IEN, 0x00000001);
+	return 0;
+}
+
+int mga_irq_uninstall(drm_device_t *dev)
+{
+	int irq;
+
+	down(&dev->struct_sem);
+	irq	 = dev->irq;
+	dev->irq = 0;
+	up(&dev->struct_sem);
+	
+	if (!irq) return -EINVAL;
+   	DRM_DEBUG("remove irq handler %d\n", irq);
+      	MGA_WRITE(MGAREG_ICLEAR, 0x00000001);
+	MGA_WRITE(MGAREG_IEN, 0);
+	free_irq(irq, dev);
+	return 0;
+}
+
+int mga_control(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_control_t	ctl;
+   
+	copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
+
+   	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	switch (ctl.func) {
+	case DRM_INST_HANDLER:
+		return mga_irq_install(dev, ctl.irq);
+	case DRM_UNINST_HANDLER:
+		return mga_irq_uninstall(dev);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mga_flush_queue(drm_device_t *dev)
+{
+   	DECLARE_WAITQUEUE(entry, current);
+  	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+   	int ret = 0;
+
+   	DRM_DEBUG("%s\n", __FUNCTION__);
+
+   	if(dev_priv == NULL) {
+	   	return 0;
+	}
+   
+   	if(dev_priv->next_prim->num_dwords != 0) {
+   		current->state = TASK_INTERRUPTIBLE;
+   		add_wait_queue(&dev_priv->flush_queue, &entry);
+		set_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status);
+		mga_dma_schedule(dev, 0);
+   		for (;;) {
+	   		if (!test_bit(MGA_IN_FLUSH, 
+				      &dev_priv->dispatch_status)) 
+				break;
+		   	atomic_inc(&dev->total_sleeps);
+	      		schedule();
+	      		if (signal_pending(current)) {
+		   		ret = -EINTR; /* Can't restart */
+				clear_bit(MGA_IN_FLUSH, 
+					  &dev_priv->dispatch_status);
+		   		break;
+			}
+		}
+   		current->state = TASK_RUNNING;
+   		remove_wait_queue(&dev_priv->flush_queue, &entry);
+	}
+   	return ret;
+}
+
+/* Must be called with the lock held */
+void mga_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	if (!dma) return;
+      	if(dev->dev_private == NULL) return;
+	if(dma->buflist == NULL) return;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+        mga_flush_queue(dev);
+
+	for (i = 0; i < dma->buf_count; i++) {
+	   	drm_buf_t *buf = dma->buflist[ i ];
+	   	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
+
+		/* Only buffers that need to get reclaimed ever 
+		 * get set to free 
+		 */
+		if (buf->pid == pid  && buf_priv) {
+			if(buf_priv->my_freelist->age == MGA_BUF_USED) 
+		     		buf_priv->my_freelist->age = MGA_BUF_FREE;
+		}
+	}
+}
+
+int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	DECLARE_WAITQUEUE(entry, current);
+	int		  ret	= 0;
+	drm_lock_t	  lock;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+   
+   	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+	       lock.context, current->pid, dev->lock.hw_lock->lock,
+	       lock.flags);
+
+	if (lock.context < 0) {
+		return -EINVAL;
+	}
+   
+	/* Only one queue:
+	 */
+
+	if (!ret) {
+		add_wait_queue(&dev->lock.lock_queue, &entry);
+		for (;;) {
+			if (!dev->lock.hw_lock) {
+				/* Device has been unregistered */
+				ret = -EINTR;
+				break;
+			}
+			if (drm_lock_take(&dev->lock.hw_lock->lock,
+					  lock.context)) {
+				dev->lock.pid	    = current->pid;
+				dev->lock.lock_time = jiffies;
+				atomic_inc(&dev->total_locks);
+				break;	/* Got lock */
+			}
+			
+				/* Contention */
+			atomic_inc(&dev->total_sleeps);
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				ret = -ERESTARTSYS;
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&dev->lock.lock_queue, &entry);
+	}
+	
+	if (!ret) {
+		if (lock.flags & _DRM_LOCK_QUIESCENT) {
+		   DRM_DEBUG("_DRM_LOCK_QUIESCENT\n");
+		   mga_flush_queue(dev);
+		   mga_dma_quiescent(dev);
+		}
+	}
+   
+	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+	return ret;
+}
+		
+int mga_flush_ioctl(struct inode *inode, struct file *filp, 
+		    unsigned int cmd, unsigned long arg)
+{
+       	drm_file_t	  *priv	  = filp->private_data;
+    	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+      	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
+
+   	DRM_DEBUG("%s\n", __FUNCTION__);
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("mga_flush_ioctl called without lock held\n");
+		return -EINVAL;
+	}
+
+   	if(lock.flags & _DRM_LOCK_FLUSH || lock.flags & _DRM_LOCK_FLUSH_ALL) {
+		drm_mga_prim_buf_t *temp_buf;
+
+		temp_buf = dev_priv->current_prim;
+
+		if(temp_buf && temp_buf->num_dwords) {
+			set_bit(MGA_BUF_FORCE_FIRE, &temp_buf->buffer_status);
+			mga_advance_primary(dev);
+ 		}
+		mga_dma_schedule(dev, 1);
+	}
+   	if(lock.flags & _DRM_LOCK_QUIESCENT) {
+		mga_flush_queue(dev);
+		mga_dma_quiescent(dev);
+	}
+
+    	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/mga_drm.h linux.18p8/drivers/char/drm/mga_drm.h
--- linux.vanilla/drivers/char/drm/mga_drm.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/mga_drm.h	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,269 @@
+/* mga_drm.h -- Public header for the Matrox g200/g400 driver -*- linux-c -*-
+ * Created: Tue Jan 25 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Jeff Hartmann <jhartmann@valinux.com>
+ *          Keith Whitwell <keithw@valinux.com>
+ *
+ */
+
+#ifndef _MGA_DRM_H_
+#define _MGA_DRM_H_
+
+/* WARNING: If you change any of these defines, make sure to change the
+ * defines in the Xserver file (xf86drmMga.h)
+ */
+#ifndef _MGA_DEFINES_
+#define _MGA_DEFINES_
+
+#define MGA_F  0x1		/* fog */
+#define MGA_A  0x2		/* alpha */
+#define MGA_S  0x4		/* specular */
+#define MGA_T2 0x8		/* multitexture */
+
+#define MGA_WARP_TGZ            0
+#define MGA_WARP_TGZF           (MGA_F)
+#define MGA_WARP_TGZA           (MGA_A)
+#define MGA_WARP_TGZAF          (MGA_F|MGA_A)
+#define MGA_WARP_TGZS           (MGA_S)
+#define MGA_WARP_TGZSF          (MGA_S|MGA_F)
+#define MGA_WARP_TGZSA          (MGA_S|MGA_A)
+#define MGA_WARP_TGZSAF         (MGA_S|MGA_F|MGA_A)
+#define MGA_WARP_T2GZ           (MGA_T2)
+#define MGA_WARP_T2GZF          (MGA_T2|MGA_F)
+#define MGA_WARP_T2GZA          (MGA_T2|MGA_A)
+#define MGA_WARP_T2GZAF         (MGA_T2|MGA_A|MGA_F)
+#define MGA_WARP_T2GZS          (MGA_T2|MGA_S)
+#define MGA_WARP_T2GZSF         (MGA_T2|MGA_S|MGA_F)
+#define MGA_WARP_T2GZSA         (MGA_T2|MGA_S|MGA_A)
+#define MGA_WARP_T2GZSAF        (MGA_T2|MGA_S|MGA_F|MGA_A)
+
+#define MGA_MAX_G400_PIPES 16
+#define MGA_MAX_G200_PIPES  8	/* no multitex */
+#define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES
+
+#define MGA_CARD_TYPE_G200 1
+#define MGA_CARD_TYPE_G400 2
+
+#define MGA_FRONT   0x1
+#define MGA_BACK    0x2
+#define MGA_DEPTH   0x4
+
+/* 3d state excluding texture units:
+ */
+#define MGA_CTXREG_DSTORG   0	/* validated */
+#define MGA_CTXREG_MACCESS  1	
+#define MGA_CTXREG_PLNWT    2	
+#define MGA_CTXREG_DWGCTL    3	
+#define MGA_CTXREG_ALPHACTRL 4
+#define MGA_CTXREG_FOGCOLOR  5
+#define MGA_CTXREG_WFLAG     6
+#define MGA_CTXREG_TDUAL0    7
+#define MGA_CTXREG_TDUAL1    8
+#define MGA_CTXREG_FCOL      9
+#define MGA_CTX_SETUP_SIZE   10
+
+/* 2d state
+ */
+#define MGA_2DREG_PITCH 	0
+#define MGA_2D_SETUP_SIZE 	1
+
+/* Each texture unit has a state:
+ */
+#define MGA_TEXREG_CTL        0
+#define MGA_TEXREG_CTL2       1
+#define MGA_TEXREG_FILTER     2
+#define MGA_TEXREG_BORDERCOL  3
+#define MGA_TEXREG_ORG        4 /* validated */
+#define MGA_TEXREG_ORG1       5
+#define MGA_TEXREG_ORG2       6
+#define MGA_TEXREG_ORG3       7
+#define MGA_TEXREG_ORG4       8
+#define MGA_TEXREG_WIDTH      9
+#define MGA_TEXREG_HEIGHT     10
+#define MGA_TEX_SETUP_SIZE    11
+
+/* What needs to be changed for the current vertex dma buffer?
+ */
+#define MGA_UPLOAD_CTX        0x1
+#define MGA_UPLOAD_TEX0       0x2
+#define MGA_UPLOAD_TEX1       0x4
+#define MGA_UPLOAD_PIPE       0x8
+#define MGA_UPLOAD_TEX0IMAGE  0x10 /* handled client-side */
+#define MGA_UPLOAD_TEX1IMAGE  0x20 /* handled client-side */
+#define MGA_UPLOAD_2D 	      0x40
+#define MGA_WAIT_AGE          0x80 /* handled client-side */
+#define MGA_UPLOAD_CLIPRECTS  0x100 /* handled client-side */
+#define MGA_DMA_FLUSH	      0x200 /* set when someone gets the lock
+                                       quiescent */
+
+/* 32 buffers of 64k each, total 2 meg.
+ */
+#define MGA_DMA_BUF_ORDER     16
+#define MGA_DMA_BUF_SZ        (1<<MGA_DMA_BUF_ORDER)
+#define MGA_DMA_BUF_NR        31
+
+/* Keep these small for testing.
+ */
+#define MGA_NR_SAREA_CLIPRECTS 8
+
+/* 2 heaps (1 for card, 1 for agp), each divided into upto 128
+ * regions, subject to a minimum region size of (1<<16) == 64k. 
+ *
+ * Clients may subdivide regions internally, but when sharing between
+ * clients, the region size is the minimum granularity. 
+ */
+
+#define MGA_CARD_HEAP 0
+#define MGA_AGP_HEAP  1
+#define MGA_NR_TEX_HEAPS 2
+#define MGA_NR_TEX_REGIONS 16
+#define MGA_LOG_MIN_TEX_REGION_SIZE 16
+#endif
+
+typedef struct _drm_mga_warp_index {
+   	int installed;
+   	unsigned long phys_addr;
+   	int size;
+} drm_mga_warp_index_t;
+
+typedef struct drm_mga_init {
+   	enum { 
+	   	MGA_INIT_DMA = 0x01,
+	       	MGA_CLEANUP_DMA = 0x02
+	} func;
+   	int reserved_map_agpstart;
+   	int reserved_map_idx;
+   	int buffer_map_idx;
+   	int sarea_priv_offset;
+   	int primary_size;
+   	int warp_ucode_size;
+   	unsigned int frontOffset;
+   	unsigned int backOffset;
+   	unsigned int depthOffset;
+   	unsigned int textureOffset;
+   	unsigned int textureSize;
+        unsigned int agpTextureOffset;
+        unsigned int agpTextureSize;
+   	unsigned int cpp;
+   	unsigned int stride;
+   	int sgram;
+	int chipset;
+   	drm_mga_warp_index_t WarpIndex[MGA_MAX_WARP_PIPES];
+	unsigned int mAccess;
+} drm_mga_init_t;
+
+/* Warning: if you change the sarea structure, you must change the Xserver
+ * structures as well */
+
+typedef struct _drm_mga_tex_region {
+	unsigned char next, prev;	
+	unsigned char in_use;	
+	unsigned int age;			
+} drm_mga_tex_region_t;
+
+typedef struct _drm_mga_sarea {
+	/* The channel for communication of state information to the kernel
+	 * on firing a vertex dma buffer.
+	 */
+   	unsigned int ContextState[MGA_CTX_SETUP_SIZE];
+   	unsigned int ServerState[MGA_2D_SETUP_SIZE];
+   	unsigned int TexState[2][MGA_TEX_SETUP_SIZE];
+   	unsigned int WarpPipe;
+   	unsigned int dirty;
+
+   	unsigned int nbox;
+   	drm_clip_rect_t boxes[MGA_NR_SAREA_CLIPRECTS];
+
+
+	/* Information about the most recently used 3d drawable.  The
+	 * client fills in the req_* fields, the server fills in the 
+	 * exported_ fields and puts the cliprects into boxes, above.
+	 *
+	 * The client clears the exported_drawable field before
+	 * clobbering the boxes data.
+	 */
+        unsigned int req_drawable;	 /* the X drawable id */
+	unsigned int req_draw_buffer;	 /* MGA_FRONT or MGA_BACK */
+
+        unsigned int exported_drawable;	 
+	unsigned int exported_index; 
+        unsigned int exported_stamp;	
+        unsigned int exported_buffers;	 
+        unsigned int exported_nfront;
+        unsigned int exported_nback;
+	int exported_back_x, exported_front_x, exported_w;	
+	int exported_back_y, exported_front_y, exported_h;
+   	drm_clip_rect_t exported_boxes[MGA_NR_SAREA_CLIPRECTS];
+   
+	/* Counters for aging textures and for client-side throttling.
+	 */
+        unsigned int last_enqueue;	/* last time a buffer was enqueued */
+	unsigned int last_dispatch;	/* age of the most recently dispatched buffer */
+	unsigned int last_quiescent;     /*  */
+
+
+	/* LRU lists for texture memory in agp space and on the card
+	 */
+	drm_mga_tex_region_t texList[MGA_NR_TEX_HEAPS][MGA_NR_TEX_REGIONS+1];
+	unsigned int texAge[MGA_NR_TEX_HEAPS];
+	
+	/* Mechanism to validate card state.
+	 */
+   	int ctxOwner;
+} drm_mga_sarea_t;	
+
+/* Device specific ioctls:
+ */
+typedef struct _drm_mga_clear {
+	unsigned int clear_color;
+	unsigned int clear_depth;
+	unsigned int flags;
+} drm_mga_clear_t;
+
+typedef struct _drm_mga_swap {
+   	int dummy;
+} drm_mga_swap_t;
+
+typedef struct _drm_mga_iload {
+	int idx;
+	int length;
+	unsigned int destOrg;
+} drm_mga_iload_t;
+
+typedef struct _drm_mga_vertex {
+   	int idx;		/* buffer to queue */
+	int used;		/* bytes in use */
+	int discard;		/* client finished with buffer?  */
+} drm_mga_vertex_t;
+
+typedef struct _drm_mga_indices {
+   	int idx;		/* buffer to queue */
+	unsigned int start;		
+	unsigned int end;		
+	int discard;		/* client finished with buffer?  */
+} drm_mga_indices_t;
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/mga_drv.c linux.18p8/drivers/char/drm/mga_drv.c
--- linux.vanilla/drivers/char/drm/mga_drv.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/mga_drv.c	Fri Sep  1 14:14:35 2000
@@ -0,0 +1,666 @@
+/* mga_drv.c -- Matrox g200/g400 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
+ * 
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "mga_drv.h"
+
+#include <linux/agp_backend.h>
+
+static __attribute__((unused)) void unused(void)
+{
+	agp_enable(0);
+}
+
+#define MGA_NAME	 "mga"
+#define MGA_DESC	 "Matrox g200/g400"
+#define MGA_DATE	 "20000719"
+#define MGA_MAJOR	 1
+#define MGA_MINOR	 0
+#define MGA_PATCHLEVEL	 0
+
+static drm_device_t	      mga_device;
+drm_ctx_t		      mga_res_ctx;
+
+static struct file_operations mga_fops = {
+#if LINUX_VERSION_CODE >= 0x020322
+				/* This started being used approx. 2.3.34 */
+	owner:   THIS_MODULE,
+#endif
+	open:	 mga_open,
+	flush:	 drm_flush,
+	release: mga_release,
+	ioctl:	 mga_ioctl,
+	mmap:	 drm_mmap,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+   	poll:	 drm_poll,
+};
+
+static struct miscdevice      mga_misc = {
+	minor: MISC_DYNAMIC_MINOR,
+	name:  MGA_NAME,
+	fops:  &mga_fops,
+};
+
+static drm_ioctl_desc_t	      mga_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]     = { mga_version,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]  = { drm_getunique,  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]   = { drm_getmagic,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]   = { drm_irq_busid,  0, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)]  = { drm_setunique,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	      = { drm_block,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]     = { drm_unblock,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_CONTROL)]     = { mga_control,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)]  = { drm_authmagic,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]     = { drm_addmap,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)]    = { mga_addbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]   = { mga_markbufs,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]   = { mga_infobufs,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]    = { mga_mapbufs,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]   = { mga_freebufs,	  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]     = { mga_addctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]      = { mga_rmctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]     = { mga_modctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]     = { mga_getctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]  = { mga_switchctx,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]     = { mga_newctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]     = { mga_resctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]    = { drm_adddraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]     = { drm_rmdraw,	  1, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_DMA)]	      = { mga_dma,	  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	      = { mga_lock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]      = { mga_unlock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]      = { drm_finish,	  1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]  = { drm_agp_enable,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]    = { drm_agp_info,    1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)]   = { drm_agp_alloc,   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)]    = { drm_agp_free,    1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)]    = { drm_agp_bind,    1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)]  = { drm_agp_unbind,  1, 1 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)]    = { mga_dma_init,    1, 1 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)]    = { mga_swap_bufs,   1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)]   = { mga_clear_bufs,  1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)]   = { mga_iload,       1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)]  = { mga_vertex,      1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)]   = { mga_flush_ioctl, 1, 0 },
+   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_indices,     1, 0 },
+};
+
+#define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls)
+
+#ifdef MODULE
+static char		      *mga = NULL;
+#endif
+
+MODULE_AUTHOR("VA Linux Systems, Inc.");
+MODULE_DESCRIPTION("Matrox g200/g400");
+MODULE_PARM(mga, "s");
+
+#ifndef MODULE
+/* mga_options is called by the kernel to parse command-line options passed
+ * via the boot-loader (e.g., LILO).  It calls the insmod option routine,
+ * drm_parse_drm.
+ */
+
+static int __init mga_options(char *str)
+{
+	drm_parse_options(str);
+	return 1;
+}
+
+__setup("mga=", mga_options);
+#endif
+
+static int mga_setup(drm_device_t *dev)
+{
+	int i;
+	
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use	  = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	drm_dma_setup(dev);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+	
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+			
+	DRM_DEBUG("\n");
+			
+	/* The kernel's context could be created here, but is now created
+	   in drm_dma_enqueue.	This is more resource-efficient for
+	   hardware that does not do DMA, but may mean that
+	   drm_select_queue fails between the time the interrupt is
+	   initialized and the time the queues are initialized. */
+			
+	return 0;
+}
+
+
+static int mga_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	if (dev->irq) mga_irq_uninstall(dev);
+	
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+	
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+	
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+				/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+   				/* Clear AGP information */
+	if (dev->agp) {
+		drm_agp_mem_t *entry;
+		drm_agp_mem_t *nexte;
+		
+				/* Remove AGP resources, but leave dev->agp
+                                   intact until cleanup is called. */
+		for (entry = dev->agp->memory; entry; entry = nexte) {
+			nexte = entry->next;
+			if (entry->bound) drm_unbind_agp(entry->memory);
+			drm_free_agp(entry->memory, entry->pages);
+			drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+		}
+		dev->agp->memory = NULL;
+		
+		if (dev->agp->acquired && drm_agp.release)
+			(*drm_agp.release)();
+		
+		dev->agp->acquired = 0;
+		dev->agp->enabled  = 0;
+	}
+				/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+	
+				/* Clear map area and mtrr information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+				if (map->mtrr >= 0) {
+					int retcode;
+					retcode = mtrr_del(map->mtrr,
+							   map->offset,
+							   map->size);
+					DRM_DEBUG("mtrr_del = %d\n", retcode);
+				}
+#endif
+				drm_ioremapfree(map->handle, map->size);
+				break;
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+			case _DRM_AGP:
+				break;
+			}
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+	
+	if (dev->queuelist) {
+		for (i = 0; i < dev->queue_count; i++) {
+			drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
+			if (dev->queuelist[i]) {
+				drm_free(dev->queuelist[i],
+					 sizeof(*dev->queuelist[0]),
+					 DRM_MEM_QUEUES);
+				dev->queuelist[i] = NULL;
+			}
+		}
+		drm_free(dev->queuelist,
+			 dev->queue_slots * sizeof(*dev->queuelist),
+			 DRM_MEM_QUEUES);
+		dev->queuelist	 = NULL;
+	}
+
+	drm_dma_takedown(dev);
+
+	dev->queue_count     = 0;
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+/* mga_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+static int mga_init(void)
+{
+	int		      retcode;
+	drm_device_t	      *dev = &mga_device;
+
+	DRM_DEBUG("\n");
+
+	memset((void *)dev, 0, sizeof(*dev));
+	dev->count_lock	  = SPIN_LOCK_UNLOCKED;
+	sema_init(&dev->struct_sem, 1);
+	
+#ifdef MODULE
+	drm_parse_options(mga);
+#endif
+	DRM_DEBUG("doing misc_register\n");
+	if ((retcode = misc_register(&mga_misc))) {
+		DRM_ERROR("Cannot register \"%s\"\n", MGA_NAME);
+		return retcode;
+	}
+	dev->device = MKDEV(MISC_MAJOR, mga_misc.minor);
+	dev->name   = MGA_NAME;
+
+   	DRM_DEBUG("doing mem init\n");
+	drm_mem_init();
+	DRM_DEBUG("doing proc init\n");
+	drm_proc_init(dev);
+	DRM_DEBUG("doing agp init\n");
+	dev->agp    = drm_agp_init();
+      	if(dev->agp == NULL) {
+	   	DRM_INFO("The mga drm module requires the agpgart module"
+		         " to function correctly\nPlease load the agpgart"
+		         " module before you load the mga module\n");
+	   	drm_proc_cleanup();
+	   	misc_deregister(&mga_misc);
+	   	mga_takedown(dev);
+	   	return -ENOMEM;
+	}
+#ifdef CONFIG_MTRR
+   	dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base,
+				      dev->agp->agp_info.aper_size * 1024 * 1024,
+				      MTRR_TYPE_WRCOMB,
+				      1);
+#endif
+	DRM_DEBUG("doing ctxbitmap init\n");
+	if((retcode = drm_ctxbitmap_init(dev))) {
+		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+		drm_proc_cleanup();
+		misc_deregister(&mga_misc);
+		mga_takedown(dev);
+		return retcode;
+	}
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+		 MGA_NAME,
+		 MGA_MAJOR,
+		 MGA_MINOR,
+		 MGA_PATCHLEVEL,
+		 MGA_DATE,
+		 mga_misc.minor);
+
+	return 0;
+}
+
+/* mga_cleanup is called via cleanup_module at module unload time. */
+
+static void mga_cleanup(void)
+{
+	drm_device_t	      *dev = &mga_device;
+
+	DRM_DEBUG("\n");
+	
+	drm_proc_cleanup();
+	if (misc_deregister(&mga_misc)) {
+		DRM_ERROR("Cannot unload module\n");
+	} else {
+		DRM_INFO("Module unloaded\n");
+	}
+	drm_ctxbitmap_cleanup(dev);
+	mga_dma_cleanup(dev);
+#ifdef CONFIG_MTRR
+   	if(dev->agp && dev->agp->agp_mtrr) {
+	   	int retval;
+	   	retval = mtrr_del(dev->agp->agp_mtrr, 
+				  dev->agp->agp_info.aper_base,
+				  dev->agp->agp_info.aper_size * 1024*1024);
+	   	DRM_DEBUG("mtrr_del = %d\n", retval);
+	}
+#endif
+
+	mga_takedown(dev);
+	if (dev->agp) {
+		drm_agp_uninit();
+		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+		dev->agp = NULL;
+	}
+}
+
+module_init(mga_init);
+module_exit(mga_cleanup);
+
+
+int mga_version(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_version_t version;
+	int	      len;
+
+	copy_from_user_ret(&version,
+			   (drm_version_t *)arg,
+			   sizeof(version),
+			   -EFAULT);
+
+#define DRM_COPY(name,value)				     \
+	len = strlen(value);				     \
+	if (len > name##_len) len = name##_len;		     \
+	name##_len = strlen(value);			     \
+	if (len && name) {				     \
+		copy_to_user_ret(name, value, len, -EFAULT); \
+	}
+
+	version.version_major	   = MGA_MAJOR;
+	version.version_minor	   = MGA_MINOR;
+	version.version_patchlevel = MGA_PATCHLEVEL;
+
+	DRM_COPY(version.name, MGA_NAME);
+	DRM_COPY(version.date, MGA_DATE);
+	DRM_COPY(version.desc, MGA_DESC);
+
+	copy_to_user_ret((drm_version_t *)arg,
+			 &version,
+			 sizeof(version),
+			 -EFAULT);
+	return 0;
+}
+
+int mga_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t  *dev    = &mga_device;
+	int	      retcode = 0;
+	
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return mga_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	return retcode;
+}
+
+int mga_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev;
+	int	      retcode = 0;
+
+	lock_kernel();
+	dev    = priv->dev;
+	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
+		  current->pid, dev->device, dev->open_count);
+
+	if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+	    && dev->lock.pid == current->pid) {
+	      	mga_reclaim_buffers(dev, priv->pid);
+		DRM_ERROR("Process %d dead, freeing lock for context %d\n",
+			  current->pid,
+			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+		drm_lock_free(dev,
+			      &dev->lock.hw_lock->lock,
+			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+		
+				/* FIXME: may require heavy-handed reset of
+                                   hardware at this point, possibly
+                                   processed via a callback to the X
+                                   server. */
+	} else if (dev->lock.hw_lock) {
+	   	/* The lock is required to reclaim buffers */
+	   	DECLARE_WAITQUEUE(entry, current);
+	   	add_wait_queue(&dev->lock.lock_queue, &entry);
+		for (;;) {
+			if (!dev->lock.hw_lock) {
+				/* Device has been unregistered */
+				retcode = -EINTR;
+				break;
+			}
+			if (drm_lock_take(&dev->lock.hw_lock->lock,
+					  DRM_KERNEL_CONTEXT)) {
+				dev->lock.pid	    = priv->pid;
+				dev->lock.lock_time = jiffies;
+				atomic_inc(&dev->total_locks);
+				break;	/* Got lock */
+			}			
+				/* Contention */
+			atomic_inc(&dev->total_sleeps);
+			current->state = TASK_INTERRUPTIBLE;
+			schedule();
+			if (signal_pending(current)) {
+				retcode = -ERESTARTSYS;
+				break;
+			}
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&dev->lock.lock_queue, &entry);
+	   	if(!retcode) {
+		   	mga_reclaim_buffers(dev, priv->pid);
+		   	drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				      DRM_KERNEL_CONTEXT);
+		}
+	}
+	drm_fasync(-1, filp, 0);
+
+	down(&dev->struct_sem);
+	if (priv->prev) priv->prev->next = priv->next;
+	else		dev->file_first	 = priv->next;
+	if (priv->next) priv->next->prev = priv->prev;
+	else		dev->file_last	 = priv->prev;
+	up(&dev->struct_sem);
+	
+	drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+#if LINUX_VERSION_CODE < 0x020333
+	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+   	atomic_inc(&dev->total_close);
+   	spin_lock(&dev->count_lock);
+   	if (!--dev->open_count) {
+	   	if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+		   	DRM_ERROR("Device busy: %d %d\n",
+				  atomic_read(&dev->ioctl_count),
+				  dev->blocked);
+		   	spin_unlock(&dev->count_lock);
+			unlock_kernel();
+		   	return -EBUSY;
+		}
+	   	spin_unlock(&dev->count_lock);
+		unlock_kernel();
+	   	return mga_takedown(dev);
+	}
+	spin_unlock(&dev->count_lock);
+	unlock_kernel();
+	return retcode;
+}
+
+
+/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int		 retcode = 0;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+	
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= MGA_IOCTL_COUNT) {
+		retcode = -EINVAL;
+	} else {
+		ioctl	  = &mga_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			retcode = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			retcode = -EACCES;
+		} else {
+			retcode = (func)(inode, filp, cmd, arg);
+		}
+	}
+	
+	atomic_dec(&dev->ioctl_count);
+	return retcode;
+}
+
+int mga_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+	
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+	mga_dma_schedule(dev, 1);
+
+	if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+			  DRM_KERNEL_CONTEXT)) {
+	   DRM_ERROR("\n");
+	}
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/mga_drv.h linux.18p8/drivers/char/drm/mga_drv.h
--- linux.vanilla/drivers/char/drm/mga_drv.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/mga_drv.h	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,445 @@
+/* mga_drv.h -- Private header for the Matrox g200/g400 driver -*- linux-c -*-
+ * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ * 	    Jeff Hartmann <jhartmann@valinux.com>
+ *
+ */
+
+#ifndef _MGA_DRV_H_
+#define _MGA_DRV_H_
+
+#define MGA_BUF_IN_USE         0
+#define MGA_BUF_SWAP_PENDING   1
+#define MGA_BUF_FORCE_FIRE     2
+#define MGA_BUF_NEEDS_OVERFLOW 3
+
+typedef struct {
+	u32 buffer_status;
+   	unsigned int num_dwords;
+   	unsigned int max_dwords;
+   	u32 *current_dma_ptr;
+   	u32 *head;
+   	u32 phys_head;
+	unsigned int prim_age;
+   	int sec_used;
+   	int idx;
+} drm_mga_prim_buf_t;
+
+typedef struct _drm_mga_freelist {
+   	unsigned int age;
+   	drm_buf_t *buf;
+   	struct _drm_mga_freelist *next;
+   	struct _drm_mga_freelist *prev;
+} drm_mga_freelist_t;
+
+#define MGA_IN_DISPATCH   0
+#define MGA_IN_FLUSH      1
+#define MGA_IN_WAIT       2
+#define MGA_IN_GETBUF	  3
+
+typedef struct _drm_mga_private {
+   	u32 dispatch_status;
+	unsigned int next_prim_age;
+	__volatile__ unsigned int last_prim_age;
+   	int reserved_map_idx;
+   	int buffer_map_idx;
+   	drm_mga_sarea_t *sarea_priv;
+   	int primary_size;
+   	int warp_ucode_size;
+   	int chipset;
+   	unsigned int frontOffset;
+   	unsigned int backOffset;
+   	unsigned int depthOffset;
+   	unsigned int textureOffset;
+   	unsigned int textureSize;
+   	int cpp;
+   	unsigned int stride;
+   	int sgram;
+	int use_agp;
+   	drm_mga_warp_index_t WarpIndex[MGA_MAX_G400_PIPES];
+	unsigned int WarpPipe;
+   	atomic_t pending_bufs;
+   	void *status_page;
+   	unsigned long real_status_page;
+   	u8 *ioremap;
+   	drm_mga_prim_buf_t **prim_bufs;
+   	drm_mga_prim_buf_t *next_prim;
+   	drm_mga_prim_buf_t *last_prim;
+   	drm_mga_prim_buf_t *current_prim;
+   	int current_prim_idx;
+   	drm_mga_freelist_t *head;
+   	drm_mga_freelist_t *tail;
+   	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */
+      	wait_queue_head_t wait_queue;	/* Processes waiting until interrupt */
+	wait_queue_head_t buf_queue;    /* Processes waiting for a free buf */
+	/* Some validated register values:
+	 */	
+	u32 mAccess;
+} drm_mga_private_t;
+
+				/* mga_drv.c */
+extern int  mga_version(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  mga_open(struct inode *inode, struct file *filp);
+extern int  mga_release(struct inode *inode, struct file *filp);
+extern int  mga_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  mga_unlock(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+				/* mga_dma.c */
+extern int  mga_dma_schedule(drm_device_t *dev, int locked);
+extern int  mga_dma(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+extern int  mga_irq_install(drm_device_t *dev, int irq);
+extern int  mga_irq_uninstall(drm_device_t *dev);
+extern int  mga_control(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  mga_lock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+
+/* mga_dma_init does init and release */
+extern int mga_dma_init(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int mga_dma_cleanup(drm_device_t *dev);
+extern int mga_flush_ioctl(struct inode *inode, struct file *filp,
+			   unsigned int cmd, unsigned long arg);
+extern void mga_flush_write_combine(void);
+extern unsigned int mga_create_sync_tag(drm_device_t *dev);
+extern drm_buf_t *mga_freelist_get(drm_device_t *dev);
+extern int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf);
+extern int mga_advance_primary(drm_device_t *dev);
+extern void mga_reclaim_buffers(drm_device_t *dev, pid_t pid);
+
+
+				/* mga_bufs.c */
+extern int  mga_addbufs(struct inode *inode, struct file *filp, 
+			unsigned int cmd, unsigned long arg);
+extern int  mga_infobufs(struct inode *inode, struct file *filp, 
+			 unsigned int cmd, unsigned long arg);
+extern int  mga_markbufs(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+extern int  mga_freebufs(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+extern int  mga_mapbufs(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  mga_addmap(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+				/* mga_state.c */
+extern int  mga_clear_bufs(struct inode *inode, struct file *filp,
+			   unsigned int cmd, unsigned long arg);
+extern int  mga_swap_bufs(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  mga_iload(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+extern int  mga_vertex(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+extern int  mga_indices(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+				/* mga_context.c */
+extern int  mga_resctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  mga_addctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  mga_modctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  mga_getctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  mga_switchctx(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  mga_newctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  mga_rmctx(struct inode *inode, struct file *filp,
+		      unsigned int cmd, unsigned long arg);
+
+extern int  mga_context_switch(drm_device_t *dev, int old, int new);
+extern int  mga_context_switch_complete(drm_device_t *dev, int new);
+
+
+typedef enum {
+	TT_GENERAL,
+	TT_BLIT,
+	TT_VECTOR,
+	TT_VERTEX
+} transferType_t;
+
+typedef struct {
+   	drm_mga_freelist_t *my_freelist;
+	int discard;
+	int dispatched;
+} drm_mga_buf_priv_t;
+
+#define DWGREG0 	0x1c00
+#define DWGREG0_END 	0x1dff
+#define DWGREG1		0x2c00
+#define DWGREG1_END	0x2dff
+
+#define ISREG0(r)	(r >= DWGREG0 && r <= DWGREG0_END)
+#define ADRINDEX0(r)	(u8)((r - DWGREG0) >> 2)
+#define ADRINDEX1(r)	(u8)(((r - DWGREG1) >> 2) | 0x80)
+#define ADRINDEX(r)	(ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) 
+
+#define MGA_VERBOSE 0
+#define MGA_NUM_PRIM_BUFS 	8
+
+#define PRIMLOCALS	u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \
+			int outcount, num_dwords
+
+#define PRIM_OVERFLOW(dev, dev_priv, length) do {			\
+	drm_mga_prim_buf_t *tmp_buf =					\
+ 		dev_priv->prim_bufs[dev_priv->current_prim_idx];	\
+	if( test_bit(MGA_BUF_NEEDS_OVERFLOW,				\
+		  &tmp_buf->buffer_status)) {				\
+ 		mga_advance_primary(dev);				\
+ 		mga_dma_schedule(dev, 1);				\
+ 	} else if( tmp_buf->max_dwords - tmp_buf->num_dwords < length ||\
+ 	    tmp_buf->sec_used > MGA_DMA_BUF_NR/2) {			\
+		set_bit(MGA_BUF_FORCE_FIRE, &tmp_buf->buffer_status);	\
+ 		mga_advance_primary(dev);				\
+ 		mga_dma_schedule(dev, 1);				\
+	}								\
+} while(0)
+
+#define PRIMGETPTR(dev_priv) do {					\
+	drm_mga_prim_buf_t *tmp_buf =					\
+		dev_priv->prim_bufs[dev_priv->current_prim_idx];	\
+	if(MGA_VERBOSE)							\
+		DRM_DEBUG("PRIMGETPTR in %s\n", __FUNCTION__);		\
+	dma_ptr = tmp_buf->current_dma_ptr;				\
+	num_dwords = tmp_buf->num_dwords;				\
+	phys_head = tmp_buf->phys_head;					\
+	outcount = 0;							\
+} while(0)
+
+#define PRIMPTR(prim_buf) do {					\
+	if(MGA_VERBOSE)						\
+		DRM_DEBUG("PRIMPTR in %s\n", __FUNCTION__);	\
+	dma_ptr = prim_buf->current_dma_ptr;			\
+	num_dwords = prim_buf->num_dwords;			\
+	phys_head = prim_buf->phys_head;			\
+	outcount = 0;						\
+} while(0)
+
+#define PRIMFINISH(prim_buf) do {				\
+	if (MGA_VERBOSE) {					\
+		DRM_DEBUG( "PRIMFINISH in %s\n", __FUNCTION__);	\
+                if (outcount & 3)				\
+                      DRM_DEBUG(" --- truncation\n");	        \
+        }							\
+	prim_buf->num_dwords = num_dwords;			\
+	prim_buf->current_dma_ptr = dma_ptr;			\
+} while(0)
+
+#define PRIMADVANCE(dev_priv)	do {				\
+drm_mga_prim_buf_t *tmp_buf = 					\
+	dev_priv->prim_bufs[dev_priv->current_prim_idx];	\
+	if (MGA_VERBOSE) {					\
+		DRM_DEBUG("PRIMADVANCE in %s\n", __FUNCTION__);	\
+                if (outcount & 3)				\
+                      DRM_DEBUG(" --- truncation\n");	\
+        }							\
+	tmp_buf->num_dwords = num_dwords;      			\
+	tmp_buf->current_dma_ptr = dma_ptr;    			\
+} while (0)
+
+#define PRIMUPDATE(dev_priv)	do {					\
+	drm_mga_prim_buf_t *tmp_buf =					\
+		dev_priv->prim_bufs[dev_priv->current_prim_idx];	\
+	tmp_buf->sec_used++;						\
+} while (0)
+
+#define AGEBUF(dev_priv, buf_priv)	do {				\
+	drm_mga_prim_buf_t *tmp_buf =					\
+		dev_priv->prim_bufs[dev_priv->current_prim_idx];	\
+	buf_priv->my_freelist->age = tmp_buf->prim_age;			\
+} while (0)
+
+
+#define PRIMOUTREG(reg, val) do {					\
+	tempIndex[outcount]=ADRINDEX(reg);				\
+	dma_ptr[1+outcount] = val;					\
+	if (MGA_VERBOSE)						\
+		DRM_DEBUG("   PRIMOUT %d: 0x%x -- 0x%x\n",		\
+		       num_dwords + 1 + outcount, ADRINDEX(reg), val);	\
+	if( ++outcount == 4) {						\
+		outcount = 0;						\
+		dma_ptr[0] = *(u32 *)tempIndex;				\
+		dma_ptr+=5;						\
+		num_dwords += 5;					\
+	}								\
+}while (0)
+
+/* A reduced set of the mga registers.
+ */
+
+#define MGAREG_MGA_EXEC 			0x0100
+#define MGAREG_ALPHACTRL 			0x2c7c
+#define MGAREG_AR0 				0x1c60
+#define MGAREG_AR1 				0x1c64
+#define MGAREG_AR2 				0x1c68
+#define MGAREG_AR3 				0x1c6c
+#define MGAREG_AR4 				0x1c70
+#define MGAREG_AR5 				0x1c74
+#define MGAREG_AR6 				0x1c78
+#define MGAREG_CXBNDRY				0x1c80
+#define MGAREG_CXLEFT 				0x1ca0
+#define MGAREG_CXRIGHT				0x1ca4
+#define MGAREG_DMAPAD 				0x1c54
+#define MGAREG_DSTORG 				0x2cb8
+#define MGAREG_DWGCTL 				0x1c00
+#define MGAREG_DWGSYNC				0x2c4c
+#define MGAREG_FCOL 				0x1c24
+#define MGAREG_FIFOSTATUS 			0x1e10
+#define MGAREG_FOGCOL 				0x1cf4
+#define MGAREG_FXBNDRY				0x1c84
+#define MGAREG_FXLEFT 				0x1ca8
+#define MGAREG_FXRIGHT				0x1cac
+#define MGAREG_ICLEAR 				0x1e18
+#define MGAREG_IEN 				0x1e1c
+#define MGAREG_LEN 				0x1c5c
+#define MGAREG_MACCESS				0x1c04
+#define MGAREG_PITCH 				0x1c8c
+#define MGAREG_PLNWT 				0x1c1c
+#define MGAREG_PRIMADDRESS 			0x1e58
+#define MGAREG_PRIMEND				0x1e5c
+#define MGAREG_PRIMPTR				0x1e50
+#define MGAREG_SECADDRESS 			0x2c40
+#define MGAREG_SECEND 				0x2c44
+#define MGAREG_SETUPADDRESS 			0x2cd0
+#define MGAREG_SETUPEND 			0x2cd4
+#define MGAREG_SOFTRAP				0x2c48
+#define MGAREG_SRCORG 				0x2cb4
+#define MGAREG_STATUS 				0x1e14
+#define MGAREG_STENCIL				0x2cc8
+#define MGAREG_STENCILCTL 			0x2ccc
+#define MGAREG_TDUALSTAGE0 			0x2cf8
+#define MGAREG_TDUALSTAGE1 			0x2cfc
+#define MGAREG_TEXBORDERCOL 			0x2c5c
+#define MGAREG_TEXCTL 				0x2c30
+#define MGAREG_TEXCTL2				0x2c3c
+#define MGAREG_TEXFILTER 			0x2c58
+#define MGAREG_TEXHEIGHT 			0x2c2c
+#define MGAREG_TEXORG 				0x2c24
+#define MGAREG_TEXORG1				0x2ca4
+#define MGAREG_TEXORG2				0x2ca8
+#define MGAREG_TEXORG3				0x2cac
+#define MGAREG_TEXORG4				0x2cb0
+#define MGAREG_TEXTRANS 			0x2c34
+#define MGAREG_TEXTRANSHIGH 			0x2c38
+#define MGAREG_TEXWIDTH 			0x2c28
+#define MGAREG_WACCEPTSEQ 			0x1dd4
+#define MGAREG_WCODEADDR 			0x1e6c
+#define MGAREG_WFLAG 				0x1dc4
+#define MGAREG_WFLAG1 				0x1de0
+#define MGAREG_WFLAGNB				0x1e64
+#define MGAREG_WFLAGNB1 			0x1e08
+#define MGAREG_WGETMSB				0x1dc8
+#define MGAREG_WIADDR 				0x1dc0
+#define MGAREG_WIADDR2				0x1dd8
+#define MGAREG_WMISC 				0x1e70
+#define MGAREG_WVRTXSZ				0x1dcc
+#define MGAREG_YBOT 				0x1c9c
+#define MGAREG_YDST 				0x1c90
+#define MGAREG_YDSTLEN				0x1c88
+#define MGAREG_YDSTORG				0x1c94
+#define MGAREG_YTOP 				0x1c98
+#define MGAREG_ZORG 				0x1c0c
+
+#define PDEA_pagpxfer_enable			0x2
+
+#define WIA_wmode_suspend			0x0
+#define WIA_wmode_start 			0x3
+#define WIA_wagp_agp				0x4
+
+#define DC_opcod_line_open 			0x0
+#define DC_opcod_autoline_open 			0x1
+#define DC_opcod_line_close 			0x2
+#define DC_opcod_autoline_close 		0x3
+#define DC_opcod_trap 				0x4
+#define DC_opcod_texture_trap 			0x6
+#define DC_opcod_bitblt 			0x8
+#define DC_opcod_iload 				0x9
+#define DC_atype_rpl 				0x0
+#define DC_atype_rstr 				0x10
+#define DC_atype_zi 				0x30
+#define DC_atype_blk 				0x40
+#define DC_atype_i 				0x70
+#define DC_linear_xy 				0x0 		
+#define DC_linear_linear 			0x80 		
+#define DC_zmode_nozcmp 			0x0
+#define DC_zmode_ze 				0x200
+#define DC_zmode_zne 				0x300
+#define DC_zmode_zlt 				0x400
+#define DC_zmode_zlte 				0x500
+#define DC_zmode_zgt 				0x600
+#define DC_zmode_zgte 				0x700
+#define DC_solid_disable 			0x0 		
+#define DC_solid_enable 			0x800 		
+#define DC_arzero_disable 			0x0 		
+#define DC_arzero_enable 			0x1000 		
+#define DC_sgnzero_disable 			0x0 		
+#define DC_sgnzero_enable 			0x2000 		
+#define DC_shftzero_disable 			0x0 		
+#define DC_shftzero_enable 			0x4000 		
+#define DC_bop_SHIFT 				16 		
+#define DC_trans_SHIFT 				20 		
+#define DC_bltmod_bmonolef 			0x0
+#define DC_bltmod_bmonowf 			0x8000000
+#define DC_bltmod_bplan 			0x2000000
+#define DC_bltmod_bfcol 			0x4000000
+#define DC_bltmod_bu32bgr 			0x6000000
+#define DC_bltmod_bu32rgb 			0xe000000
+#define DC_bltmod_bu24bgr 			0x16000000
+#define DC_bltmod_bu24rgb 			0x1e000000
+#define DC_pattern_disable 			0x0 		
+#define DC_pattern_enable 			0x20000000 	
+#define DC_transc_disable 			0x0 		
+#define DC_transc_enable 			0x40000000 	
+#define DC_clipdis_disable 			0x0 		
+#define DC_clipdis_enable 			0x80000000 	
+
+#define SETADD_mode_vertlist                   	0x0 	
+
+
+#define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | 		\
+		       DC_sgnzero_enable | DC_shftzero_enable | 	\
+		       (0xC << DC_bop_SHIFT) | DC_clipdis_enable | 	\
+		       DC_solid_enable | DC_transc_enable)
+	  
+
+#define MGA_COPY_CMD (DC_opcod_bitblt | DC_atype_rpl | DC_linear_xy |	\
+		      DC_solid_disable | DC_arzero_disable | 		\
+		      DC_sgnzero_enable | DC_shftzero_enable | 		\
+		      (0xC << DC_bop_SHIFT) | DC_bltmod_bfcol | 	\
+		      DC_pattern_disable | DC_transc_disable | 		\
+		      DC_clipdis_enable)				\
+
+#define MGA_FLUSH_CMD (DC_opcod_texture_trap | (0xF << DC_trans_SHIFT) |\
+		       DC_arzero_enable | DC_sgnzero_enable |		\
+		       DC_atype_i)
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/mga_state.c linux.18p8/drivers/char/drm/mga_state.c
--- linux.vanilla/drivers/char/drm/mga_state.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/mga_state.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,1067 @@
+/* mga_state.c -- State support for mga g200/g400 -*- linux-c -*-
+ * Created: Thu Jan 27 02:53:43 2000 by jhartmann@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Jeff Hartmann <jhartmann@valinux.com>
+ * 	    Keith Whitwell <keithw@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "mga_drv.h"
+#include "drm.h"
+
+static void mgaEmitClipRect(drm_mga_private_t * dev_priv,
+			    drm_clip_rect_t * box)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int *regs = sarea_priv->ContextState;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	/* This takes 10 dwords */
+	PRIMGETPTR(dev_priv);
+
+	/* Force reset of dwgctl (eliminates clip disable) */
+#if 0
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DWGSYNC, 0);
+	PRIMOUTREG(MGAREG_DWGSYNC, 0);
+	PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
+#else
+	PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
+	PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000);
+	PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
+	PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000);
+#endif
+
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_CXBNDRY, ((box->x2) << 16) | (box->x1));
+	PRIMOUTREG(MGAREG_YTOP, box->y1 * dev_priv->stride / 2);
+	PRIMOUTREG(MGAREG_YBOT, box->y2 * dev_priv->stride / 2);
+
+	PRIMADVANCE(dev_priv);
+}
+
+static void mgaEmitContext(drm_mga_private_t * dev_priv)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int *regs = sarea_priv->ContextState;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	/* This takes a max of 15 dwords */
+	PRIMGETPTR(dev_priv);
+
+	PRIMOUTREG(MGAREG_DSTORG, regs[MGA_CTXREG_DSTORG]);
+	PRIMOUTREG(MGAREG_MACCESS, regs[MGA_CTXREG_MACCESS]);
+	PRIMOUTREG(MGAREG_PLNWT, regs[MGA_CTXREG_PLNWT]);
+	PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
+
+	PRIMOUTREG(MGAREG_ALPHACTRL, regs[MGA_CTXREG_ALPHACTRL]);
+	PRIMOUTREG(MGAREG_FOGCOL, regs[MGA_CTXREG_FOGCOLOR]);
+	PRIMOUTREG(MGAREG_WFLAG, regs[MGA_CTXREG_WFLAG]);
+	PRIMOUTREG(MGAREG_ZORG, dev_priv->depthOffset);	/* invarient */
+
+	if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
+		PRIMOUTREG(MGAREG_WFLAG1, regs[MGA_CTXREG_WFLAG]);
+		PRIMOUTREG(MGAREG_TDUALSTAGE0, regs[MGA_CTXREG_TDUAL0]);
+		PRIMOUTREG(MGAREG_TDUALSTAGE1, regs[MGA_CTXREG_TDUAL1]);
+		PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]);
+	} else {
+		PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+	}
+
+	PRIMADVANCE(dev_priv);
+}
+
+static void mgaG200EmitTex(drm_mga_private_t * dev_priv)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int *regs = sarea_priv->TexState[0];
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	PRIMGETPTR(dev_priv);
+
+	/* This takes 20 dwords */
+
+	PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2]);
+	PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]);
+	PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]);
+	PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]);
+
+	PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG]);
+	PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1]);
+	PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2]);
+	PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3]);
+
+	PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]);
+	PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]);
+	PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]);
+	PRIMOUTREG(0x2d00 + 24 * 4, regs[MGA_TEXREG_WIDTH]);
+
+	PRIMOUTREG(0x2d00 + 34 * 4, regs[MGA_TEXREG_HEIGHT]);
+	PRIMOUTREG(MGAREG_TEXTRANS, 0xffff);
+	PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+
+	PRIMADVANCE(dev_priv);
+}
+
+static void mgaG400EmitTex0(drm_mga_private_t * dev_priv)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int *regs = sarea_priv->TexState[0];
+	int multitex = sarea_priv->WarpPipe & MGA_T2;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	PRIMGETPTR(dev_priv);
+
+	/* This takes a max of 30 dwords */
+
+	PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000);
+	PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]);
+	PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]);
+	PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]);
+
+	PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG]);
+	PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1]);
+	PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2]);
+	PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3]);
+
+	PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]);
+	PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]);
+	PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]);
+	PRIMOUTREG(0x2d00 + 49 * 4, 0);
+
+	PRIMOUTREG(0x2d00 + 57 * 4, 0);
+	PRIMOUTREG(0x2d00 + 53 * 4, 0);
+	PRIMOUTREG(0x2d00 + 61 * 4, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+
+	if (!multitex) {
+		PRIMOUTREG(0x2d00 + 52 * 4, 0x40);
+		PRIMOUTREG(0x2d00 + 60 * 4, 0x40);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+	}
+
+	PRIMOUTREG(0x2d00 + 54 * 4, regs[MGA_TEXREG_WIDTH] | 0x40);
+	PRIMOUTREG(0x2d00 + 62 * 4, regs[MGA_TEXREG_HEIGHT] | 0x40);
+	PRIMOUTREG(MGAREG_TEXTRANS, 0xffff);
+	PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff);
+
+	PRIMADVANCE(dev_priv);
+}
+
+#define TMC_map1_enable 		0x80000000
+
+static void mgaG400EmitTex1(drm_mga_private_t * dev_priv)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int *regs = sarea_priv->TexState[1];
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	PRIMGETPTR(dev_priv);
+
+	/* This takes 25 dwords */
+
+	PRIMOUTREG(MGAREG_TEXCTL2,
+		   regs[MGA_TEXREG_CTL2] | TMC_map1_enable | 0x00008000);
+	PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]);
+	PRIMOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER]);
+	PRIMOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL]);
+
+	PRIMOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG]);
+	PRIMOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1]);
+	PRIMOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2]);
+	PRIMOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3]);
+
+	PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]);
+	PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]);
+	PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]);
+	PRIMOUTREG(0x2d00 + 49 * 4, 0);
+
+	PRIMOUTREG(0x2d00 + 57 * 4, 0);
+	PRIMOUTREG(0x2d00 + 53 * 4, 0);
+	PRIMOUTREG(0x2d00 + 61 * 4, 0);
+	PRIMOUTREG(0x2d00 + 52 * 4, regs[MGA_TEXREG_WIDTH] | 0x40);
+
+	PRIMOUTREG(0x2d00 + 60 * 4, regs[MGA_TEXREG_HEIGHT] | 0x40);
+	PRIMOUTREG(MGAREG_TEXTRANS, 0xffff);
+	PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff);
+	PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000);
+
+	PRIMADVANCE(dev_priv);
+}
+
+#define EMIT_PIPE 50
+static void mgaG400EmitPipe(drm_mga_private_t * dev_priv)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int pipe = sarea_priv->WarpPipe;
+	float fParam = 12800.0f;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	PRIMGETPTR(dev_priv);
+
+	/* This takes 50 dwords */
+
+	/* Establish vertex size.  
+	 */
+	PRIMOUTREG(MGAREG_WIADDR2, WIA_wmode_suspend);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+
+	if (pipe & MGA_T2) {
+		PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001e09);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+
+		PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
+		PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
+		PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
+		PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x1e000000);
+	} else {
+		if (dev_priv->WarpPipe & MGA_T2) {
+			/* Flush the WARP pipe */
+			PRIMOUTREG(MGAREG_YDST, 0);
+			PRIMOUTREG(MGAREG_FXLEFT, 0);
+			PRIMOUTREG(MGAREG_FXRIGHT, 1);
+			PRIMOUTREG(MGAREG_DWGCTL, MGA_FLUSH_CMD);
+
+			PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 1);
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_DWGSYNC, 0x7000);
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+
+			PRIMOUTREG(MGAREG_TEXCTL2, 0 | 0x00008000);
+			PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0);
+			PRIMOUTREG(MGAREG_TEXCTL2, 0x80 | 0x00008000);
+			PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0);
+		}
+
+		PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001807);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+		PRIMOUTREG(MGAREG_DMAPAD, 0);
+
+		PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
+		PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
+		PRIMOUTREG(MGAREG_WACCEPTSEQ, 0);
+		PRIMOUTREG(MGAREG_WACCEPTSEQ, 0x18000000);
+	}
+
+	PRIMOUTREG(MGAREG_WFLAG, 0);
+	PRIMOUTREG(MGAREG_WFLAG1, 0);
+	PRIMOUTREG(0x2d00 + 56 * 4, *((u32 *) (&fParam)));
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+
+	PRIMOUTREG(0x2d00 + 49 * 4, 0);	/* Tex stage 0 */
+	PRIMOUTREG(0x2d00 + 57 * 4, 0);	/* Tex stage 0 */
+	PRIMOUTREG(0x2d00 + 53 * 4, 0);	/* Tex stage 1 */
+	PRIMOUTREG(0x2d00 + 61 * 4, 0);	/* Tex stage 1 */
+
+	PRIMOUTREG(0x2d00 + 54 * 4, 0x40);	/* Tex stage 0 : w */
+	PRIMOUTREG(0x2d00 + 62 * 4, 0x40);	/* Tex stage 0 : h */
+	PRIMOUTREG(0x2d00 + 52 * 4, 0x40);	/* Tex stage 1 : w */
+	PRIMOUTREG(0x2d00 + 60 * 4, 0x40);	/* Tex stage 1 : h */
+
+	/* Dma pading required due to hw bug */
+	PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
+	PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
+	PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
+	PRIMOUTREG(MGAREG_WIADDR2,
+		   (u32) (dev_priv->WarpIndex[pipe].
+			  phys_addr | WIA_wmode_start | WIA_wagp_agp));
+	PRIMADVANCE(dev_priv);
+}
+
+static void mgaG200EmitPipe(drm_mga_private_t * dev_priv)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int pipe = sarea_priv->WarpPipe;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	PRIMGETPTR(dev_priv);
+
+	/* This takes 15 dwords */
+
+	PRIMOUTREG(MGAREG_WIADDR, WIA_wmode_suspend);
+	PRIMOUTREG(MGAREG_WVRTXSZ, 7);
+	PRIMOUTREG(MGAREG_WFLAG, 0);
+	PRIMOUTREG(0x2d00 + 24 * 4, 0);	/* tex w/h */
+
+	PRIMOUTREG(0x2d00 + 25 * 4, 0x100);
+	PRIMOUTREG(0x2d00 + 34 * 4, 0);	/* tex w/h */
+	PRIMOUTREG(0x2d00 + 42 * 4, 0xFFFF);
+	PRIMOUTREG(0x2d00 + 60 * 4, 0xFFFF);
+
+	/* Dma pading required due to hw bug */
+	PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
+	PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
+	PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
+	PRIMOUTREG(MGAREG_WIADDR,
+		   (u32) (dev_priv->WarpIndex[pipe].
+			  phys_addr | WIA_wmode_start | WIA_wagp_agp));
+
+	PRIMADVANCE( dev_priv );
+}
+
+static void mgaEmitState(drm_mga_private_t * dev_priv)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int dirty = sarea_priv->dirty;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
+		int multitex = sarea_priv->WarpPipe & MGA_T2;
+
+		if (sarea_priv->WarpPipe != dev_priv->WarpPipe) {
+			mgaG400EmitPipe(dev_priv);
+			dev_priv->WarpPipe = sarea_priv->WarpPipe;
+		}
+
+		if (dirty & MGA_UPLOAD_CTX) {
+			mgaEmitContext(dev_priv);
+			sarea_priv->dirty &= ~MGA_UPLOAD_CTX;
+		}
+
+		if (dirty & MGA_UPLOAD_TEX0) {
+			mgaG400EmitTex0(dev_priv);
+			sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
+		}
+
+		if ((dirty & MGA_UPLOAD_TEX1) && multitex) {
+			mgaG400EmitTex1(dev_priv);
+			sarea_priv->dirty &= ~MGA_UPLOAD_TEX1;
+		}
+	} else {
+		if (sarea_priv->WarpPipe != dev_priv->WarpPipe) {
+			mgaG200EmitPipe(dev_priv);
+			dev_priv->WarpPipe = sarea_priv->WarpPipe;
+		}
+
+		if (dirty & MGA_UPLOAD_CTX) {
+			mgaEmitContext(dev_priv);
+			sarea_priv->dirty &= ~MGA_UPLOAD_CTX;
+		}
+
+		if (dirty & MGA_UPLOAD_TEX0) {
+			mgaG200EmitTex(dev_priv);
+			sarea_priv->dirty &= ~MGA_UPLOAD_TEX0;
+		}
+	}
+}
+
+
+/* Disallow all write destinations except the front and backbuffer.
+ */
+static int mgaVerifyContext(drm_mga_private_t * dev_priv)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int *regs = sarea_priv->ContextState;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOffset &&
+	    regs[MGA_CTXREG_DSTORG] != dev_priv->backOffset) {
+		DRM_DEBUG("BAD DSTORG: %x (front %x, back %x)\n\n",
+			  regs[MGA_CTXREG_DSTORG], dev_priv->frontOffset,
+			  dev_priv->backOffset);
+		regs[MGA_CTXREG_DSTORG] = 0;
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Disallow texture reads from PCI space.
+ */
+static int mgaVerifyTex(drm_mga_private_t * dev_priv, int unit)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) {
+		DRM_DEBUG("BAD TEXREG_ORG: %x, unit %d\n",
+			  sarea_priv->TexState[unit][MGA_TEXREG_ORG],
+			  unit);
+		sarea_priv->TexState[unit][MGA_TEXREG_ORG] = 0;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int mgaVerifyState(drm_mga_private_t * dev_priv)
+{
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int dirty = sarea_priv->dirty;
+	int rv = 0;
+
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
+		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
+
+	if (dirty & MGA_UPLOAD_CTX)
+		rv |= mgaVerifyContext(dev_priv);
+
+	if (dirty & MGA_UPLOAD_TEX0)
+		rv |= mgaVerifyTex(dev_priv, 0);
+
+	if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
+		if (dirty & MGA_UPLOAD_TEX1)
+			rv |= mgaVerifyTex(dev_priv, 1);
+
+		if (dirty & MGA_UPLOAD_PIPE)
+			rv |= (sarea_priv->WarpPipe > MGA_MAX_G400_PIPES);
+	} else {
+		if (dirty & MGA_UPLOAD_PIPE)
+			rv |= (sarea_priv->WarpPipe > MGA_MAX_G200_PIPES);
+	}
+
+	return rv == 0;
+}
+
+static int mgaVerifyIload(drm_mga_private_t * dev_priv,
+			  unsigned long bus_address,
+			  unsigned int dstOrg, int length)
+{
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if (dstOrg < dev_priv->textureOffset ||
+	    dstOrg + length >
+	    (dev_priv->textureOffset + dev_priv->textureSize)) {
+		return -EINVAL;
+	}
+	if (length % 64) {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* This copies a 64 byte aligned agp region to the frambuffer
+ * with a standard blit, the ioctl needs to do checking */
+
+static void mga_dma_dispatch_tex_blit(drm_device_t * dev,
+				      unsigned long bus_address,
+				      int length, unsigned int destOrg)
+{
+	drm_mga_private_t *dev_priv = dev->dev_private;
+	int use_agp = PDEA_pagpxfer_enable | 0x00000001;
+	u16 y2;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	y2 = length / 64;
+
+	PRIM_OVERFLOW(dev, dev_priv, 30);
+	PRIMGETPTR(dev_priv);
+
+	PRIMOUTREG(MGAREG_DSTORG, destOrg);
+	PRIMOUTREG(MGAREG_MACCESS, 0x00000000);
+	DRM_DEBUG("srcorg : %lx\n", bus_address | use_agp);
+	PRIMOUTREG(MGAREG_SRCORG, (u32) bus_address | use_agp);
+	PRIMOUTREG(MGAREG_AR5, 64);
+
+	PRIMOUTREG(MGAREG_PITCH, 64);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD);
+
+	PRIMOUTREG(MGAREG_AR0, 63);
+	PRIMOUTREG(MGAREG_AR3, 0);
+	PRIMOUTREG(MGAREG_FXBNDRY, (63 << 16));
+	PRIMOUTREG(MGAREG_YDSTLEN + MGAREG_MGA_EXEC, y2);
+
+	PRIMOUTREG(MGAREG_SRCORG, 0);
+	PRIMOUTREG(MGAREG_PITCH, dev_priv->stride / dev_priv->cpp);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMADVANCE(dev_priv);
+}
+
+static void mga_dma_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf)
+{
+	drm_mga_private_t *dev_priv = dev->dev_private;
+	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned long address = (unsigned long) buf->bus_address;
+	int length = buf->used;
+	int use_agp = PDEA_pagpxfer_enable;
+	int i = 0;
+	int primary_needed;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	DRM_DEBUG("dispatch vertex %d addr 0x%lx, "
+		  "length 0x%x nbox %d dirty %x\n",
+		  buf->idx, address, length,
+		  sarea_priv->nbox, sarea_priv->dirty);
+
+	DRM_DEBUG("used : %d, total : %d\n", buf->used, buf->total);
+
+	if (buf->used) {
+		/* WARNING: if you change any of the state functions verify
+		 * these numbers (Overestimating this doesn't hurt).  
+		 */
+		buf_priv->dispatched = 1;
+		primary_needed = (50 + 15 + 15 + 30 + 25 +
+				  10 + 15 * MGA_NR_SAREA_CLIPRECTS);
+		PRIM_OVERFLOW(dev, dev_priv, primary_needed);
+		mgaEmitState(dev_priv);
+		do {
+			if (i < sarea_priv->nbox) {
+				DRM_DEBUG("idx %d Emit box %d/%d:"
+					  "%d,%d - %d,%d\n",
+					  buf->idx,
+					  i, sarea_priv->nbox,
+					  sarea_priv->boxes[i].x1,
+					  sarea_priv->boxes[i].y1,
+					  sarea_priv->boxes[i].x2,
+					  sarea_priv->boxes[i].y2);
+
+				mgaEmitClipRect(dev_priv,
+						&sarea_priv->boxes[i]);
+			}
+
+			PRIMGETPTR(dev_priv);
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_SECADDRESS,
+				   ((u32) address) | TT_VERTEX);
+			PRIMOUTREG(MGAREG_SECEND,
+				   (((u32) (address + length)) | use_agp));
+			PRIMADVANCE(dev_priv);
+		} while (++i < sarea_priv->nbox);
+	}
+	if (buf_priv->discard) {
+		if (buf_priv->dispatched == 1)
+			AGEBUF(dev_priv, buf_priv);
+		buf_priv->dispatched = 0;
+		mga_freelist_put(dev, buf);
+	}
+
+
+}
+
+
+static void mga_dma_dispatch_indices(drm_device_t * dev,
+				     drm_buf_t * buf,
+				     unsigned int start, unsigned int end)
+{
+	drm_mga_private_t *dev_priv = dev->dev_private;
+	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int address = (unsigned int) buf->bus_address;
+	int use_agp = PDEA_pagpxfer_enable;
+	int i = 0;
+	int primary_needed;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	DRM_DEBUG("dispatch indices %d addr 0x%x, "
+		  "start 0x%x end 0x%x nbox %d dirty %x\n",
+		  buf->idx, address, start, end,
+		  sarea_priv->nbox, sarea_priv->dirty);
+
+	if (start != end) {
+		/* WARNING: if you change any of the state functions verify
+		 * these numbers (Overestimating this doesn't hurt).  
+		 */
+		buf_priv->dispatched = 1;
+		primary_needed = (50 + 15 + 15 + 30 + 25 +
+				  10 + 15 * MGA_NR_SAREA_CLIPRECTS);
+		PRIM_OVERFLOW(dev, dev_priv, primary_needed);
+		mgaEmitState(dev_priv);
+
+		do {
+			if (i < sarea_priv->nbox) {
+				DRM_DEBUG("idx %d Emit box %d/%d:"
+					  "%d,%d - %d,%d\n",
+					  buf->idx,
+					  i, sarea_priv->nbox,
+					  sarea_priv->boxes[i].x1,
+					  sarea_priv->boxes[i].y1,
+					  sarea_priv->boxes[i].x2,
+					  sarea_priv->boxes[i].y2);
+
+				mgaEmitClipRect(dev_priv,
+						&sarea_priv->boxes[i]);
+			}
+
+			PRIMGETPTR(dev_priv);
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_SETUPADDRESS,
+				   ((address + start) |
+				    SETADD_mode_vertlist));
+			PRIMOUTREG(MGAREG_SETUPEND,
+				   ((address + end) | use_agp));
+			PRIMADVANCE(dev_priv);
+		} while (++i < sarea_priv->nbox);
+	}
+	if (buf_priv->discard) {
+		if (buf_priv->dispatched == 1)
+			AGEBUF(dev_priv, buf_priv);
+		buf_priv->dispatched = 0;
+		mga_freelist_put(dev, buf);
+	}
+}
+
+
+static void mga_dma_dispatch_clear(drm_device_t * dev, int flags,
+				   unsigned int clear_color,
+				   unsigned int clear_zval)
+{
+	drm_mga_private_t *dev_priv = dev->dev_private;
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int *regs = sarea_priv->ContextState;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	unsigned int cmd;
+	int i;
+	int primary_needed;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if (dev_priv->sgram)
+		cmd = MGA_CLEAR_CMD | DC_atype_blk;
+	else
+		cmd = MGA_CLEAR_CMD | DC_atype_rstr;
+
+	primary_needed = nbox * 70;
+	if (primary_needed == 0)
+		primary_needed = 70;
+	PRIM_OVERFLOW(dev, dev_priv, primary_needed);
+	PRIMGETPTR(dev_priv);
+
+	for (i = 0; i < nbox; i++) {
+		unsigned int height = pbox[i].y2 - pbox[i].y1;
+
+		DRM_DEBUG("dispatch clear %d,%d-%d,%d flags %x!\n",
+			  pbox[i].x1, pbox[i].y1, pbox[i].x2,
+			  pbox[i].y2, flags);
+
+		if (flags & MGA_FRONT) {
+			DRM_DEBUG("clear front\n");
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_YDSTLEN,
+				   (pbox[i].y1 << 16) | height);
+			PRIMOUTREG(MGAREG_FXBNDRY,
+				   (pbox[i].x2 << 16) | pbox[i].x1);
+
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_FCOL, clear_color);
+			PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset);
+			PRIMOUTREG(MGAREG_DWGCTL + MGAREG_MGA_EXEC, cmd);
+		}
+
+		if (flags & MGA_BACK) {
+			DRM_DEBUG("clear back\n");
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_YDSTLEN,
+				   (pbox[i].y1 << 16) | height);
+			PRIMOUTREG(MGAREG_FXBNDRY,
+				   (pbox[i].x2 << 16) | pbox[i].x1);
+
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_FCOL, clear_color);
+			PRIMOUTREG(MGAREG_DSTORG, dev_priv->backOffset);
+			PRIMOUTREG(MGAREG_DWGCTL + MGAREG_MGA_EXEC, cmd);
+		}
+
+		if (flags & MGA_DEPTH) {
+			DRM_DEBUG("clear depth\n");
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_YDSTLEN,
+				   (pbox[i].y1 << 16) | height);
+			PRIMOUTREG(MGAREG_FXBNDRY,
+				   (pbox[i].x2 << 16) | pbox[i].x1);
+
+			PRIMOUTREG(MGAREG_DMAPAD, 0);
+			PRIMOUTREG(MGAREG_FCOL, clear_zval);
+			PRIMOUTREG(MGAREG_DSTORG, dev_priv->depthOffset);
+			PRIMOUTREG(MGAREG_DWGCTL + MGAREG_MGA_EXEC, cmd);
+		}
+	}
+
+	/* Force reset of DWGCTL */
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
+	PRIMADVANCE(dev_priv);
+}
+
+static void mga_dma_dispatch_swap(drm_device_t * dev)
+{
+	drm_mga_private_t *dev_priv = dev->dev_private;
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int *regs = sarea_priv->ContextState;
+	int nbox = sarea_priv->nbox;
+	drm_clip_rect_t *pbox = sarea_priv->boxes;
+	int i;
+	int primary_needed;
+	PRIMLOCALS;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	primary_needed = nbox * 5;
+	primary_needed += 65;
+	PRIM_OVERFLOW(dev, dev_priv, primary_needed);
+	PRIMGETPTR(dev_priv);
+
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DWGSYNC, 0x7100);
+	PRIMOUTREG(MGAREG_DWGSYNC, 0x7000);
+
+	PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset);
+	PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess);
+	PRIMOUTREG(MGAREG_SRCORG, dev_priv->backOffset);
+	PRIMOUTREG(MGAREG_AR5, dev_priv->stride / 2);
+
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD);
+
+	for (i = 0; i < nbox; i++) {
+		unsigned int h = pbox[i].y2 - pbox[i].y1;
+		unsigned int start = pbox[i].y1 * dev_priv->stride / 2;
+
+		DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
+			  pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2);
+
+		PRIMOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1);
+		PRIMOUTREG(MGAREG_AR3, start + pbox[i].x1);
+		PRIMOUTREG(MGAREG_FXBNDRY,
+			   pbox[i].x1 | ((pbox[i].x2 - 1) << 16));
+		PRIMOUTREG(MGAREG_YDSTLEN + MGAREG_MGA_EXEC,
+			   (pbox[i].y1 << 16) | h);
+	}
+
+	/* Force reset of DWGCTL */
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_DMAPAD, 0);
+	PRIMOUTREG(MGAREG_SRCORG, 0);
+	PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
+
+	PRIMADVANCE(dev_priv);
+}
+
+int mga_clear_bufs(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_mga_private_t *dev_priv =
+	    (drm_mga_private_t *) dev->dev_private;
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_mga_clear_t clear;
+
+	copy_from_user_ret(&clear, (drm_mga_clear_t *) arg, sizeof(clear),
+			   -EFAULT);
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("mga_clear_bufs called without lock held\n");
+		return -EINVAL;
+	}
+
+	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
+		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
+
+	/* Make sure we restore the 3D state next time.
+	 */
+	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX;
+	mga_dma_dispatch_clear(dev, clear.flags,
+			       clear.clear_color, clear.clear_depth);
+	PRIMUPDATE(dev_priv);
+	mga_flush_write_combine();
+	mga_dma_schedule(dev, 1);
+	return 0;
+}
+
+int mga_swap_bufs(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_mga_private_t *dev_priv =
+	    (drm_mga_private_t *) dev->dev_private;
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("mga_swap_bufs called without lock held\n");
+		return -EINVAL;
+	}
+
+	if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
+		sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
+
+	/* Make sure we restore the 3D state next time.
+	 */
+	dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX;
+	mga_dma_dispatch_swap(dev);
+	PRIMUPDATE(dev_priv);
+	set_bit(MGA_BUF_SWAP_PENDING,
+		&dev_priv->current_prim->buffer_status);
+	mga_flush_write_combine();
+	mga_dma_schedule(dev, 1);
+	return 0;
+}
+
+int mga_iload(struct inode *inode, struct file *filp,
+	      unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+	drm_mga_private_t *dev_priv =
+	    (drm_mga_private_t *) dev->dev_private;
+	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_buf_t *buf;
+	drm_mga_buf_priv_t *buf_priv;
+	drm_mga_iload_t iload;
+	unsigned long bus_address;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	DRM_DEBUG("Starting Iload\n");
+	copy_from_user_ret(&iload, (drm_mga_iload_t *) arg, sizeof(iload),
+			   -EFAULT);
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("mga_iload called without lock held\n");
+		return -EINVAL;
+	}
+
+	buf = dma->buflist[iload.idx];
+	buf_priv = buf->dev_private;
+	bus_address = buf->bus_address;
+	DRM_DEBUG("bus_address %lx, length %d, destorg : %x\n",
+		  bus_address, iload.length, iload.destOrg);
+
+	if (mgaVerifyIload(dev_priv,
+			   bus_address, iload.destOrg, iload.length)) {
+		mga_freelist_put(dev, buf);
+		return -EINVAL;
+	}
+
+	sarea_priv->dirty |= MGA_UPLOAD_CTX;
+
+	mga_dma_dispatch_tex_blit(dev, bus_address, iload.length,
+				  iload.destOrg);
+	AGEBUF(dev_priv, buf_priv);
+	buf_priv->discard = 1;
+	mga_freelist_put(dev, buf);
+	mga_flush_write_combine();
+	mga_dma_schedule(dev, 1);
+	return 0;
+}
+
+int mga_vertex(struct inode *inode, struct file *filp,
+	       unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_mga_private_t *dev_priv =
+	    (drm_mga_private_t *) dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_t *buf;
+	drm_mga_buf_priv_t *buf_priv;
+	drm_mga_vertex_t vertex;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	copy_from_user_ret(&vertex, (drm_mga_vertex_t *) arg,
+			   sizeof(vertex), -EFAULT);
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("mga_vertex called without lock held\n");
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("mga_vertex\n");
+
+	buf = dma->buflist[vertex.idx];
+	buf_priv = buf->dev_private;
+
+	buf->used = vertex.used;
+	buf_priv->discard = vertex.discard;
+
+	if (!mgaVerifyState(dev_priv)) {
+		if (vertex.discard) {
+			if (buf_priv->dispatched == 1)
+				AGEBUF(dev_priv, buf_priv);
+			buf_priv->dispatched = 0;
+			mga_freelist_put(dev, buf);
+		}
+		DRM_DEBUG("bad state\n");
+		return -EINVAL;
+	}
+
+	mga_dma_dispatch_vertex(dev, buf);
+
+	PRIMUPDATE(dev_priv);
+	mga_flush_write_combine();
+	mga_dma_schedule(dev, 1);
+	return 0;
+}
+
+
+int mga_indices(struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_mga_private_t *dev_priv =
+	    (drm_mga_private_t *) dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_t *buf;
+	drm_mga_buf_priv_t *buf_priv;
+	drm_mga_indices_t indices;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	copy_from_user_ret(&indices, (drm_mga_indices_t *) arg,
+			   sizeof(indices), -EFAULT);
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("mga_indices called without lock held\n");
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("mga_indices\n");
+
+	buf = dma->buflist[indices.idx];
+	buf_priv = buf->dev_private;
+
+	buf_priv->discard = indices.discard;
+
+	if (!mgaVerifyState(dev_priv)) {
+		if (indices.discard) {
+			if (buf_priv->dispatched == 1)
+				AGEBUF(dev_priv, buf_priv);
+			buf_priv->dispatched = 0;
+			mga_freelist_put(dev, buf);
+		}
+		return -EINVAL;
+	}
+
+	mga_dma_dispatch_indices(dev, buf, indices.start, indices.end);
+
+	PRIMUPDATE(dev_priv);
+	mga_flush_write_combine();
+	mga_dma_schedule(dev, 1);
+	return 0;
+}
+
+
+
+static int mga_dma_get_buffers(drm_device_t * dev, drm_dma_t * d)
+{
+	int i;
+	drm_buf_t *buf;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	for (i = d->granted_count; i < d->request_count; i++) {
+		buf = mga_freelist_get(dev);
+		if (!buf)
+			break;
+		buf->pid = current->pid;
+		copy_to_user_ret(&d->request_indices[i],
+				 &buf->idx, sizeof(buf->idx), -EFAULT);
+		copy_to_user_ret(&d->request_sizes[i],
+				 &buf->total, sizeof(buf->total), -EFAULT);
+		++d->granted_count;
+	}
+	return 0;
+}
+
+int mga_dma(struct inode *inode, struct file *filp, unsigned int cmd,
+	    unsigned long arg)
+{
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_device_dma_t *dma = dev->dma;
+	int retcode = 0;
+	drm_dma_t d;
+	DRM_DEBUG("%s\n", __FUNCTION__);
+
+	copy_from_user_ret(&d, (drm_dma_t *) arg, sizeof(d), -EFAULT);
+	DRM_DEBUG("%d %d: %d send, %d req\n",
+		  current->pid, d.context, d.send_count, d.request_count);
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+		DRM_ERROR("mga_dma called without lock held\n");
+		return -EINVAL;
+	}
+
+	/* Please don't send us buffers.
+	 */
+	if (d.send_count != 0) {
+		DRM_ERROR
+		    ("Process %d trying to send %d buffers via drmDMA\n",
+		     current->pid, d.send_count);
+		return -EINVAL;
+	}
+
+	/* We'll send you buffers.
+	 */
+	if (d.request_count < 0 || d.request_count > dma->buf_count) {
+		DRM_ERROR
+		    ("Process %d trying to get %d buffers (of %d max)\n",
+		     current->pid, d.request_count, dma->buf_count);
+		return -EINVAL;
+	}
+
+	d.granted_count = 0;
+
+	if (d.request_count) {
+		retcode = mga_dma_get_buffers(dev, &d);
+	}
+
+	DRM_DEBUG("%d returning, granted = %d\n",
+		  current->pid, d.granted_count);
+	copy_to_user_ret((drm_dma_t *) arg, &d, sizeof(d), -EFAULT);
+	return retcode;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/proc.c linux.18p8/drivers/char/drm/proc.c
--- linux.vanilla/drivers/char/drm/proc.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/proc.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,577 @@
+/* proc.c -- /proc support for DRM -*- linux-c -*-
+ * Created: Mon Jan 11 09:48:47 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+static struct proc_dir_entry *drm_root	   = NULL;
+static struct proc_dir_entry *drm_dev_root = NULL;
+static char		     drm_slot_name[64];
+
+static int	   drm_name_info(char *buf, char **start, off_t offset,
+				 int len, int *eof, void *data);
+static int	   drm_vm_info(char *buf, char **start, off_t offset,
+			       int len, int *eof, void *data);
+static int	   drm_clients_info(char *buf, char **start, off_t offset,
+				    int len, int *eof, void *data);
+static int	   drm_queues_info(char *buf, char **start, off_t offset,
+				   int len, int *eof, void *data);
+static int	   drm_bufs_info(char *buf, char **start, off_t offset,
+				 int len, int *eof, void *data);
+#if DRM_DEBUG_CODE
+static int	   drm_vma_info(char *buf, char **start, off_t offset,
+				int len, int *eof, void *data);
+#endif
+#if DRM_DMA_HISTOGRAM
+static int	   drm_histo_info(char *buf, char **start, off_t offset,
+				  int len, int *eof, void *data);
+#endif
+
+struct drm_proc_list {
+	const char *name;
+	int	   (*f)(char *, char **, off_t, int, int *, void *);
+} drm_proc_list[] = {
+	{ "name",    drm_name_info    },
+	{ "mem",     drm_mem_info     },
+	{ "vm",	     drm_vm_info      },
+	{ "clients", drm_clients_info },
+	{ "queues",  drm_queues_info  },
+	{ "bufs",    drm_bufs_info    },
+#if DRM_DEBUG_CODE
+	{ "vma",     drm_vma_info     },
+#endif
+#if DRM_DMA_HISTOGRAM
+	{ "histo",   drm_histo_info   },
+#endif
+};
+#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
+
+int drm_proc_init(drm_device_t *dev)
+{
+	struct proc_dir_entry *ent;
+	int		      i, j;
+
+	drm_root = create_proc_entry("dri", S_IFDIR, NULL);
+	if (!drm_root) {
+		DRM_ERROR("Cannot create /proc/dri\n");
+		return -1;
+	}
+
+				/* Instead of doing this search, we should
+				   add some global support for /proc/dri. */
+	for (i = 0; i < 8; i++) {
+		sprintf(drm_slot_name, "dri/%d", i);
+		drm_dev_root = create_proc_entry(drm_slot_name, S_IFDIR, NULL);
+		if (!drm_dev_root) {
+			DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name);
+			remove_proc_entry("dri", NULL);
+		}
+		if (drm_dev_root->nlink == 2) break;
+		drm_dev_root = NULL;
+	}
+	if (!drm_dev_root) {
+		DRM_ERROR("Cannot find slot in /proc/dri\n");
+		return -1;
+	}
+
+	for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+		ent = create_proc_entry(drm_proc_list[i].name,
+					S_IFREG|S_IRUGO, drm_dev_root);
+		if (!ent) {
+			DRM_ERROR("Cannot create /proc/%s/%s\n",
+				  drm_slot_name, drm_proc_list[i].name);
+			for (j = 0; j < i; j++)
+				remove_proc_entry(drm_proc_list[i].name,
+						  drm_dev_root);
+			remove_proc_entry(drm_slot_name, NULL);
+			remove_proc_entry("dri", NULL);
+			return -1;
+		}
+		ent->read_proc = drm_proc_list[i].f;
+		ent->data      = dev;
+	}
+
+	return 0;
+}
+
+
+int drm_proc_cleanup(void)
+{
+	int i;
+	
+	if (drm_root) {
+		if (drm_dev_root) {
+			for (i = 0; i < DRM_PROC_ENTRIES; i++) {
+				remove_proc_entry(drm_proc_list[i].name,
+						  drm_dev_root);
+			}
+			remove_proc_entry(drm_slot_name, NULL);
+		}
+		remove_proc_entry("dri", NULL);
+		remove_proc_entry(DRM_NAME, NULL);
+	}
+	drm_root = drm_dev_root = NULL;
+	return 0;
+}
+
+static int drm_name_info(char *buf, char **start, off_t offset, int len,
+			 int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+
+	if (dev->unique) {
+		DRM_PROC_PRINT("%s 0x%x %s\n",
+			       dev->name, dev->device, dev->unique);
+	} else {
+		DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device);
+	}
+	return len;
+}
+
+static int _drm_vm_info(char *buf, char **start, off_t offset, int len,
+			int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	drm_map_t    *map;
+				/* Hardcoded from _DRM_FRAME_BUFFER,
+                                   _DRM_REGISTERS, _DRM_SHM, and
+                                   _DRM_AGP. */
+	const char   *types[] = { "FB", "REG", "SHM", "AGP" };
+	const char   *type;
+	int	     i;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("slot	 offset	      size type flags	 "
+		       "address mtrr\n\n");
+	for (i = 0; i < dev->map_count; i++) {
+		map = dev->maplist[i];
+		if (map->type < 0 || map->type > 3) type = "??";
+		else				    type = types[map->type];
+		DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s  0x%02x 0x%08lx ",
+			       i,
+			       map->offset,
+			       map->size,
+			       type,
+			       map->flags,
+			       (unsigned long)map->handle);
+		if (map->mtrr < 0) {
+			DRM_PROC_PRINT("none\n");
+		} else {
+			DRM_PROC_PRINT("%4d\n", map->mtrr);
+		}
+	}
+
+	return len;
+}
+
+static int drm_vm_info(char *buf, char **start, off_t offset, int len,
+		       int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_vm_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+
+
+static int _drm_queues_info(char *buf, char **start, off_t offset, int len,
+			    int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     i;
+	drm_queue_t  *q;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("  ctx/flags   use   fin"
+		       "   blk/rw/rwf  wait    flushed	   queued"
+		       "      locks\n\n");
+	for (i = 0; i < dev->queue_count; i++) {
+		q = dev->queuelist[i];
+		atomic_inc(&q->use_count);
+		DRM_PROC_PRINT_RET(atomic_dec(&q->use_count),
+				   "%5d/0x%03x %5d %5d"
+				   " %5d/%c%c/%c%c%c %5Zd %10d %10d %10d\n",
+				   i,
+				   q->flags,
+				   atomic_read(&q->use_count),
+				   atomic_read(&q->finalization),
+				   atomic_read(&q->block_count),
+				   atomic_read(&q->block_read) ? 'r' : '-',
+				   atomic_read(&q->block_write) ? 'w' : '-',
+				   waitqueue_active(&q->read_queue) ? 'r':'-',
+				   waitqueue_active(&q->write_queue) ? 'w':'-',
+				   waitqueue_active(&q->flush_queue) ? 'f':'-',
+				   DRM_BUFCOUNT(&q->waitlist),
+				   atomic_read(&q->total_flushed),
+				   atomic_read(&q->total_queued),
+				   atomic_read(&q->total_locks));
+		atomic_dec(&q->use_count);
+	}
+	
+	return len;
+}
+
+static int drm_queues_info(char *buf, char **start, off_t offset, int len,
+			   int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_queues_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+
+/* drm_bufs_info is called whenever a process reads
+   /dev/drm/<dev>/bufs. */
+
+static int _drm_bufs_info(char *buf, char **start, off_t offset, int len,
+			  int *eof, void *data)
+{
+	drm_device_t	 *dev = (drm_device_t *)data;
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+
+	if (!dma)	return 0;
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT(" o     size count  free	 segs pages    kB\n\n");
+	for (i = 0; i <= DRM_MAX_ORDER; i++) {
+		if (dma->bufs[i].buf_count)
+			DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n",
+				       i,
+				       dma->bufs[i].buf_size,
+				       dma->bufs[i].buf_count,
+				       atomic_read(&dma->bufs[i]
+						   .freelist.count),
+				       dma->bufs[i].seg_count,
+				       dma->bufs[i].seg_count
+				       *(1 << dma->bufs[i].page_order),
+				       (dma->bufs[i].seg_count
+					* (1 << dma->bufs[i].page_order))
+				       * PAGE_SIZE / 1024);
+	}
+	DRM_PROC_PRINT("\n");
+	for (i = 0; i < dma->buf_count; i++) {
+		if (i && !(i%32)) DRM_PROC_PRINT("\n");
+		DRM_PROC_PRINT(" %d", dma->buflist[i]->list);
+	}
+	DRM_PROC_PRINT("\n");
+
+	return len;
+}
+
+static int drm_bufs_info(char *buf, char **start, off_t offset, int len,
+			 int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_bufs_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+
+
+static int _drm_clients_info(char *buf, char **start, off_t offset, int len,
+			     int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	drm_file_t   *priv;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("a dev	pid    uid	magic	  ioctls\n\n");
+	for (priv = dev->file_first; priv; priv = priv->next) {
+		DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
+			       priv->authenticated ? 'y' : 'n',
+			       priv->minor,
+			       priv->pid,
+			       priv->uid,
+			       priv->magic,
+			       priv->ioctl_count);
+	}
+
+	return len;
+}
+
+static int drm_clients_info(char *buf, char **start, off_t offset, int len,
+			    int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_clients_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+
+#if DRM_DEBUG_CODE
+
+#define DRM_VMA_VERBOSE 0
+
+static int _drm_vma_info(char *buf, char **start, off_t offset, int len,
+			 int *eof, void *data)
+{
+	drm_device_t	      *dev = (drm_device_t *)data;
+	drm_vma_entry_t	      *pt;
+	struct vm_area_struct *vma;
+#if DRM_VMA_VERBOSE
+	unsigned long	      i;
+	unsigned long	      address;
+	pgd_t		      *pgd;
+	pmd_t		      *pmd;
+	pte_t		      *pte;
+#endif
+#if defined(__i386__)
+	unsigned int	      pgprot;
+#endif
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+	DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
+		       atomic_read(&dev->vma_count),
+		       high_memory, virt_to_phys(high_memory));
+	for (pt = dev->vmalist; pt; pt = pt->next) {
+		if (!(vma = pt->vma)) continue;
+		DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+			       pt->pid,
+			       vma->vm_start,
+			       vma->vm_end,
+			       vma->vm_flags & VM_READ	   ? 'r' : '-',
+			       vma->vm_flags & VM_WRITE	   ? 'w' : '-',
+			       vma->vm_flags & VM_EXEC	   ? 'x' : '-',
+			       vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
+			       vma->vm_flags & VM_LOCKED   ? 'l' : '-',
+			       vma->vm_flags & VM_IO	   ? 'i' : '-',
+			       VM_OFFSET(vma));
+		
+#if defined(__i386__)
+		pgprot = pgprot_val(vma->vm_page_prot);
+		DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c",
+			       pgprot & _PAGE_PRESENT  ? 'p' : '-',
+			       pgprot & _PAGE_RW       ? 'w' : 'r',
+			       pgprot & _PAGE_USER     ? 'u' : 's',
+			       pgprot & _PAGE_PWT      ? 't' : 'b',
+			       pgprot & _PAGE_PCD      ? 'u' : 'c',
+			       pgprot & _PAGE_ACCESSED ? 'a' : '-',
+			       pgprot & _PAGE_DIRTY    ? 'd' : '-',
+			       pgprot & _PAGE_PSE      ? 'm' : 'k',
+			       pgprot & _PAGE_GLOBAL   ? 'g' : 'l' );
+#endif		
+		DRM_PROC_PRINT("\n");
+#if 0
+		for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) {
+			pgd = pgd_offset(vma->vm_mm, i);
+			pmd = pmd_offset(pgd, i);
+			pte = pte_offset(pmd, i);
+			if (pte_present(*pte)) {
+				address = __pa(pte_page(*pte))
+					+ (i & (PAGE_SIZE-1));
+				DRM_PROC_PRINT("      0x%08lx -> 0x%08lx"
+					       " %c%c%c%c%c\n",
+					       i,
+					       address,
+					       pte_read(*pte)  ? 'r' : '-',
+					       pte_write(*pte) ? 'w' : '-',
+					       pte_exec(*pte)  ? 'x' : '-',
+					       pte_dirty(*pte) ? 'd' : '-',
+					       pte_young(*pte) ? 'a' : '-' );
+			} else {
+				DRM_PROC_PRINT("      0x%08lx\n", i);
+			}
+		}
+#endif
+	}
+	
+	return len;
+}
+
+static int drm_vma_info(char *buf, char **start, off_t offset, int len,
+			int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_vma_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+#endif
+
+
+#if DRM_DMA_HISTOGRAM
+static int _drm_histo_info(char *buf, char **start, off_t offset, int len,
+			   int *eof, void *data)
+{
+	drm_device_t	 *dev = (drm_device_t *)data;
+	drm_device_dma_t *dma = dev->dma;
+	int		 i;
+	unsigned long	 slot_value = DRM_DMA_HISTOGRAM_INITIAL;
+	unsigned long	 prev_value = 0;
+	drm_buf_t	 *buffer;
+
+	if (offset > 0) return 0; /* no partial requests */
+	len  = 0;
+	*eof = 1;
+
+	DRM_PROC_PRINT("general statistics:\n");
+	DRM_PROC_PRINT("total	 %10u\n", atomic_read(&dev->histo.total));
+	DRM_PROC_PRINT("open	 %10u\n", atomic_read(&dev->total_open));
+	DRM_PROC_PRINT("close	 %10u\n", atomic_read(&dev->total_close));
+	DRM_PROC_PRINT("ioctl	 %10u\n", atomic_read(&dev->total_ioctl));
+	DRM_PROC_PRINT("irq	 %10u\n", atomic_read(&dev->total_irq));
+	DRM_PROC_PRINT("ctx	 %10u\n", atomic_read(&dev->total_ctx));
+	
+	DRM_PROC_PRINT("\nlock statistics:\n");
+	DRM_PROC_PRINT("locks	 %10u\n", atomic_read(&dev->total_locks));
+	DRM_PROC_PRINT("unlocks	 %10u\n", atomic_read(&dev->total_unlocks));
+	DRM_PROC_PRINT("contends %10u\n", atomic_read(&dev->total_contends));
+	DRM_PROC_PRINT("sleeps	 %10u\n", atomic_read(&dev->total_sleeps));
+
+
+	if (dma) {
+		DRM_PROC_PRINT("\ndma statistics:\n");
+		DRM_PROC_PRINT("prio	 %10u\n",
+			       atomic_read(&dma->total_prio));
+		DRM_PROC_PRINT("bytes	 %10u\n",
+			       atomic_read(&dma->total_bytes));
+		DRM_PROC_PRINT("dmas	 %10u\n",
+			       atomic_read(&dma->total_dmas));
+		DRM_PROC_PRINT("missed:\n");
+		DRM_PROC_PRINT("  dma	 %10u\n",
+			       atomic_read(&dma->total_missed_dma));
+		DRM_PROC_PRINT("  lock	 %10u\n",
+			       atomic_read(&dma->total_missed_lock));
+		DRM_PROC_PRINT("  free	 %10u\n",
+			       atomic_read(&dma->total_missed_free));
+		DRM_PROC_PRINT("  sched	 %10u\n",
+			       atomic_read(&dma->total_missed_sched));
+		DRM_PROC_PRINT("tried	 %10u\n",
+			       atomic_read(&dma->total_tried));
+		DRM_PROC_PRINT("hit	 %10u\n",
+			       atomic_read(&dma->total_hit));
+		DRM_PROC_PRINT("lost	 %10u\n",
+			       atomic_read(&dma->total_lost));
+		
+		buffer = dma->next_buffer;
+		if (buffer) {
+			DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx);
+		} else {
+			DRM_PROC_PRINT("next_buffer    none\n");
+		}
+		buffer = dma->this_buffer;
+		if (buffer) {
+			DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx);
+		} else {
+			DRM_PROC_PRINT("this_buffer    none\n");
+		}
+	}
+	
+
+	DRM_PROC_PRINT("\nvalues:\n");
+	if (dev->lock.hw_lock) {
+		DRM_PROC_PRINT("lock	       0x%08x\n",
+			       dev->lock.hw_lock->lock);
+	} else {
+		DRM_PROC_PRINT("lock		     none\n");
+	}
+	DRM_PROC_PRINT("context_flag   0x%08lx\n", dev->context_flag);
+	DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag);
+	DRM_PROC_PRINT("dma_flag       0x%08lx\n", dev->dma_flag);
+
+	DRM_PROC_PRINT("queue_count    %10d\n",	 dev->queue_count);
+	DRM_PROC_PRINT("last_context   %10d\n",	 dev->last_context);
+	DRM_PROC_PRINT("last_switch    %10lu\n", dev->last_switch);
+	DRM_PROC_PRINT("last_checked   %10d\n",	 dev->last_checked);
+		
+	
+	DRM_PROC_PRINT("\n		       q2d	  d2c	     c2f"
+		       "	q2c	   q2f	      dma	 sch"
+		       "	ctx	  lacq	     lhld\n\n");
+	for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) {
+		DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u"
+			       " %10u %10u %10u %10u %10u\n",
+			       i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ",
+			       i == DRM_DMA_HISTOGRAM_SLOTS - 1
+			       ? prev_value : slot_value ,
+			       
+			       atomic_read(&dev->histo
+					   .queued_to_dispatched[i]),
+			       atomic_read(&dev->histo
+					   .dispatched_to_completed[i]),
+			       atomic_read(&dev->histo
+					   .completed_to_freed[i]),
+			       
+			       atomic_read(&dev->histo
+					   .queued_to_completed[i]),
+			       atomic_read(&dev->histo
+					   .queued_to_freed[i]),
+			       atomic_read(&dev->histo.dma[i]),
+			       atomic_read(&dev->histo.schedule[i]),
+			       atomic_read(&dev->histo.ctx[i]),
+			       atomic_read(&dev->histo.lacq[i]),
+			       atomic_read(&dev->histo.lhld[i]));
+		prev_value = slot_value;
+		slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value);
+	}
+	return len;
+}
+
+static int drm_histo_info(char *buf, char **start, off_t offset, int len,
+			  int *eof, void *data)
+{
+	drm_device_t *dev = (drm_device_t *)data;
+	int	     ret;
+
+	down(&dev->struct_sem);
+	ret = _drm_histo_info(buf, start, offset, len, eof, data);
+	up(&dev->struct_sem);
+	return ret;
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/r128_bufs.c linux.18p8/drivers/char/drm/r128_bufs.c
--- linux.vanilla/drivers/char/drm/r128_bufs.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/r128_bufs.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,309 @@
+/* r128_bufs.c -- IOCTLs to manage buffers -*- linux-c -*-
+ * Created: Wed Apr 12 16:19:08 2000 by kevin@precisioninsight.com
+ *
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors: Kevin E. Martin <martin@valinux.com>
+ *          Rickard E. (Rik) Faith <faith@valinux.com>
+ *	    Jeff Hartmann <jhartmann@valinux.com>
+ * 
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "drmP.h"
+#include "r128_drv.h"
+#include "linux/un.h"
+
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
+		     unsigned long arg)
+{
+	drm_file_t       *priv = filp->private_data;
+	drm_device_t     *dev  = priv->dev;
+	drm_device_dma_t *dma  = dev->dma;
+	drm_buf_desc_t    request;
+	drm_buf_entry_t  *entry;
+	drm_buf_t        *buf;
+	unsigned long     offset;
+	unsigned long     agp_offset;
+	int               count;
+	int               order;
+	int               size;
+	int               alignment;
+	int               page_order;
+	int               total;
+	int               byte_count;
+	int               i;
+
+	if (!dma) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	count      = request.count;
+	order      = drm_order(request.size);
+	size       = 1 << order;
+
+	alignment  = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size;
+	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+	total      = PAGE_SIZE << page_order;
+
+	byte_count = 0;
+	agp_offset = dev->agp->base + request.agp_start;
+
+	DRM_DEBUG("count:      %d\n",  count);
+	DRM_DEBUG("order:      %d\n",  order);
+	DRM_DEBUG("size:       %d\n",  size);
+	DRM_DEBUG("agp_offset: %ld\n", agp_offset);
+	DRM_DEBUG("alignment:  %d\n",  alignment);
+	DRM_DEBUG("page_order: %d\n",  page_order);
+	DRM_DEBUG("total:      %d\n",  total);
+
+	if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
+	if (dev->queue_count) return -EBUSY; /* Not while in use */
+
+	spin_lock(&dev->count_lock);
+	if (dev->buf_use) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	atomic_inc(&dev->buf_alloc);
+	spin_unlock(&dev->count_lock);
+   
+	down(&dev->struct_sem);
+	entry = &dma->bufs[order];
+	if (entry->buf_count) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM; /* May only call once for each order */
+	}
+   
+	entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
+				   DRM_MEM_BUFS);
+	if (!entry->buflist) {
+		up(&dev->struct_sem);
+		atomic_dec(&dev->buf_alloc);
+		return -ENOMEM;
+	}
+	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
+   
+	entry->buf_size   = size;
+	entry->page_order = page_order;
+	offset            = 0;
+
+	for (offset = 0;
+	     entry->buf_count < count;
+	     offset += alignment, ++entry->buf_count) {
+		buf          = &entry->buflist[entry->buf_count];
+		buf->idx     = dma->buf_count + entry->buf_count;
+		buf->total   = alignment;
+		buf->order   = order;
+		buf->used    = 0;
+		buf->offset  = (dma->byte_count + offset);
+		buf->address = (void *)(agp_offset + offset);
+		buf->next    = NULL;
+		buf->waiting = 0;
+		buf->pending = 0;
+		init_waitqueue_head(&buf->dma_wait);
+		buf->pid     = 0;
+
+		buf->dev_priv_size = sizeof(drm_r128_buf_priv_t);
+		buf->dev_private   = drm_alloc(sizeof(drm_r128_buf_priv_t),
+					       DRM_MEM_BUFS);
+		memset(buf->dev_private, 0, buf->dev_priv_size);
+
+#if DRM_DMA_HISTOGRAM
+		buf->time_queued     = 0;
+		buf->time_dispatched = 0;
+		buf->time_completed  = 0;
+		buf->time_freed      = 0;
+#endif
+
+		byte_count += PAGE_SIZE << page_order;
+
+		DRM_DEBUG("buffer %d @ %p\n",
+			  entry->buf_count, buf->address);
+	}
+
+	DRM_DEBUG("byte_count: %d\n", byte_count);
+
+	dma->buflist = drm_realloc(dma->buflist,
+				   dma->buf_count * sizeof(*dma->buflist),
+				   (dma->buf_count + entry->buf_count)
+				   * sizeof(*dma->buflist),
+				   DRM_MEM_BUFS);
+	for (i = dma->buf_count; i < dma->buf_count + entry->buf_count; i++)
+		dma->buflist[i] = &entry->buflist[i - dma->buf_count];
+
+	dma->buf_count  += entry->buf_count;
+	dma->byte_count += byte_count;
+
+	drm_freelist_create(&entry->freelist, entry->buf_count);
+	for (i = 0; i < entry->buf_count; i++) {
+		drm_freelist_put(dev, &entry->freelist, &entry->buflist[i]);
+	}
+
+	up(&dev->struct_sem);
+
+	request.count = entry->buf_count;
+	request.size  = size;
+
+	copy_to_user_ret((drm_buf_desc_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+
+	dma->flags = _DRM_DMA_USE_AGP;
+
+	atomic_dec(&dev->buf_alloc);
+	return 0;
+}
+#endif
+
+int r128_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t		*priv		= filp->private_data;
+	drm_device_t		*dev		= priv->dev;
+	drm_r128_private_t	*dev_priv	= dev->dev_private;
+	drm_buf_desc_t		request;
+
+	if (!dev_priv || dev_priv->is_pci) return -EINVAL;
+
+	copy_from_user_ret(&request,
+			   (drm_buf_desc_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	if (request.flags & _DRM_AGP_BUFFER)
+		return r128_addbufs_agp(inode, filp, cmd, arg);
+	else
+#endif
+		return -EINVAL;
+}
+
+int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t		*priv		= filp->private_data;
+	drm_device_t		*dev		= priv->dev;
+	drm_r128_private_t	*dev_priv	= dev->dev_private;
+	drm_device_dma_t	*dma		= dev->dma;
+	int			 retcode	= 0;
+	const int		 zero		= 0;
+	unsigned long		 virtual;
+	unsigned long		 address;
+	drm_buf_map_t		 request;
+	int			 i;
+
+	if (!dma || !dev_priv || dev_priv->is_pci) return -EINVAL;
+
+	DRM_DEBUG("\n");
+
+	spin_lock(&dev->count_lock);
+	if (atomic_read(&dev->buf_alloc)) {
+		spin_unlock(&dev->count_lock);
+		return -EBUSY;
+	}
+	++dev->buf_use;		/* Can't allocate more after this call */
+	spin_unlock(&dev->count_lock);
+
+	copy_from_user_ret(&request,
+			   (drm_buf_map_t *)arg,
+			   sizeof(request),
+			   -EFAULT);
+
+	if (request.count >= dma->buf_count) {
+		if (dma->flags & _DRM_DMA_USE_AGP) {
+			drm_map_t *map;
+
+			map = dev_priv->agp_vertbufs;
+			if (!map) {
+				retcode = -EINVAL;
+				goto done;
+			}
+
+			down(&current->mm->mmap_sem);
+			virtual = do_mmap(filp, 0, map->size, 
+					  PROT_READ|PROT_WRITE,
+					  MAP_SHARED, 
+					  (unsigned long)map->offset);
+			up(&current->mm->mmap_sem);
+		} else {
+			down(&current->mm->mmap_sem);
+			virtual = do_mmap(filp, 0, dma->byte_count,
+					  PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+			up(&current->mm->mmap_sem);
+		}
+		if (virtual > -1024UL) {
+			/* Real error */
+			retcode = (signed long)virtual;
+			goto done;
+		}
+		request.virtual = (void *)virtual;
+
+		for (i = 0; i < dma->buf_count; i++) {
+			if (copy_to_user(&request.list[i].idx,
+					 &dma->buflist[i]->idx,
+					 sizeof(request.list[0].idx))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].total,
+					 &dma->buflist[i]->total,
+					 sizeof(request.list[0].total))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			if (copy_to_user(&request.list[i].used,
+					 &zero,
+					 sizeof(zero))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+			address = virtual + dma->buflist[i]->offset;
+			if (copy_to_user(&request.list[i].address,
+					 &address,
+					 sizeof(address))) {
+				retcode = -EFAULT;
+				goto done;
+			}
+		}
+	}
+ done:
+	request.count = dma->buf_count;
+	DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
+
+	copy_to_user_ret((drm_buf_map_t *)arg,
+			 &request,
+			 sizeof(request),
+			 -EFAULT);
+
+	return retcode;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/r128_context.c linux.18p8/drivers/char/drm/r128_context.c
--- linux.vanilla/drivers/char/drm/r128_context.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/r128_context.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,207 @@
+/* r128_context.c -- IOCTLs for r128 contexts -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:35 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Author: Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "r128_drv.h"
+
+extern drm_ctx_t r128_res_ctx;
+
+static int r128_alloc_queue(drm_device_t *dev)
+{
+	return drm_ctxbitmap_next(dev);
+}
+
+int r128_context_switch(drm_device_t *dev, int old, int new)
+{
+        char        buf[64];
+
+        atomic_inc(&dev->total_ctx);
+
+        if (test_and_set_bit(0, &dev->context_flag)) {
+                DRM_ERROR("Reentering -- FIXME\n");
+                return -EBUSY;
+        }
+
+#if DRM_DMA_HISTOGRAM
+        dev->ctx_start = get_cycles();
+#endif
+        
+        DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+        if (new == dev->last_context) {
+                clear_bit(0, &dev->context_flag);
+                return 0;
+        }
+        
+        if (drm_flags & DRM_FLAG_NOCTX) {
+                r128_context_switch_complete(dev, new);
+        } else {
+                sprintf(buf, "C %d %d\n", old, new);
+                drm_write_string(dev, buf);
+        }
+        
+        return 0;
+}
+
+int r128_context_switch_complete(drm_device_t *dev, int new)
+{
+        dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+        dev->last_switch  = jiffies;
+        
+        if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+                DRM_ERROR("Lock isn't held after context switch\n");
+        }
+
+				/* If a context switch is ever initiated
+                                   when the kernel holds the lock, release
+                                   that lock here. */
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+                                                      - dev->ctx_start)]);
+                   
+#endif
+        clear_bit(0, &dev->context_flag);
+        wake_up(&dev->context_wait);
+        
+        return 0;
+}
+
+
+int r128_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			copy_to_user_ret(&res.contexts[i],
+					 &i,
+					 sizeof(i),
+					 -EFAULT);
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+	return 0;
+}
+
+
+int r128_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	if ((ctx.handle = r128_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+				/* Skip kernel's context and get a new one. */
+		ctx.handle = r128_alloc_queue(dev);
+	}
+	DRM_DEBUG("%d\n", ctx.handle);
+	if (ctx.handle == -1) {
+		DRM_DEBUG("Not enough free contexts.\n");
+				/* Should this return -EBUSY instead? */
+		return -ENOMEM;
+	}
+
+	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int r128_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	drm_ctx_t ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+	if (ctx.flags==_DRM_CONTEXT_PRESERVED)
+		r128_res_ctx.handle=ctx.handle;
+	return 0;
+}
+
+int r128_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	drm_ctx_t ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+	/* This is 0, because we don't hanlde any context flags */
+	ctx.flags = 0;
+	copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int r128_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	return r128_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int r128_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	r128_context_switch_complete(dev, ctx.handle);
+
+	return 0;
+}
+
+int r128_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	drm_ctxbitmap_free(dev, ctx.handle);
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/r128_dma.c linux.18p8/drivers/char/drm/r128_dma.c
--- linux.vanilla/drivers/char/drm/r128_dma.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/r128_dma.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,922 @@
+/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
+ * Created: Wed Apr  5 19:24:19 2000 by kevin@precisioninsight.com
+ *
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "r128_drv.h"
+
+#include <linux/interrupt.h>	/* For task queue support */
+#include <linux/delay.h>
+
+
+
+#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size)
+
+#define DO_REMAPFREE(_m)                                                    \
+	do {                                                                \
+		if ((_m)->handle && (_m)->size)                             \
+			drm_ioremapfree((_m)->handle, (_m)->size);          \
+	} while (0)
+
+#define DO_FIND_MAP(_m, _o)                                                 \
+	do {                                                                \
+		int _i;                                                     \
+		for (_i = 0; _i < dev->map_count; _i++) {                   \
+			if (dev->maplist[_i]->offset == _o) {               \
+				_m = dev->maplist[_i];                      \
+				break;                                      \
+			}                                                   \
+		}                                                           \
+	} while (0)
+
+
+#define R128_MAX_VBUF_AGE	0x10000000
+#define R128_VB_AGE_REG		R128_GUI_SCRATCH_REG0
+
+int R128_READ_PLL(drm_device_t *dev, int addr)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+
+	R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
+	return R128_READ(R128_CLOCK_CNTL_DATA);
+}
+
+static void r128_flush_write_combine(void)
+{
+	int xchangeDummy;
+
+	__asm__ volatile("push %%eax ;"
+			 "xchg %%eax, %0 ;"
+			 "pop %%eax" : : "m" (xchangeDummy));
+	__asm__ volatile("push %%eax ;"
+			 "push %%ebx ;"
+			 "push %%ecx ;"
+			 "push %%edx ;"
+			 "movl $0,%%eax ;"
+			 "cpuid ;"
+			 "pop %%edx ;"
+			 "pop %%ecx ;"
+			 "pop %%ebx ;"
+			 "pop %%eax" : /* no outputs */ :  /* no inputs */ );
+}
+
+static void r128_status(drm_device_t *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+
+	printk("GUI_STAT           = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_GUI_STAT));
+	printk("PM4_STAT           = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_PM4_STAT));
+	printk("PM4_BUFFER_DL_WPTR = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR));
+	printk("PM4_BUFFER_DL_RPTR = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR));
+}
+
+static int r128_do_cleanup_cce(drm_device_t *dev)
+{
+	if (dev->dev_private) {
+		drm_r128_private_t *dev_priv = dev->dev_private;
+
+		if (!dev_priv->is_pci) {
+			DO_REMAPFREE(dev_priv->agp_ring);
+			DO_REMAPFREE(dev_priv->agp_read_ptr);
+			DO_REMAPFREE(dev_priv->agp_vertbufs);
+			DO_REMAPFREE(dev_priv->agp_indbufs);
+			DO_REMAPFREE(dev_priv->agp_textures);
+		}
+
+		drm_free(dev->dev_private, sizeof(drm_r128_private_t),
+			 DRM_MEM_DRIVER);
+		dev->dev_private = NULL;
+	}
+
+	return 0;
+}
+
+static int r128_do_init_cce(drm_device_t *dev, drm_r128_init_t *init)
+{
+	drm_r128_private_t *dev_priv;
+        int                 i;
+
+	dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER);
+	if (dev_priv == NULL) return -ENOMEM;
+	dev->dev_private = (void *)dev_priv;
+
+	memset(dev_priv, 0, sizeof(drm_r128_private_t));
+
+	dev_priv->is_pci         = init->is_pci;
+
+	dev_priv->usec_timeout   = init->usec_timeout;
+	if (dev_priv->usec_timeout < 1 ||
+	    dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) {
+		drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+		dev->dev_private = NULL;
+		return -EINVAL;
+	}
+
+	dev_priv->cce_mode       = init->cce_mode;
+	dev_priv->cce_fifo_size  = init->cce_fifo_size;
+	dev_priv->cce_is_bm_mode =
+		((init->cce_mode == R128_PM4_192BM) ||
+		 (init->cce_mode == R128_PM4_128BM_64INDBM) ||
+		 (init->cce_mode == R128_PM4_64BM_128INDBM) ||
+		 (init->cce_mode == R128_PM4_64BM_64VCBM_64INDBM));
+	dev_priv->cce_secure     = init->cce_secure;
+
+	if (dev_priv->cce_is_bm_mode && dev_priv->is_pci) {
+		drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+		dev->dev_private = NULL;
+		return -EINVAL;
+	}
+
+	for (i = 0; i < dev->map_count; i++) {
+		if (dev->maplist[i]->type == _DRM_SHM) {
+			dev_priv->sarea = dev->maplist[i];
+			break;
+		}
+	}
+
+	DO_FIND_MAP(dev_priv->fb,           init->fb_offset);
+	if (!dev_priv->is_pci) {
+		DO_FIND_MAP(dev_priv->agp_ring,     init->agp_ring_offset);
+		DO_FIND_MAP(dev_priv->agp_read_ptr, init->agp_read_ptr_offset);
+		DO_FIND_MAP(dev_priv->agp_vertbufs, init->agp_vertbufs_offset);
+		DO_FIND_MAP(dev_priv->agp_indbufs,  init->agp_indbufs_offset);
+		DO_FIND_MAP(dev_priv->agp_textures, init->agp_textures_offset);
+	}
+	DO_FIND_MAP(dev_priv->mmio,         init->mmio_offset);
+
+	dev_priv->sarea_priv =
+		(drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle +
+				     init->sarea_priv_offset);
+
+	if (!dev_priv->is_pci) {
+		DO_REMAP(dev_priv->agp_ring);
+		DO_REMAP(dev_priv->agp_read_ptr);
+		DO_REMAP(dev_priv->agp_vertbufs);
+#if 0
+		DO_REMAP(dev_priv->agp_indirectbufs);
+		DO_REMAP(dev_priv->agp_textures);
+#endif
+
+		dev_priv->ring_size     = init->ring_size;
+		dev_priv->ring_sizel2qw = drm_order(init->ring_size/8);
+		dev_priv->ring_entries  = init->ring_size/sizeof(u32);
+		dev_priv->ring_read_ptr = ((__volatile__ u32 *)
+					   dev_priv->agp_read_ptr->handle);
+		dev_priv->ring_start    = (u32 *)dev_priv->agp_ring->handle;
+		dev_priv->ring_end      = ((u32 *)dev_priv->agp_ring->handle
+					   + dev_priv->ring_entries);
+	}
+
+	dev_priv->submit_age    = 0;
+	R128_WRITE(R128_VB_AGE_REG, dev_priv->submit_age);
+
+	return 0;
+}
+
+int r128_init_cce(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+        drm_file_t        *priv   = filp->private_data;
+        drm_device_t      *dev    = priv->dev;
+	drm_r128_init_t    init;
+
+	copy_from_user_ret(&init, (drm_r128_init_t *)arg, sizeof(init),
+			   -EFAULT);
+
+	switch (init.func) {
+	case R128_INIT_CCE:
+		return r128_do_init_cce(dev, &init);
+	case R128_CLEANUP_CCE:
+		return r128_do_cleanup_cce(dev);
+	}
+
+	return -EINVAL;
+}
+
+static void r128_mark_vertbufs_done(drm_device_t *dev)
+{
+	drm_device_dma_t   *dma      = dev->dma;
+	int                 i;
+
+	for (i = 0; i < dma->buf_count; i++) {
+		drm_buf_t           *buf      = dma->buflist[i];
+		drm_r128_buf_priv_t *buf_priv = buf->dev_private;
+		buf_priv->age = 0;
+	}
+}
+
+static int r128_do_pixcache_flush(drm_device_t *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	u32                 tmp;
+	int                 i;
+
+	tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL;
+	R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp);
+
+	for (i = 0; i < dev_priv->usec_timeout; i++) {
+		if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY))
+			return 0;
+		udelay(1);
+	}
+
+	return -EBUSY;
+}
+
+static int r128_do_wait_for_fifo(drm_device_t *dev, int entries)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int                 i;
+
+	for (i = 0; i < dev_priv->usec_timeout; i++) {
+		int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK;
+		if (slots >= entries) return 0;
+		udelay(1);
+	}
+	return -EBUSY;
+}
+
+static int r128_do_wait_for_idle(drm_device_t *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int                 i, ret;
+
+	if (!(ret = r128_do_wait_for_fifo(dev, 64))) return ret;
+
+	for (i = 0; i < dev_priv->usec_timeout; i++) {
+		if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) {
+			(void)r128_do_pixcache_flush(dev);
+			return 0;
+		}
+		udelay(1);
+	}
+	return -EBUSY;
+}
+
+int r128_do_engine_reset(drm_device_t *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	u32                 clock_cntl_index, mclk_cntl, gen_reset_cntl;
+
+	(void)r128_do_pixcache_flush(dev);
+
+	clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX);
+	mclk_cntl        = R128_READ_PLL(dev, R128_MCLK_CNTL);
+
+	R128_WRITE_PLL(R128_MCLK_CNTL,
+		       mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
+
+	gen_reset_cntl   = R128_READ(R128_GEN_RESET_CNTL);
+
+	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI);
+	(void)R128_READ(R128_GEN_RESET_CNTL);
+	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI);
+	(void)R128_READ(R128_GEN_RESET_CNTL);
+
+	R128_WRITE_PLL(R128_MCLK_CNTL,    mclk_cntl);
+	R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index);
+	R128_WRITE(R128_GEN_RESET_CNTL,   gen_reset_cntl);
+
+	/* For CCE ring buffer only */
+	if (dev_priv->cce_is_bm_mode) {
+		R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
+		R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
+		*dev_priv->ring_read_ptr = 0;
+		dev_priv->sarea_priv->ring_write = 0;
+	}
+
+	/* Reset the CCE mode */
+	(void)r128_do_wait_for_idle(dev);
+	R128_WRITE(R128_PM4_BUFFER_CNTL,
+		   dev_priv->cce_mode | dev_priv->ring_sizel2qw);
+	(void)R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */
+	R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN);
+
+	r128_mark_vertbufs_done(dev);
+	return 0;
+}
+
+int r128_eng_reset(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+        drm_file_t        *priv   = filp->private_data;
+        drm_device_t      *dev    = priv->dev;
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+	    dev->lock.pid != current->pid) {
+		DRM_ERROR("r128_eng_reset called without holding the lock\n");
+		return -EINVAL;
+	}
+
+	return r128_do_engine_reset(dev);
+}
+
+static int r128_do_engine_flush(drm_device_t *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	u32                 tmp;
+
+	tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR);
+	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp | R128_PM4_BUFFER_DL_DONE);
+
+	return 0;
+}
+
+int r128_eng_flush(struct inode *inode, struct file *filp,
+		   unsigned int cmd, unsigned long arg)
+{
+        drm_file_t        *priv   = filp->private_data;
+        drm_device_t      *dev    = priv->dev;
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+	    dev->lock.pid != current->pid) {
+		DRM_ERROR("r128_eng_flush called without holding the lock\n");
+		return -EINVAL;
+	}
+
+	return r128_do_engine_flush(dev);
+}
+
+static int r128_do_cce_wait_for_fifo(drm_device_t *dev, int entries)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int                 i;
+
+	for (i = 0; i < dev_priv->usec_timeout; i++) {
+		int slots = R128_READ(R128_PM4_STAT) & R128_PM4_FIFOCNT_MASK;
+		if (slots >= entries) return 0;
+		udelay(1);
+	}
+	return -EBUSY;
+}
+
+int r128_do_cce_wait_for_idle(drm_device_t *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int                 i;
+
+	if (dev_priv->cce_is_bm_mode) {
+		for (i = 0; i < dev_priv->usec_timeout; i++) {
+			if (*dev_priv->ring_read_ptr == dev_priv->sarea_priv->ring_write) {
+				int pm4stat = R128_READ(R128_PM4_STAT);
+				if ((pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size &&
+				    !(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) {
+					return r128_do_pixcache_flush(dev);
+				}
+			}
+			udelay(1);
+		}
+		return -EBUSY;
+	} else {
+		int ret = r128_do_cce_wait_for_fifo(dev, dev_priv->cce_fifo_size);
+		if (ret < 0) return ret;
+
+		for (i = 0; i < dev_priv->usec_timeout; i++) {
+			int pm4stat = R128_READ(R128_PM4_STAT);
+			if (!(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) {
+				return r128_do_pixcache_flush(dev);
+			}
+			udelay(1);
+		}
+		return -EBUSY;
+	}
+}
+
+int r128_cce_idle(struct inode *inode, struct file *filp,
+		  unsigned int cmd, unsigned long arg)
+{
+        drm_file_t         *priv     = filp->private_data;
+        drm_device_t       *dev      = priv->dev;
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+	    dev->lock.pid != current->pid) {
+		DRM_ERROR("r128_wait_idle called without holding the lock\n");
+		return -EINVAL;
+	}
+
+	return r128_do_cce_wait_for_idle(dev);
+}
+
+static int r128_submit_packets_ring_secure(drm_device_t *dev,
+					   u32 *commands, int *count)
+{
+	drm_r128_private_t *dev_priv  = dev->dev_private;
+	int                 write     = dev_priv->sarea_priv->ring_write;
+	int                *write_ptr = dev_priv->ring_start + write;
+	int                 c         = *count;
+	u32                 tmp       = 0;
+	int                 psize     = 0;
+	int                 writing   = 1;
+	int                 timeout;
+
+	while (c > 0) {
+		tmp = *commands++;
+		if (!psize) {
+			writing = 1;
+
+			if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) {
+				if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) {
+					if ((tmp & R128_CCE_PACKET0_REG_MASK) !=
+					    (R128_PM4_VC_FPU_SETUP >> 2)) {
+						writing = 0;
+					}
+				}
+				psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2;
+			} else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) {
+				if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) {
+					if ((tmp & R128_CCE_PACKET1_REG0_MASK) !=
+					    (R128_PM4_VC_FPU_SETUP >> 2)) {
+						writing = 0;
+					}
+				} else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <=
+					   (0x1004 << 9)) {
+					if ((tmp & R128_CCE_PACKET1_REG1_MASK) !=
+					    (R128_PM4_VC_FPU_SETUP << 9)) {
+						writing = 0;
+					}
+				}
+				psize = 3;
+			} else {
+				psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2;
+			}
+		}
+		psize--;
+
+		if (writing) {
+			write++;
+			*write_ptr++ = tmp;
+		}
+		if (write >= dev_priv->ring_entries) {
+			write     = 0;
+			write_ptr = dev_priv->ring_start;
+		}
+		timeout = 0;
+		while (write == *dev_priv->ring_read_ptr) {
+			(void)R128_READ(R128_PM4_BUFFER_DL_RPTR);
+			if (timeout++ >= dev_priv->usec_timeout)
+				return -EBUSY;
+			udelay(1);
+		}
+		c--;
+	}
+
+	if (write < 32)
+	    memcpy(dev_priv->ring_end,
+		   dev_priv->ring_start,
+		   write * sizeof(u32));
+
+	/* Make sure WC cache has been flushed */
+	r128_flush_write_combine();
+
+	dev_priv->sarea_priv->ring_write = write;
+	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write);
+
+	*count = 0;
+
+	return 0;
+}
+
+static int r128_submit_packets_pio_secure(drm_device_t *dev,
+					  u32 *commands, int *count)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	u32                 tmp      = 0;
+	int                 psize    = 0;
+	int                 writing  = 1;
+	int                 addr     = R128_PM4_FIFO_DATA_EVEN;
+	int                 ret;
+
+	while (*count > 0) {
+		tmp = *commands++;
+		if (!psize) {
+			writing = 1;
+
+			if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) {
+				if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) {
+					if ((tmp & R128_CCE_PACKET0_REG_MASK) !=
+					    (R128_PM4_VC_FPU_SETUP >> 2)) {
+						writing = 0;
+					}
+				}
+				psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2;
+			} else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) {
+				if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) {
+					if ((tmp & R128_CCE_PACKET1_REG0_MASK) !=
+					    (R128_PM4_VC_FPU_SETUP >> 2)) {
+						writing = 0;
+					}
+				} else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <=
+					   (0x1004 << 9)) {
+					if ((tmp & R128_CCE_PACKET1_REG1_MASK) !=
+					    (R128_PM4_VC_FPU_SETUP << 9)) {
+						writing = 0;
+					}
+				}
+				psize = 3;
+			} else {
+				psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2;
+			}
+		}
+		psize--;
+
+		if (writing) {
+			if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0)
+				return ret;
+			R128_WRITE(addr, tmp);
+			addr ^= 0x0004;
+		}
+
+		*count -= 1;
+	}
+
+	if (addr == R128_PM4_FIFO_DATA_ODD) {
+		if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) return ret;
+		R128_WRITE(addr, R128_CCE_PACKET2);
+	}
+
+	return 0;
+}
+
+static int r128_submit_packets_ring(drm_device_t *dev,
+				    u32 *commands, int *count)
+{
+	drm_r128_private_t *dev_priv  = dev->dev_private;
+	int                 write     = dev_priv->sarea_priv->ring_write;
+	int                *write_ptr = dev_priv->ring_start + write;
+	int                 c         = *count;
+	int                 timeout;
+
+	while (c > 0) {
+		write++;
+		*write_ptr++ = *commands++;
+		if (write >= dev_priv->ring_entries) {
+			write     = 0;
+			write_ptr = dev_priv->ring_start;
+		}
+		timeout = 0;
+		while (write == *dev_priv->ring_read_ptr) {
+			(void)R128_READ(R128_PM4_BUFFER_DL_RPTR);
+			if (timeout++ >= dev_priv->usec_timeout)
+				return -EBUSY;
+			udelay(1);
+		}
+		c--;
+	}
+
+	if (write < 32)
+	    memcpy(dev_priv->ring_end,
+		   dev_priv->ring_start,
+		   write * sizeof(u32));
+
+	/* Make sure WC cache has been flushed */
+	r128_flush_write_combine();
+
+	dev_priv->sarea_priv->ring_write = write;
+	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write);
+
+	*count = 0;
+
+	return 0;
+}
+
+static int r128_submit_packets_pio(drm_device_t *dev,
+				   u32 *commands, int *count)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int                 ret;
+
+	while (*count > 1) {
+		if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret;
+		R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++);
+		R128_WRITE(R128_PM4_FIFO_DATA_ODD,  *commands++);
+		*count -= 2;
+	}
+
+	if (*count) {
+		if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret;
+		R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++);
+		R128_WRITE(R128_PM4_FIFO_DATA_ODD,  R128_CCE_PACKET2);
+		*count = 0;
+	}
+
+	return 0;
+}
+
+static int r128_do_submit_packets(drm_device_t *dev, u32 *buffer, int count)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int                 c = count;
+	int                 ret;
+
+	if (dev_priv->cce_is_bm_mode) {
+		int left = 0;
+
+		if (c >= dev_priv->ring_entries) {
+			c    = dev_priv->ring_entries-1;
+			left = count - c;
+		}
+
+		/* Since this is only used by the kernel we can use the
+                   insecure ring buffer submit packet routine */
+		ret = r128_submit_packets_ring(dev, buffer, &c);
+
+		c += left;
+	} else {
+		/* Since this is only used by the kernel we can use the
+                   insecure PIO submit packet routine */
+		ret = r128_submit_packets_pio(dev, buffer, &c);
+	}
+
+	if (ret < 0) return ret;
+	else         return c;
+}
+
+int r128_submit_pkt(struct inode *inode, struct file *filp,
+		    unsigned int cmd, unsigned long arg)
+{
+        drm_file_t         *priv     = filp->private_data;
+        drm_device_t       *dev      = priv->dev;
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_packet_t   packet;
+	u32                *buffer;
+	int                 c;
+	int                 size;
+	int                 ret = 0;
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+	    dev->lock.pid != current->pid) {
+		DRM_ERROR("r128_submit_pkt called without holding the lock\n");
+		return -EINVAL;
+	}
+
+	copy_from_user_ret(&packet, (drm_r128_packet_t *)arg, sizeof(packet),
+			   -EFAULT);
+
+	c    = packet.count;
+	size = c * sizeof(*buffer);
+
+	if (dev_priv->cce_is_bm_mode) {
+		int left = 0;
+
+		if (c >= dev_priv->ring_entries) {
+			c    = dev_priv->ring_entries-1;
+			size = c * sizeof(*buffer);
+			left = packet.count - c;
+		}
+
+		if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM;
+		copy_from_user_ret(buffer, packet.buffer, size, -EFAULT);
+
+		if (dev_priv->cce_secure)
+			ret = r128_submit_packets_ring_secure(dev, buffer, &c);
+		else
+			ret = r128_submit_packets_ring(dev, buffer, &c);
+
+		c += left;
+	} else {
+		if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM;
+		copy_from_user_ret(buffer, packet.buffer, size, -EFAULT);
+
+		if (dev_priv->cce_secure)
+			ret = r128_submit_packets_pio_secure(dev, buffer, &c);
+		else
+			ret = r128_submit_packets_pio(dev, buffer, &c);
+	}
+
+	kfree(buffer);
+
+	packet.count = c;
+	copy_to_user_ret((drm_r128_packet_t *)arg, &packet, sizeof(packet),
+			 -EFAULT);
+
+	if (ret)        return ret;
+	else if (c > 0) return -EAGAIN;
+
+	return 0;
+}
+
+static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v)
+{
+	drm_device_dma_t    *dma      = dev->dma;
+	drm_r128_private_t  *dev_priv = dev->dev_private;
+	drm_r128_buf_priv_t *buf_priv;
+	drm_buf_t           *buf;
+	int                  i, ret;
+	u32                  cce[2];
+
+	/* Make sure we have valid data */
+	for (i = 0; i < v->send_count; i++) {
+		int idx = v->send_indices[i];
+
+		if (idx < 0 || idx >= dma->buf_count) {
+			DRM_ERROR("Index %d (of %d max)\n",
+				  idx, dma->buf_count - 1);
+			return -EINVAL;
+		}
+		buf = dma->buflist[idx];
+		if (buf->pid != current->pid) {
+			DRM_ERROR("Process %d using buffer owned by %d\n",
+				  current->pid, buf->pid);
+			return -EINVAL;
+		}
+		if (buf->pending) {
+			DRM_ERROR("Sending pending buffer:"
+				  " buffer %d, offset %d\n",
+				  v->send_indices[i], i);
+			return -EINVAL;
+		}
+	}
+
+	/* Wait for idle, if we've wrapped to make sure that all pending
+           buffers have been processed */
+	if (dev_priv->submit_age == R128_MAX_VBUF_AGE) {
+		if ((ret = r128_do_cce_wait_for_idle(dev)) < 0) return ret;
+		dev_priv->submit_age = 0;
+		r128_mark_vertbufs_done(dev);
+	}
+
+	/* Make sure WC cache has been flushed (if in PIO mode) */
+	if (!dev_priv->cce_is_bm_mode) r128_flush_write_combine();
+
+	/* FIXME: Add support for sending vertex buffer to the CCE here
+	   instead of in client code.  The v->prim holds the primitive
+	   type that should be drawn.  Loop over the list buffers in
+	   send_indices[] and submit a packet for each VB.
+
+	   This will require us to loop over the clip rects here as
+	   well, which implies that we extend the kernel driver to allow
+	   cliprects to be stored here.  Note that the cliprects could
+	   possibly come from the X server instead of the client, but
+	   this will require additional changes to the DRI to allow for
+	   this optimization. */
+
+	/* Submit a CCE packet that writes submit_age to R128_VB_AGE_REG */
+	cce[0] = R128CCE0(R128_CCE_PACKET0, R128_VB_AGE_REG, 0);
+	cce[1] = dev_priv->submit_age;
+	if ((ret = r128_do_submit_packets(dev, cce, 2)) < 0) {
+		/* Until we add support for sending VBs to the CCE in
+		   this routine, we can recover from this error.  After
+		   we add that support, we won't be able to easily
+		   recover, so we will probably have to implement
+		   another mechanism for handling timeouts from packets
+		   submitted directly by the kernel. */
+		return ret;
+	}
+
+	/* Now that the submit packet request has succeeded, we can mark
+           the buffers as pending */
+	for (i = 0; i < v->send_count; i++) {
+		buf = dma->buflist[v->send_indices[i]];
+		buf->pending = 1;
+
+		buf_priv      = buf->dev_private;
+		buf_priv->age = dev_priv->submit_age;
+	}
+
+	dev_priv->submit_age++;
+
+	return 0;
+}
+
+static drm_buf_t *r128_freelist_get(drm_device_t *dev)
+{
+	drm_device_dma_t    *dma      = dev->dma;
+	drm_r128_private_t  *dev_priv = dev->dev_private;
+	drm_r128_buf_priv_t *buf_priv;
+	drm_buf_t           *buf;
+	int                  i, t;
+
+	/* FIXME: Optimize -- use freelist code */
+
+	for (i = 0; i < dma->buf_count; i++) {
+		buf = dma->buflist[i];
+		buf_priv = buf->dev_private;
+		if (buf->pid == 0) return buf;
+	}
+
+	for (t = 0; t < dev_priv->usec_timeout; t++) {
+		u32 done_age = R128_READ(R128_VB_AGE_REG);
+
+		for (i = 0; i < dma->buf_count; i++) {
+			buf = dma->buflist[i];
+			buf_priv = buf->dev_private;
+			if (buf->pending && buf_priv->age <= done_age) {
+				/* The buffer has been processed, so it
+                                   can now be used */
+				buf->pending = 0;
+				return buf;
+			}
+		}
+		udelay(1);
+	}
+
+	r128_status(dev);
+	return NULL;
+}
+
+
+static int r128_get_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v)
+{
+	drm_buf_t *buf;
+	int        i;
+
+	for (i = v->granted_count; i < v->request_count; i++) {
+		buf = r128_freelist_get(dev);
+		if (!buf) break;
+		buf->pid = current->pid;
+		copy_to_user_ret(&v->request_indices[i],
+				 &buf->idx,
+				 sizeof(buf->idx),
+				 -EFAULT);
+		copy_to_user_ret(&v->request_sizes[i],
+				 &buf->total,
+				 sizeof(buf->total),
+				 -EFAULT);
+		++v->granted_count;
+	}
+	return 0;
+}
+
+int r128_vertex_buf(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	drm_file_t	   *priv     = filp->private_data;
+	drm_device_t	   *dev	     = priv->dev;
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_device_dma_t   *dma	     = dev->dma;
+	int		    retcode  = 0;
+	drm_r128_vertex_t   v;
+
+	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ||
+	    dev->lock.pid != current->pid) {
+		DRM_ERROR("r128_vertex_buf called without holding the lock\n");
+		return -EINVAL;
+	}
+
+	if (!dev_priv || dev_priv->is_pci) {
+		DRM_ERROR("r128_vertex_buf called with a PCI card\n");
+		return -EINVAL;
+	}
+
+	copy_from_user_ret(&v, (drm_r128_vertex_t *)arg, sizeof(v), -EFAULT);
+	DRM_DEBUG("%d: %d send, %d req\n",
+		  current->pid, v.send_count, v.request_count);
+
+	if (v.send_count < 0 || v.send_count > dma->buf_count) {
+		DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
+			  current->pid, v.send_count, dma->buf_count);
+		return -EINVAL;
+	}
+	if (v.request_count < 0 || v.request_count > dma->buf_count) {
+		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+			  current->pid, v.request_count, dma->buf_count);
+		return -EINVAL;
+	}
+
+	if (v.send_count) {
+		retcode = r128_send_vertbufs(dev, &v);
+	}
+
+	v.granted_count = 0;
+
+	if (!retcode && v.request_count) {
+		retcode = r128_get_vertbufs(dev, &v);
+	}
+
+	DRM_DEBUG("%d returning, granted = %d\n",
+		  current->pid, v.granted_count);
+	copy_to_user_ret((drm_r128_vertex_t *)arg, &v, sizeof(v), -EFAULT);
+
+	return retcode;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/r128_drm.h linux.18p8/drivers/char/drm/r128_drm.h
--- linux.vanilla/drivers/char/drm/r128_drm.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/r128_drm.h	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,111 @@
+/* r128_drm.h -- Public header for the r128 driver -*- linux-c -*-
+ * Created: Wed Apr  5 19:24:19 2000 by kevin@precisioninsight.com
+ *
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#ifndef _R128_DRM_H_
+#define _R128_DRM_H_
+
+/* WARNING: If you change any of these defines, make sure to change the
+ * defines in the Xserver file (xf86drmR128.h)
+ */
+typedef struct drm_r128_init {
+	enum { 
+		R128_INIT_CCE    = 0x01,
+		R128_CLEANUP_CCE = 0x02
+	} func;
+	int sarea_priv_offset;
+	int is_pci;
+	int cce_mode;
+	int cce_fifo_size;
+	int cce_secure;
+	int ring_size;
+	int usec_timeout;
+
+	int fb_offset;
+	int agp_ring_offset;
+	int agp_read_ptr_offset;
+	int agp_vertbufs_offset;
+	int agp_indbufs_offset;
+	int agp_textures_offset;
+	int mmio_offset;
+} drm_r128_init_t;
+
+typedef struct drm_r128_packet {
+	unsigned long *buffer;
+	int            count;
+	int            flags;
+} drm_r128_packet_t;
+
+typedef enum drm_r128_prim {
+	_DRM_R128_PRIM_NONE		= 0x0001,
+	_DRM_R128_PRIM_POINT		= 0x0002,
+	_DRM_R128_PRIM_LINE		= 0x0004,
+	_DRM_R128_PRIM_POLY_LINE	= 0x0008,
+	_DRM_R128_PRIM_TRI_LIST		= 0x0010,
+	_DRM_R128_PRIM_TRI_FAN		= 0x0020,
+	_DRM_R128_PRIM_TRI_STRIP	= 0x0040,
+	_DRM_R128_PRIM_TRI_TYPE2	= 0x0080
+} drm_r128_prim_t;
+
+typedef struct drm_r128_vertex {
+				/* Indices here refer to the offset into
+				   buflist in drm_buf_get_t.  */
+	int		send_count;	  /* Number of buffers to send	    */
+	int		*send_indices;	  /* List of handles to buffers	    */
+	int		*send_sizes;	  /* Lengths of data to send	    */
+	drm_r128_prim_t	prim;		  /* Primitive type		    */
+	int		request_count;	  /* Number of buffers requested    */
+	int		*request_indices; /* Buffer information		    */
+	int		*request_sizes;
+	int		granted_count;	  /* Number of buffers granted	    */
+} drm_r128_vertex_t;
+
+/* WARNING: If you change any of these defines, make sure to change the
+ * defines in the Xserver file (r128_sarea.h)
+ */
+#define R128_LOCAL_TEX_HEAP       0
+#define R128_AGP_TEX_HEAP         1
+#define R128_NR_TEX_HEAPS         2
+#define R128_NR_TEX_REGIONS      64
+#define R128_LOG_TEX_GRANULARITY 16
+
+typedef struct drm_tex_region {
+	unsigned char next, prev;       
+	unsigned char in_use;   
+	int age;                        
+} drm_tex_region_t;
+
+typedef struct drm_r128_sarea {
+	drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1];
+	int              tex_age[R128_NR_TEX_HEAPS];
+	int              ctx_owner;
+	int              ring_write;
+} drm_r128_sarea_t;
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/r128_drv.c linux.18p8/drivers/char/drm/r128_drv.c
--- linux.vanilla/drivers/char/drm/r128_drv.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/r128_drv.c	Fri Sep  1 14:14:35 2000
@@ -0,0 +1,731 @@
+/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *          Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "r128_drv.h"
+
+#include <linux/agp_backend.h>
+
+static __attribute__((unused)) void unused(void)
+{
+	agp_enable(0);
+}
+
+#define R128_NAME	 "r128"
+#define R128_DESC	 "ATI Rage 128"
+#define R128_DATE	 "20000719"
+#define R128_MAJOR	 1
+#define R128_MINOR	 0
+#define R128_PATCHLEVEL  0
+
+static drm_device_t	      r128_device;
+drm_ctx_t	              r128_res_ctx;
+
+static struct file_operations r128_fops = {
+#if LINUX_VERSION_CODE >= 0x020322
+				/* This started being used approx. 2.3.34 */
+	owner:   THIS_MODULE,
+#endif
+	open:	 r128_open,
+	flush:	 drm_flush,
+	release: r128_release,
+	ioctl:	 r128_ioctl,
+	mmap:	 drm_mmap,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+	poll:	 drm_poll,
+};
+
+static struct miscdevice      r128_misc = {
+	minor: MISC_DYNAMIC_MINOR,
+	name:  R128_NAME,
+	fops:  &r128_fops,
+};
+
+static drm_ioctl_desc_t	      r128_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]     = { r128_version,	   0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)]  = { drm_getunique,   0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]   = { drm_getmagic,	   0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]   = { drm_irq_busid,   0, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)]  = { drm_setunique,   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	      = { drm_block,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]     = { drm_unblock,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)]  = { drm_authmagic,   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]     = { drm_addmap,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)]    = { r128_addbufs,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]   = { drm_markbufs,    1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]   = { drm_infobufs,    1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]    = { r128_mapbufs,	   1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]   = { drm_freebufs,    1, 0 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]     = { r128_addctx,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]      = { r128_rmctx,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]     = { r128_modctx,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]     = { r128_getctx,	   1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]  = { r128_switchctx,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]     = { r128_newctx,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]     = { r128_resctx,	   1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]    = { drm_adddraw,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]     = { drm_rmdraw,	   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	      = { r128_lock,	   1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]      = { r128_unlock,	   1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]      = { drm_finish,	   1, 0 },
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { drm_agp_acquire, 1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { drm_agp_release, 1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]  = { drm_agp_enable,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]    = { drm_agp_info,    1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)]   = { drm_agp_alloc,   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)]    = { drm_agp_free,    1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)]    = { drm_agp_bind,    1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)]  = { drm_agp_unbind,  1, 1 },
+#endif
+
+	[DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)]   = { r128_init_cce,   1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)]  = { r128_eng_reset,  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_R128_FLUSH)]  = { r128_eng_flush,  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_submit_pkt, 1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_R128_IDLE)]   = { r128_cce_idle,   1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_vertex_buf, 1, 0 },
+};
+#define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls)
+
+#ifdef MODULE
+static char		      *r128 = NULL;
+#endif
+
+MODULE_AUTHOR("VA Linux Systems, Inc.");
+MODULE_DESCRIPTION("r128");
+MODULE_PARM(r128, "s");
+
+#ifndef MODULE
+/* r128_options is called by the kernel to parse command-line options
+ * passed via the boot-loader (e.g., LILO).  It calls the insmod option
+ * routine, drm_parse_drm.
+ */
+
+static int __init r128_options(char *str)
+{
+	drm_parse_options(str);
+	return 1;
+}
+
+__setup("r128=", r128_options);
+#endif
+
+static int r128_setup(drm_device_t *dev)
+{
+	int i;
+
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use	  = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	drm_dma_setup(dev);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+
+	r128_res_ctx.handle=-1;
+
+	DRM_DEBUG("\n");
+
+	/* The kernel's context could be created here, but is now created
+	   in drm_dma_enqueue.	This is more resource-efficient for
+	   hardware that does not do DMA, but may mean that
+	   drm_select_queue fails between the time the interrupt is
+	   initialized and the time the queues are initialized. */
+
+	return 0;
+}
+
+
+static int r128_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+				/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+				/* Clear AGP information */
+	if (dev->agp) {
+		drm_agp_mem_t *entry;
+		drm_agp_mem_t *nexte;
+
+				/* Remove AGP resources, but leave dev->agp
+                                   intact until r128_cleanup is called. */
+		for (entry = dev->agp->memory; entry; entry = nexte) {
+			nexte = entry->next;
+			if (entry->bound) drm_unbind_agp(entry->memory);
+			drm_free_agp(entry->memory, entry->pages);
+			drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
+		}
+		dev->agp->memory = NULL;
+
+		if (dev->agp->acquired && drm_agp.release)
+			(*drm_agp.release)();
+
+		dev->agp->acquired = 0;
+		dev->agp->enabled  = 0;
+	}
+#endif
+
+				/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+
+				/* Clear map area and mtrr information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+				if (map->mtrr >= 0) {
+					int retcode;
+					retcode = mtrr_del(map->mtrr,
+							   map->offset,
+							   map->size);
+					DRM_DEBUG("mtrr_del = %d\n", retcode);
+				}
+#endif
+				drm_ioremapfree(map->handle, map->size);
+				break;
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+			case _DRM_AGP:
+				/* Do nothing here, because this is all
+                                   handled in the AGP/GART driver. */
+				break;
+			}
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+
+	drm_dma_takedown(dev);
+
+	dev->queue_count     = 0;
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+
+	return 0;
+}
+
+/* r128_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+static int r128_init(void)
+{
+	int		      retcode;
+	drm_device_t	      *dev = &r128_device;
+
+	DRM_DEBUG("\n");
+
+	memset((void *)dev, 0, sizeof(*dev));
+	dev->count_lock	  = SPIN_LOCK_UNLOCKED;
+	sema_init(&dev->struct_sem, 1);
+
+#ifdef MODULE
+	drm_parse_options(r128);
+#endif
+
+	if ((retcode = misc_register(&r128_misc))) {
+		DRM_ERROR("Cannot register \"%s\"\n", R128_NAME);
+		return retcode;
+	}
+	dev->device = MKDEV(MISC_MAJOR, r128_misc.minor);
+	dev->name   = R128_NAME;
+
+	drm_mem_init();
+	drm_proc_init(dev);
+
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	dev->agp    = drm_agp_init();
+      	if (dev->agp == NULL) {
+	   	DRM_ERROR("Cannot initialize agpgart module.\n");
+	   	drm_proc_cleanup();
+	   	misc_deregister(&r128_misc);
+	   	r128_takedown(dev);
+	   	return -ENOMEM;
+	}
+
+#ifdef CONFIG_MTRR
+	dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base,
+				      dev->agp->agp_info.aper_size*1024*1024,
+				      MTRR_TYPE_WRCOMB,
+				      1);
+#endif
+#endif
+
+	if((retcode = drm_ctxbitmap_init(dev))) {
+		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+		drm_proc_cleanup();
+		misc_deregister(&r128_misc);
+		r128_takedown(dev);
+		return retcode;
+	}
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+		 R128_NAME,
+		 R128_MAJOR,
+		 R128_MINOR,
+		 R128_PATCHLEVEL,
+		 R128_DATE,
+		 r128_misc.minor);
+
+	return 0;
+}
+
+/* r128_cleanup is called via cleanup_module at module unload time. */
+
+static void r128_cleanup(void)
+{
+	drm_device_t	      *dev = &r128_device;
+
+	DRM_DEBUG("\n");
+
+	drm_proc_cleanup();
+	if (misc_deregister(&r128_misc)) {
+		DRM_ERROR("Cannot unload module\n");
+	} else {
+		DRM_INFO("Module unloaded\n");
+	}
+	drm_ctxbitmap_cleanup(dev);
+	r128_takedown(dev);
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	if (dev->agp) {
+		drm_agp_uninit();
+		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+		dev->agp = NULL;
+	}
+#endif
+}
+
+module_init(r128_init);
+module_exit(r128_cleanup);
+
+
+int r128_version(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_version_t version;
+	int	      len;
+
+	copy_from_user_ret(&version,
+			   (drm_version_t *)arg,
+			   sizeof(version),
+			   -EFAULT);
+
+#define DRM_COPY(name,value)				     \
+	len = strlen(value);				     \
+	if (len > name##_len) len = name##_len;		     \
+	name##_len = strlen(value);			     \
+	if (len && name) {				     \
+		copy_to_user_ret(name, value, len, -EFAULT); \
+	}
+
+	version.version_major	   = R128_MAJOR;
+	version.version_minor	   = R128_MINOR;
+	version.version_patchlevel = R128_PATCHLEVEL;
+
+	DRM_COPY(version.name, R128_NAME);
+	DRM_COPY(version.date, R128_DATE);
+	DRM_COPY(version.desc, R128_DESC);
+
+	copy_to_user_ret((drm_version_t *)arg,
+			 &version,
+			 sizeof(version),
+			 -EFAULT);
+	return 0;
+}
+
+int r128_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t  *dev    = &r128_device;
+	int	      retcode = 0;
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return r128_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	
+	return retcode;
+}
+
+int r128_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev;
+	int	      retcode = 0;
+
+	lock_kernel();
+	dev = priv->dev;
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_release(inode, filp))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_close);
+		spin_lock(&dev->count_lock);
+		if (!--dev->open_count) {
+			if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+				DRM_ERROR("Device busy: %d %d\n",
+					  atomic_read(&dev->ioctl_count),
+					  dev->blocked);
+				spin_unlock(&dev->count_lock);
+				unlock_kernel();
+				return -EBUSY;
+			}
+			spin_unlock(&dev->count_lock);
+			unlock_kernel();
+			return r128_takedown(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	
+	unlock_kernel();
+	return retcode;
+}
+
+/* r128_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int r128_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int		 retcode = 0;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= R128_IOCTL_COUNT) {
+		retcode = -EINVAL;
+	} else {
+		ioctl	  = &r128_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			retcode = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			retcode = -EACCES;
+		} else {
+			retcode = (func)(inode, filp, cmd, arg);
+		}
+	}
+
+	atomic_dec(&dev->ioctl_count);
+	return retcode;
+}
+
+int r128_lock(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+        drm_file_t        *priv   = filp->private_data;
+        drm_device_t      *dev    = priv->dev;
+        DECLARE_WAITQUEUE(entry, current);
+        int               ret   = 0;
+        drm_lock_t        lock;
+#if DRM_DMA_HISTOGRAM
+        cycles_t          start;
+
+        dev->lck_start = start = get_cycles();
+#endif
+
+        copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+        if (lock.context == DRM_KERNEL_CONTEXT) {
+                DRM_ERROR("Process %d using kernel context %d\n",
+                          current->pid, lock.context);
+                return -EINVAL;
+        }
+
+        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+                  lock.context, current->pid, dev->lock.hw_lock->lock,
+                  lock.flags);
+
+#if 0
+				/* dev->queue_count == 0 right now for
+                                   r128.  FIXME? */
+        if (lock.context < 0 || lock.context >= dev->queue_count)
+                return -EINVAL;
+#endif
+
+        if (!ret) {
+#if 0
+                if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+                    != lock.context) {
+                        long j = jiffies - dev->lock.lock_time;
+
+                        if (lock.context == r128_res_ctx.handle &&
+				j >= 0 && j < DRM_LOCK_SLICE) {
+                                /* Can't take lock if we just had it and
+                                   there is contention. */
+                                DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n",
+					lock.context, current->pid, j,
+					dev->lock.lock_time, jiffies);
+                                current->state = TASK_INTERRUPTIBLE;
+				current->policy |= SCHED_YIELD;
+                                schedule_timeout(DRM_LOCK_SLICE-j);
+				DRM_DEBUG("jiffies=%d\n", jiffies);
+                        }
+                }
+#endif
+                add_wait_queue(&dev->lock.lock_queue, &entry);
+                for (;;) {
+                        if (!dev->lock.hw_lock) {
+                                /* Device has been unregistered */
+                                ret = -EINTR;
+                                break;
+                        }
+                        if (drm_lock_take(&dev->lock.hw_lock->lock,
+                                          lock.context)) {
+                                dev->lock.pid       = current->pid;
+                                dev->lock.lock_time = jiffies;
+                                atomic_inc(&dev->total_locks);
+                                break;  /* Got lock */
+                        }
+
+                                /* Contention */
+                        atomic_inc(&dev->total_sleeps);
+                        current->state = TASK_INTERRUPTIBLE;
+#if 1
+			current->policy |= SCHED_YIELD;
+#endif
+                        schedule();
+                        if (signal_pending(current)) {
+                                ret = -ERESTARTSYS;
+                                break;
+                        }
+                }
+                current->state = TASK_RUNNING;
+                remove_wait_queue(&dev->lock.lock_queue, &entry);
+        }
+
+#if 0
+	if (!ret && dev->last_context != lock.context &&
+		lock.context != r128_res_ctx.handle &&
+		dev->last_context != r128_res_ctx.handle) {
+		add_wait_queue(&dev->context_wait, &entry);
+	        current->state = TASK_INTERRUPTIBLE;
+                /* PRE: dev->last_context != lock.context */
+	        r128_context_switch(dev, dev->last_context, lock.context);
+		/* POST: we will wait for the context
+                   switch and will dispatch on a later call
+                   when dev->last_context == lock.context
+                   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+                   TIME! */
+		current->policy |= SCHED_YIELD;
+	        schedule();
+	        current->state = TASK_RUNNING;
+	        remove_wait_queue(&dev->context_wait, &entry);
+	        if (signal_pending(current)) {
+	                ret = -EINTR;
+	        } else if (dev->last_context != lock.context) {
+			DRM_ERROR("Context mismatch: %d %d\n",
+                        	dev->last_context, lock.context);
+	        }
+	}
+#endif
+
+        if (!ret) {
+                if (lock.flags & _DRM_LOCK_READY) {
+				/* Wait for space in DMA/FIFO */
+		}
+                if (lock.flags & _DRM_LOCK_QUIESCENT) {
+				/* Make hardware quiescent */
+#if 0
+                        r128_quiescent(dev);
+#endif
+		}
+        }
+
+#if LINUX_VERSION_CODE < 0x020400
+	if (lock.context != r128_res_ctx.handle) {
+		current->counter = 5;
+		current->priority = DEF_PRIORITY/4;
+	}
+#endif
+        DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+
+        return ret;
+}
+
+
+int r128_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+				/* FIXME: Try to send data to card here */
+	if (!dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+
+#if LINUX_VERSION_CODE < 0x020400
+	if (lock.context != r128_res_ctx.handle) {
+		current->counter = 5;
+		current->priority = DEF_PRIORITY;
+	}
+#endif
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/r128_drv.h linux.18p8/drivers/char/drm/r128_drv.h
--- linux.vanilla/drivers/char/drm/r128_drv.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/r128_drv.h	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,224 @@
+/* r128_drv.h -- Private header for r128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
+ *          Kevin E. Martin <martin@valinux.com>
+ *
+ */
+
+#ifndef _R128_DRV_H_
+#define _R128_DRV_H_
+
+typedef struct drm_r128_private {
+	int               is_pci;
+
+	int               cce_mode;
+	int               cce_fifo_size;
+	int               cce_is_bm_mode;
+	int               cce_secure;
+
+	drm_r128_sarea_t *sarea_priv;
+
+	__volatile__ u32 *ring_read_ptr;
+
+	u32              *ring_start;
+	u32              *ring_end;
+	int               ring_size;
+	int               ring_sizel2qw;
+	int               ring_entries;
+
+	int               submit_age;
+
+	int               usec_timeout;
+
+	drm_map_t        *sarea;
+	drm_map_t        *fb;
+	drm_map_t        *agp_ring;
+	drm_map_t        *agp_read_ptr;
+	drm_map_t        *agp_vertbufs;
+	drm_map_t        *agp_indbufs;
+	drm_map_t        *agp_textures;
+	drm_map_t        *mmio;
+} drm_r128_private_t;
+
+typedef struct drm_r128_buf_priv {
+	u32               age;
+} drm_r128_buf_priv_t;
+
+				/* r128_drv.c */
+extern int  r128_version(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  r128_open(struct inode *inode, struct file *filp);
+extern int  r128_release(struct inode *inode, struct file *filp);
+extern int  r128_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  r128_lock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  r128_unlock(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+				/* r128_dma.c */
+extern int r128_init_cce(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+extern int r128_eng_reset(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int r128_eng_flush(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int r128_submit_pkt(struct inode *inode, struct file *filp,
+			   unsigned int cmd, unsigned long arg);
+extern int r128_cce_idle(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+extern int r128_vertex_buf(struct inode *inode, struct file *filp,
+			   unsigned int cmd, unsigned long arg);
+
+				/* r128_bufs.c */
+extern int r128_addbufs(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int r128_mapbufs(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+
+				/* r128_context.c */
+extern int  r128_resctx(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  r128_addctx(struct inode *inode, struct file *filp,
+		        unsigned int cmd, unsigned long arg);
+extern int  r128_modctx(struct inode *inode, struct file *filp,
+		        unsigned int cmd, unsigned long arg);
+extern int  r128_getctx(struct inode *inode, struct file *filp,
+		        unsigned int cmd, unsigned long arg);
+extern int  r128_switchctx(struct inode *inode, struct file *filp,
+			   unsigned int cmd, unsigned long arg);
+extern int  r128_newctx(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  r128_rmctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+
+extern int  r128_context_switch(drm_device_t *dev, int old, int new);
+extern int  r128_context_switch_complete(drm_device_t *dev, int new);
+
+
+/* Register definitions, register access macros and drmAddMap constants
+ * for Rage 128 kernel driver.
+ */
+
+#define R128_PC_NGUI_CTLSTAT	0x0184
+#       define R128_PC_FLUSH_ALL	0x00ff
+#       define R128_PC_BUSY		(1 << 31)
+
+#define R128_CLOCK_CNTL_INDEX	0x0008
+#define R128_CLOCK_CNTL_DATA	0x000c
+#       define R128_PLL_WR_EN		(1 << 7)
+
+#define R128_MCLK_CNTL		0x000f
+#       define R128_FORCE_GCP		(1 << 16)
+#       define R128_FORCE_PIPE3D_CP	(1 << 17)
+#       define R128_FORCE_RCP		(1 << 18)
+
+#define R128_GEN_RESET_CNTL	0x00f0
+#       define R128_SOFT_RESET_GUI	(1 <<  0)
+
+#define R128_PM4_BUFFER_CNTL	0x0704
+#       define R128_PM4_NONPM4			(0  << 28)
+#       define R128_PM4_192PIO			(1  << 28)
+#       define R128_PM4_192BM			(2  << 28)
+#       define R128_PM4_128PIO_64INDBM		(3  << 28)
+#       define R128_PM4_128BM_64INDBM		(4  << 28)
+#       define R128_PM4_64PIO_128INDBM		(5  << 28)
+#       define R128_PM4_64BM_128INDBM		(6  << 28)
+#       define R128_PM4_64PIO_64VCBM_64INDBM	(7  << 28)
+#       define R128_PM4_64BM_64VCBM_64INDBM	(8  << 28)
+#       define R128_PM4_64PIO_64VCPIO_64INDPIO	(15 << 28)
+
+
+#define R128_PM4_BUFFER_DL_RPTR	0x0710
+#define R128_PM4_BUFFER_DL_WPTR	0x0714
+#       define R128_PM4_BUFFER_DL_DONE		(1 << 31)
+
+#define R128_PM4_VC_FPU_SETUP	0x071c
+
+#define R128_PM4_STAT		0x07b8
+#       define R128_PM4_FIFOCNT_MASK		0x0fff
+#       define R128_PM4_BUSY			(1 << 16)
+#       define R128_PM4_GUI_ACTIVE		(1 << 31)
+
+#define R128_PM4_BUFFER_ADDR	0x07f0
+#define R128_PM4_MICRO_CNTL	0x07fc
+#       define R128_PM4_MICRO_FREERUN		(1 << 30)
+
+#define R128_PM4_FIFO_DATA_EVEN	0x1000
+#define R128_PM4_FIFO_DATA_ODD	0x1004
+
+#define R128_GUI_SCRATCH_REG0	0x15e0
+#define R128_GUI_SCRATCH_REG1	0x15e4
+#define R128_GUI_SCRATCH_REG2	0x15e8
+#define R128_GUI_SCRATCH_REG3	0x15ec
+#define R128_GUI_SCRATCH_REG4	0x15f0
+#define R128_GUI_SCRATCH_REG5	0x15f4
+
+#define R128_GUI_STAT		0x1740
+#       define R128_GUI_FIFOCNT_MASK		0x0fff
+#       define R128_GUI_ACTIVE			(1 << 31)
+
+
+/* CCE command packets */
+#define R128_CCE_PACKET0	0x00000000
+#define R128_CCE_PACKET1	0x40000000
+#define R128_CCE_PACKET2	0x80000000
+#       define R128_CCE_PACKET_MASK		0xC0000000
+#       define R128_CCE_PACKET_COUNT_MASK	0x3fff0000
+#       define R128_CCE_PACKET0_REG_MASK	0x000007ff
+#       define R128_CCE_PACKET1_REG0_MASK	0x000007ff
+#       define R128_CCE_PACKET1_REG1_MASK	0x003ff800
+
+
+#define R128_MAX_USEC_TIMEOUT	100000	/* 100 ms */
+
+
+#define R128_BASE(reg)		((u32)(dev_priv->mmio->handle))
+#define R128_ADDR(reg)		(R128_BASE(reg) + reg)
+
+#define R128_DEREF(reg)		*(__volatile__ int *)R128_ADDR(reg)
+#define R128_READ(reg)		R128_DEREF(reg)
+#define R128_WRITE(reg,val)	do { R128_DEREF(reg) = val; } while (0)
+
+#define R128_DEREF8(reg)	*(__volatile__ char *)R128_ADDR(reg)
+#define R128_READ8(reg)		R128_DEREF8(reg)
+#define R128_WRITE8(reg,val)	do { R128_DEREF8(reg) = val; } while (0)
+
+#define R128_WRITE_PLL(addr,val)                                              \
+do {                                                                          \
+	R128_WRITE8(R128_CLOCK_CNTL_INDEX, ((addr) & 0x1f) | R128_PLL_WR_EN); \
+	R128_WRITE(R128_CLOCK_CNTL_DATA, (val));                              \
+} while (0)
+
+extern int R128_READ_PLL(drm_device_t *dev, int addr);
+
+#define R128CCE0(p,r,n)   ((p) | ((n) << 16) | ((r) >> 2))
+#define R128CCE1(p,r1,r2) ((p) | (((r2) >> 2) << 11) | ((r1) >> 2))
+#define R128CCE2(p)       ((p))
+#define R128CCE3(p,n)     ((p) | ((n) << 16))
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/tdfx_context.c linux.18p8/drivers/char/drm/tdfx_context.c
--- linux.vanilla/drivers/char/drm/tdfx_context.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/tdfx_context.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,209 @@
+/* tdfx_context.c -- IOCTLs for tdfx contexts -*- linux-c -*-
+ * Created: Thu Oct  7 10:50:22 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Daryll Strauss <daryll@valinux.com>
+ * 
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+#include "tdfx_drv.h"
+
+extern drm_ctx_t tdfx_res_ctx;
+
+static int tdfx_alloc_queue(drm_device_t *dev)
+{
+	return drm_ctxbitmap_next(dev);
+}
+
+int tdfx_context_switch(drm_device_t *dev, int old, int new)
+{
+        char        buf[64];
+
+        atomic_inc(&dev->total_ctx);
+
+        if (test_and_set_bit(0, &dev->context_flag)) {
+                DRM_ERROR("Reentering -- FIXME\n");
+                return -EBUSY;
+        }
+
+#if DRM_DMA_HISTOGRAM
+        dev->ctx_start = get_cycles();
+#endif
+        
+        DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+        if (new == dev->last_context) {
+                clear_bit(0, &dev->context_flag);
+                return 0;
+        }
+        
+        if (drm_flags & DRM_FLAG_NOCTX) {
+                tdfx_context_switch_complete(dev, new);
+        } else {
+                sprintf(buf, "C %d %d\n", old, new);
+                drm_write_string(dev, buf);
+        }
+        
+        return 0;
+}
+
+int tdfx_context_switch_complete(drm_device_t *dev, int new)
+{
+        dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
+        dev->last_switch  = jiffies;
+        
+        if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+                DRM_ERROR("Lock isn't held after context switch\n");
+        }
+
+				/* If a context switch is ever initiated
+                                   when the kernel holds the lock, release
+                                   that lock here. */
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles()
+                                                      - dev->ctx_start)]);
+                   
+#endif
+        clear_bit(0, &dev->context_flag);
+        wake_up(&dev->context_wait);
+        
+        return 0;
+}
+
+
+int tdfx_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_ctx_res_t	res;
+	drm_ctx_t	ctx;
+	int		i;
+
+	DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+	copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+	if (res.count >= DRM_RESERVED_CONTEXTS) {
+		memset(&ctx, 0, sizeof(ctx));
+		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+			ctx.handle = i;
+			copy_to_user_ret(&res.contexts[i],
+					 &i,
+					 sizeof(i),
+					 -EFAULT);
+		}
+	}
+	res.count = DRM_RESERVED_CONTEXTS;
+	copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+	return 0;
+}
+
+
+int tdfx_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	if ((ctx.handle = tdfx_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
+				/* Skip kernel's context and get a new one. */
+		ctx.handle = tdfx_alloc_queue(dev);
+	}
+	DRM_DEBUG("%d\n", ctx.handle);
+	if (ctx.handle == -1) {
+		DRM_DEBUG("Not enough free contexts.\n");
+				/* Should this return -EBUSY instead? */
+		return -ENOMEM;
+	}
+   
+	copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int tdfx_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	drm_ctx_t ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+	if (ctx.flags==_DRM_CONTEXT_PRESERVED)
+		tdfx_res_ctx.handle=ctx.handle;
+	return 0;
+}
+
+int tdfx_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	drm_ctx_t ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+	/* This is 0, because we don't hanlde any context flags */
+	ctx.flags = 0;
+	copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+	return 0;
+}
+
+int tdfx_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		   unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	return tdfx_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int tdfx_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	tdfx_context_switch_complete(dev, ctx.handle);
+
+	return 0;
+}
+
+int tdfx_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+	       unsigned long arg)
+{
+	drm_file_t      *priv   = filp->private_data;
+	drm_device_t    *dev    = priv->dev;
+	drm_ctx_t	ctx;
+
+	copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+	DRM_DEBUG("%d\n", ctx.handle);
+	drm_ctxbitmap_free(dev, ctx.handle);
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/tdfx_drv.c linux.18p8/drivers/char/drm/tdfx_drv.c
--- linux.vanilla/drivers/char/drm/tdfx_drv.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/tdfx_drv.c	Fri Sep  1 14:14:35 2000
@@ -0,0 +1,690 @@
+/* tdfx.c -- tdfx driver -*- linux-c -*-
+ * Created: Thu Oct  7 10:38:32 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Daryll Strauss <daryll@valinux.com>
+ *
+ */
+
+#include <linux/config.h>
+#include "drmP.h"
+#include "tdfx_drv.h"
+
+#include <linux/agp_backend.h>
+
+static __attribute__((unused)) void unused(void)
+{
+	agp_enable(0);
+}
+
+#define TDFX_NAME	 "tdfx"
+#define TDFX_DESC	 "3dfx Banshee/Voodoo3+"
+#define TDFX_DATE	 "20000719"
+#define TDFX_MAJOR	 1
+#define TDFX_MINOR	 0
+#define TDFX_PATCHLEVEL  0
+
+static drm_device_t	      tdfx_device;
+drm_ctx_t	              tdfx_res_ctx;
+
+static struct file_operations tdfx_fops = {
+#if LINUX_VERSION_CODE >= 0x020322
+				/* This started being used approx. 2.3.34 */
+	owner:   THIS_MODULE,
+#endif
+	open:	 tdfx_open,
+	flush:	 drm_flush,
+	release: tdfx_release,
+	ioctl:	 tdfx_ioctl,
+	mmap:	 drm_mmap,
+	read:	 drm_read,
+	fasync:	 drm_fasync,
+	poll:	 drm_poll,
+};
+
+static struct miscdevice      tdfx_misc = {
+	minor: MISC_DYNAMIC_MINOR,
+	name:  TDFX_NAME,
+	fops:  &tdfx_fops,
+};
+
+static drm_ioctl_desc_t	      tdfx_ioctls[] = {
+	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]    = { tdfx_version,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)]  = { drm_getmagic,	  0, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)]  = { drm_irq_busid,	  0, 1 },
+
+	[DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_BLOCK)]	     = { drm_block,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)]    = { drm_unblock,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)]    = { drm_addmap,	  1, 1 },
+	
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]    = { tdfx_addctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]     = { tdfx_rmctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]    = { tdfx_modctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]    = { tdfx_getctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { tdfx_switchctx,  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]    = { tdfx_newctx,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]    = { tdfx_resctx,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)]   = { drm_adddraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)]    = { drm_rmdraw,	  1, 1 },
+	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	     = { tdfx_lock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]     = { tdfx_unlock,	  1, 0 },
+	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]     = { drm_finish,	  1, 0 },
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)]   = {drm_agp_acquire, 1, 1},
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)]   = {drm_agp_release, 1, 1},
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)]    = {drm_agp_enable,  1, 1},
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)]      = {drm_agp_info,    1, 1},
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)]     = {drm_agp_alloc,   1, 1},
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)]      = {drm_agp_free,    1, 1},
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)]      = {drm_agp_unbind,  1, 1},
+	[DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)]    = {drm_agp_bind,    1, 1},
+#endif
+};
+#define TDFX_IOCTL_COUNT DRM_ARRAY_SIZE(tdfx_ioctls)
+
+#ifdef MODULE
+static char		      *tdfx = NULL;
+#endif
+
+MODULE_AUTHOR("VA Linux Systems, Inc.");
+MODULE_DESCRIPTION("tdfx");
+MODULE_PARM(tdfx, "s");
+
+#ifndef MODULE
+/* tdfx_options is called by the kernel to parse command-line options
+ * passed via the boot-loader (e.g., LILO).  It calls the insmod option
+ * routine, drm_parse_drm.
+ */
+
+static int __init tdfx_options(char *str)
+{
+	drm_parse_options(str);
+	return 1;
+}
+
+__setup("tdfx=", tdfx_options);
+#endif
+
+static int tdfx_setup(drm_device_t *dev)
+{
+	int i;
+	
+	atomic_set(&dev->ioctl_count, 0);
+	atomic_set(&dev->vma_count, 0);
+	dev->buf_use	  = 0;
+	atomic_set(&dev->buf_alloc, 0);
+
+	atomic_set(&dev->total_open, 0);
+	atomic_set(&dev->total_close, 0);
+	atomic_set(&dev->total_ioctl, 0);
+	atomic_set(&dev->total_irq, 0);
+	atomic_set(&dev->total_ctx, 0);
+	atomic_set(&dev->total_locks, 0);
+	atomic_set(&dev->total_unlocks, 0);
+	atomic_set(&dev->total_contends, 0);
+	atomic_set(&dev->total_sleeps, 0);
+
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		dev->magiclist[i].head = NULL;
+		dev->magiclist[i].tail = NULL;
+	}
+	dev->maplist	    = NULL;
+	dev->map_count	    = 0;
+	dev->vmalist	    = NULL;
+	dev->lock.hw_lock   = NULL;
+	init_waitqueue_head(&dev->lock.lock_queue);
+	dev->queue_count    = 0;
+	dev->queue_reserved = 0;
+	dev->queue_slots    = 0;
+	dev->queuelist	    = NULL;
+	dev->irq	    = 0;
+	dev->context_flag   = 0;
+	dev->interrupt_flag = 0;
+	dev->dma            = 0;
+	dev->dma_flag	    = 0;
+	dev->last_context   = 0;
+	dev->last_switch    = 0;
+	dev->last_checked   = 0;
+	init_timer(&dev->timer);
+	init_waitqueue_head(&dev->context_wait);
+
+	dev->ctx_start	    = 0;
+	dev->lck_start	    = 0;
+	
+	dev->buf_rp	  = dev->buf;
+	dev->buf_wp	  = dev->buf;
+	dev->buf_end	  = dev->buf + DRM_BSZ;
+	dev->buf_async	  = NULL;
+	init_waitqueue_head(&dev->buf_readers);
+	init_waitqueue_head(&dev->buf_writers);
+
+	tdfx_res_ctx.handle=-1;
+			
+	DRM_DEBUG("\n");
+			
+	/* The kernel's context could be created here, but is now created
+	   in drm_dma_enqueue.	This is more resource-efficient for
+	   hardware that does not do DMA, but may mean that
+	   drm_select_queue fails between the time the interrupt is
+	   initialized and the time the queues are initialized. */
+			
+	return 0;
+}
+
+
+static int tdfx_takedown(drm_device_t *dev)
+{
+	int		  i;
+	drm_magic_entry_t *pt, *next;
+	drm_map_t	  *map;
+	drm_vma_entry_t	  *vma, *vma_next;
+
+	DRM_DEBUG("\n");
+
+	down(&dev->struct_sem);
+	del_timer(&dev->timer);
+	
+	if (dev->devname) {
+		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+		dev->devname = NULL;
+	}
+	
+	if (dev->unique) {
+		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+		dev->unique = NULL;
+		dev->unique_len = 0;
+	}
+				/* Clear pid list */
+	for (i = 0; i < DRM_HASH_SIZE; i++) {
+		for (pt = dev->magiclist[i].head; pt; pt = next) {
+			next = pt->next;
+			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+		}
+		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+	}
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+				/* Clear AGP information */
+	if (dev->agp) {
+		drm_agp_mem_t *temp;
+		drm_agp_mem_t *temp_next;
+	   
+		temp = dev->agp->memory;
+		while(temp != NULL) {
+			temp_next = temp->next;
+			drm_free_agp(temp->memory, temp->pages);
+			drm_free(temp, sizeof(*temp), DRM_MEM_AGPLISTS);
+			temp = temp_next;
+		}
+		if (dev->agp->acquired) (*drm_agp.release)();
+	}
+#endif
+				/* Clear vma list (only built for debugging) */
+	if (dev->vmalist) {
+		for (vma = dev->vmalist; vma; vma = vma_next) {
+			vma_next = vma->next;
+			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+		}
+		dev->vmalist = NULL;
+	}
+	
+				/* Clear map area and mtrr information */
+	if (dev->maplist) {
+		for (i = 0; i < dev->map_count; i++) {
+			map = dev->maplist[i];
+			switch (map->type) {
+			case _DRM_REGISTERS:
+			case _DRM_FRAME_BUFFER:
+#ifdef CONFIG_MTRR
+				if (map->mtrr >= 0) {
+					int retcode;
+					retcode = mtrr_del(map->mtrr,
+							   map->offset,
+							   map->size);
+					DRM_DEBUG("mtrr_del = %d\n", retcode);
+				}
+#endif
+				drm_ioremapfree(map->handle, map->size);
+				break;
+			case _DRM_SHM:
+				drm_free_pages((unsigned long)map->handle,
+					       drm_order(map->size)
+					       - PAGE_SHIFT,
+					       DRM_MEM_SAREA);
+				break;
+			case _DRM_AGP:
+				/* Do nothing here, because this is all
+                                   handled in the AGP/GART driver. */
+				break;
+			}
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+		}
+		drm_free(dev->maplist,
+			 dev->map_count * sizeof(*dev->maplist),
+			 DRM_MEM_MAPS);
+		dev->maplist   = NULL;
+		dev->map_count = 0;
+	}
+	
+	if (dev->lock.hw_lock) {
+		dev->lock.hw_lock    = NULL; /* SHM removed */
+		dev->lock.pid	     = 0;
+		wake_up_interruptible(&dev->lock.lock_queue);
+	}
+	up(&dev->struct_sem);
+	
+	return 0;
+}
+
+/* tdfx_init is called via init_module at module load time, or via
+ * linux/init/main.c (this is not currently supported). */
+
+static int tdfx_init(void)
+{
+	int		      retcode;
+	drm_device_t	      *dev = &tdfx_device;
+
+	DRM_DEBUG("\n");
+
+	memset((void *)dev, 0, sizeof(*dev));
+	dev->count_lock	  = SPIN_LOCK_UNLOCKED;
+	sema_init(&dev->struct_sem, 1);
+	
+#ifdef MODULE
+	drm_parse_options(tdfx);
+#endif
+
+	if ((retcode = misc_register(&tdfx_misc))) {
+		DRM_ERROR("Cannot register \"%s\"\n", TDFX_NAME);
+		return retcode;
+	}
+	dev->device = MKDEV(MISC_MAJOR, tdfx_misc.minor);
+	dev->name   = TDFX_NAME;
+
+	drm_mem_init();
+	drm_proc_init(dev);
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	dev->agp    = drm_agp_init();
+#endif
+	if((retcode = drm_ctxbitmap_init(dev))) {
+		DRM_ERROR("Cannot allocate memory for context bitmap.\n");
+		drm_proc_cleanup();
+		misc_deregister(&tdfx_misc);
+		tdfx_takedown(dev);
+		return retcode;
+	}
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+		 TDFX_NAME,
+		 TDFX_MAJOR,
+		 TDFX_MINOR,
+		 TDFX_PATCHLEVEL,
+		 TDFX_DATE,
+		 tdfx_misc.minor);
+	
+	return 0;
+}
+
+/* tdfx_cleanup is called via cleanup_module at module unload time. */
+
+static void tdfx_cleanup(void)
+{
+	drm_device_t	      *dev = &tdfx_device;
+
+	DRM_DEBUG("\n");
+	
+	drm_proc_cleanup();
+	if (misc_deregister(&tdfx_misc)) {
+		DRM_ERROR("Cannot unload module\n");
+	} else {
+		DRM_INFO("Module unloaded\n");
+	}
+	drm_ctxbitmap_cleanup(dev);
+	tdfx_takedown(dev);
+#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
+	if (dev->agp) {
+		drm_agp_uninit();
+		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
+		dev->agp = NULL;
+	}
+#endif
+}
+
+module_init(tdfx_init);
+module_exit(tdfx_cleanup);
+
+
+int tdfx_version(struct inode *inode, struct file *filp, unsigned int cmd,
+		  unsigned long arg)
+{
+	drm_version_t version;
+	int	      len;
+
+	copy_from_user_ret(&version,
+			   (drm_version_t *)arg,
+			   sizeof(version),
+			   -EFAULT);
+
+#define DRM_COPY(name,value)				     \
+	len = strlen(value);				     \
+	if (len > name##_len) len = name##_len;		     \
+	name##_len = strlen(value);			     \
+	if (len && name) {				     \
+		copy_to_user_ret(name, value, len, -EFAULT); \
+	}
+
+	version.version_major	   = TDFX_MAJOR;
+	version.version_minor	   = TDFX_MINOR;
+	version.version_patchlevel = TDFX_PATCHLEVEL;
+
+	DRM_COPY(version.name, TDFX_NAME);
+	DRM_COPY(version.date, TDFX_DATE);
+	DRM_COPY(version.desc, TDFX_DESC);
+
+	copy_to_user_ret((drm_version_t *)arg,
+			 &version,
+			 sizeof(version),
+			 -EFAULT);
+	return 0;
+}
+
+int tdfx_open(struct inode *inode, struct file *filp)
+{
+	drm_device_t  *dev    = &tdfx_device;
+	int	      retcode = 0;
+	
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_open_helper(inode, filp, dev))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_open);
+		spin_lock(&dev->count_lock);
+		if (!dev->open_count++) {
+			spin_unlock(&dev->count_lock);
+			return tdfx_setup(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+	return retcode;
+}
+
+int tdfx_release(struct inode *inode, struct file *filp)
+{
+	drm_file_t    *priv   = filp->private_data;
+	drm_device_t  *dev;
+	int	      retcode = 0;
+
+	lock_kernel();
+	dev = priv->dev;
+
+	DRM_DEBUG("open_count = %d\n", dev->open_count);
+	if (!(retcode = drm_release(inode, filp))) {
+#if LINUX_VERSION_CODE < 0x020333
+		MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+		atomic_inc(&dev->total_close);
+		spin_lock(&dev->count_lock);
+		if (!--dev->open_count) {
+			if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+				DRM_ERROR("Device busy: %d %d\n",
+					  atomic_read(&dev->ioctl_count),
+					  dev->blocked);
+				spin_unlock(&dev->count_lock);
+				unlock_kernel();
+				return -EBUSY;
+			}
+			spin_unlock(&dev->count_lock);
+			unlock_kernel();
+			return tdfx_takedown(dev);
+		}
+		spin_unlock(&dev->count_lock);
+	}
+
+	unlock_kernel();
+	return retcode;
+}
+
+/* tdfx_ioctl is called whenever a process performs an ioctl on /dev/drm. */
+
+int tdfx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	int		 nr	 = DRM_IOCTL_NR(cmd);
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	int		 retcode = 0;
+	drm_ioctl_desc_t *ioctl;
+	drm_ioctl_t	 *func;
+
+	atomic_inc(&dev->ioctl_count);
+	atomic_inc(&dev->total_ioctl);
+	++priv->ioctl_count;
+	
+	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+		  current->pid, cmd, nr, dev->device, priv->authenticated);
+
+	if (nr >= TDFX_IOCTL_COUNT) {
+		retcode = -EINVAL;
+	} else {
+		ioctl	  = &tdfx_ioctls[nr];
+		func	  = ioctl->func;
+
+		if (!func) {
+			DRM_DEBUG("no function\n");
+			retcode = -EINVAL;
+		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+			    || (ioctl->auth_needed && !priv->authenticated)) {
+			retcode = -EACCES;
+		} else {
+			retcode = (func)(inode, filp, cmd, arg);
+		}
+	}
+	
+	atomic_dec(&dev->ioctl_count);
+	return retcode;
+}
+
+int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd,
+	      unsigned long arg)
+{
+        drm_file_t        *priv   = filp->private_data;
+        drm_device_t      *dev    = priv->dev;
+        DECLARE_WAITQUEUE(entry, current);
+        int               ret   = 0;
+        drm_lock_t        lock;
+#if DRM_DMA_HISTOGRAM
+        cycles_t          start;
+
+        dev->lck_start = start = get_cycles();
+#endif
+
+        copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+
+        if (lock.context == DRM_KERNEL_CONTEXT) {
+                DRM_ERROR("Process %d using kernel context %d\n",
+                          current->pid, lock.context);
+                return -EINVAL;
+        }
+
+        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+                  lock.context, current->pid, dev->lock.hw_lock->lock,
+                  lock.flags);
+
+#if 0
+				/* dev->queue_count == 0 right now for
+                                   tdfx.  FIXME? */
+        if (lock.context < 0 || lock.context >= dev->queue_count)
+                return -EINVAL;
+#endif
+        
+        if (!ret) {
+#if 0
+                if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+                    != lock.context) {
+                        long j = jiffies - dev->lock.lock_time;
+
+                        if (lock.context == tdfx_res_ctx.handle &&
+				j >= 0 && j < DRM_LOCK_SLICE) {
+                                /* Can't take lock if we just had it and
+                                   there is contention. */
+                                DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n",
+					lock.context, current->pid, j, 
+					dev->lock.lock_time, jiffies);
+                                current->state = TASK_INTERRUPTIBLE;
+				current->policy |= SCHED_YIELD;
+                                schedule_timeout(DRM_LOCK_SLICE-j);
+				DRM_DEBUG("jiffies=%d\n", jiffies);
+                        }
+                }
+#endif
+                add_wait_queue(&dev->lock.lock_queue, &entry);
+                for (;;) {
+                        if (!dev->lock.hw_lock) {
+                                /* Device has been unregistered */
+                                ret = -EINTR;
+                                break;
+                        }
+                        if (drm_lock_take(&dev->lock.hw_lock->lock,
+                                          lock.context)) {
+                                dev->lock.pid       = current->pid;
+                                dev->lock.lock_time = jiffies;
+                                atomic_inc(&dev->total_locks);
+                                break;  /* Got lock */
+                        }
+                        
+                                /* Contention */
+                        atomic_inc(&dev->total_sleeps);
+                        current->state = TASK_INTERRUPTIBLE;
+#if 1
+			current->policy |= SCHED_YIELD;
+#endif
+                        schedule();
+                        if (signal_pending(current)) {
+                                ret = -ERESTARTSYS;
+                                break;
+                        }
+                }
+                current->state = TASK_RUNNING;
+                remove_wait_queue(&dev->lock.lock_queue, &entry);
+        }
+
+#if 0
+	if (!ret && dev->last_context != lock.context &&
+		lock.context != tdfx_res_ctx.handle &&
+		dev->last_context != tdfx_res_ctx.handle) {
+		add_wait_queue(&dev->context_wait, &entry);
+	        current->state = TASK_INTERRUPTIBLE;
+                /* PRE: dev->last_context != lock.context */
+	        tdfx_context_switch(dev, dev->last_context, lock.context);
+		/* POST: we will wait for the context
+                   switch and will dispatch on a later call
+                   when dev->last_context == lock.context
+                   NOTE WE HOLD THE LOCK THROUGHOUT THIS
+                   TIME! */
+		current->policy |= SCHED_YIELD;
+	        schedule();
+	        current->state = TASK_RUNNING;
+	        remove_wait_queue(&dev->context_wait, &entry);
+	        if (signal_pending(current)) {
+	                ret = -EINTR;
+	        } else if (dev->last_context != lock.context) {
+			DRM_ERROR("Context mismatch: %d %d\n",
+                        	dev->last_context, lock.context);
+	        }
+	}
+#endif
+
+        if (!ret) {
+                if (lock.flags & _DRM_LOCK_READY) {
+				/* Wait for space in DMA/FIFO */
+		}
+                if (lock.flags & _DRM_LOCK_QUIESCENT) {
+				/* Make hardware quiescent */
+#if 0
+                        tdfx_quiescent(dev);
+#endif
+		}
+        }
+
+#if LINUX_VERSION_CODE < 0x020400
+	if (lock.context != tdfx_res_ctx.handle) {
+		current->counter = 5;
+		current->priority = DEF_PRIORITY/4;
+	}
+#endif
+        DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+#if DRM_DMA_HISTOGRAM
+        atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
+#endif
+        
+        return ret;
+}
+
+
+int tdfx_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
+		 unsigned long arg)
+{
+	drm_file_t	  *priv	  = filp->private_data;
+	drm_device_t	  *dev	  = priv->dev;
+	drm_lock_t	  lock;
+
+	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+	
+	if (lock.context == DRM_KERNEL_CONTEXT) {
+		DRM_ERROR("Process %d using kernel context %d\n",
+			  current->pid, lock.context);
+		return -EINVAL;
+	}
+
+	DRM_DEBUG("%d frees lock (%d holds)\n",
+		  lock.context,
+		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+	atomic_inc(&dev->total_unlocks);
+	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+		atomic_inc(&dev->total_contends);
+	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT);
+				/* FIXME: Try to send data to card here */
+	if (!dev->context_flag) {
+		if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
+				  DRM_KERNEL_CONTEXT)) {
+			DRM_ERROR("\n");
+		}
+	}
+
+#if LINUX_VERSION_CODE < 0x020400
+	if (lock.context != tdfx_res_ctx.handle) {
+		current->counter = 5;
+		current->priority = DEF_PRIORITY;
+	}
+#endif
+	
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/tdfx_drv.h linux.18p8/drivers/char/drm/tdfx_drv.h
--- linux.vanilla/drivers/char/drm/tdfx_drv.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/tdfx_drv.h	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,67 @@
+/* tdfx_drv.h -- Private header for tdfx driver -*- linux-c -*-
+ * Created: Thu Oct  7 10:40:04 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Daryll Strauss <daryll@valinux.com>
+ * 
+ */
+
+#ifndef _TDFX_DRV_H_
+#define _TDFX_DRV_H_
+
+				/* tdfx_drv.c */
+extern int  tdfx_version(struct inode *inode, struct file *filp,
+			  unsigned int cmd, unsigned long arg);
+extern int  tdfx_open(struct inode *inode, struct file *filp);
+extern int  tdfx_release(struct inode *inode, struct file *filp);
+extern int  tdfx_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  tdfx_lock(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+extern int  tdfx_unlock(struct inode *inode, struct file *filp,
+			 unsigned int cmd, unsigned long arg);
+
+				/* tdfx_context.c */
+
+extern int  tdfx_resctx(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  tdfx_addctx(struct inode *inode, struct file *filp,
+		        unsigned int cmd, unsigned long arg);
+extern int  tdfx_modctx(struct inode *inode, struct file *filp,
+		        unsigned int cmd, unsigned long arg);
+extern int  tdfx_getctx(struct inode *inode, struct file *filp,
+		        unsigned int cmd, unsigned long arg);
+extern int  tdfx_switchctx(struct inode *inode, struct file *filp,
+			   unsigned int cmd, unsigned long arg);
+extern int  tdfx_newctx(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long arg);
+extern int  tdfx_rmctx(struct inode *inode, struct file *filp,
+		       unsigned int cmd, unsigned long arg);
+
+extern int  tdfx_context_switch(drm_device_t *dev, int old, int new);
+extern int  tdfx_context_switch_complete(drm_device_t *dev, int new);
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/vm.c linux.18p8/drivers/char/drm/vm.c
--- linux.vanilla/drivers/char/drm/vm.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/drm/vm.c	Fri Sep  1 14:12:33 2000
@@ -0,0 +1,319 @@
+/* vm.c -- Memory mapping for DRM -*- linux-c -*-
+ * Created: Mon Jan  4 08:58:31 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ * Authors:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *
+ */
+
+#define __NO_VERSION__
+#include "drmP.h"
+
+struct vm_operations_struct   drm_vm_ops = {
+	nopage:	 drm_vm_nopage,
+	open:	 drm_vm_open,
+	close:	 drm_vm_close,
+};
+
+struct vm_operations_struct   drm_vm_shm_ops = {
+	nopage:	 drm_vm_shm_nopage,
+	open:	 drm_vm_open,
+	close:	 drm_vm_close,
+};
+
+struct vm_operations_struct   drm_vm_dma_ops = {
+	nopage:	 drm_vm_dma_nopage,
+	open:	 drm_vm_open,
+	close:	 drm_vm_close,
+};
+
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long drm_vm_nopage(struct vm_area_struct *vma,
+			    unsigned long address,
+			    int write_access)
+#else
+				/* Return type changed in 2.3.23 */
+struct page *drm_vm_nopage(struct vm_area_struct *vma,
+			   unsigned long address,
+			   int write_access)
+#endif
+{
+	DRM_DEBUG("0x%08lx, %d\n", address, write_access);
+
+	return NOPAGE_SIGBUS;		/* Disallow mremap */
+}
+
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long drm_vm_shm_nopage(struct vm_area_struct *vma,
+				unsigned long address,
+				int write_access)
+#else
+				/* Return type changed in 2.3.23 */
+struct page *drm_vm_shm_nopage(struct vm_area_struct *vma,
+			       unsigned long address,
+			       int write_access)
+#endif
+{
+	drm_file_t	 *priv	 = vma->vm_file->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	unsigned long	 physical;
+	unsigned long	 offset;
+	unsigned long	 page;
+
+	if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
+	if (!dev->lock.hw_lock)    return NOPAGE_OOM;  /* Nothing allocated */
+
+	offset	 = address - vma->vm_start;
+	page	 = offset >> PAGE_SHIFT;
+	physical = (unsigned long)dev->lock.hw_lock + offset;
+	atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */
+
+	DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
+#if LINUX_VERSION_CODE < 0x020317
+	return physical;
+#else
+	return mem_map + MAP_NR(physical);
+#endif
+}
+
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long drm_vm_dma_nopage(struct vm_area_struct *vma,
+				unsigned long address,
+				int write_access)
+#else
+				/* Return type changed in 2.3.23 */
+struct page *drm_vm_dma_nopage(struct vm_area_struct *vma,
+			       unsigned long address,
+			       int write_access)
+#endif
+{
+	drm_file_t	 *priv	 = vma->vm_file->private_data;
+	drm_device_t	 *dev	 = priv->dev;
+	drm_device_dma_t *dma	 = dev->dma;
+	unsigned long	 physical;
+	unsigned long	 offset;
+	unsigned long	 page;
+
+	if (!dma)		   return NOPAGE_SIGBUS; /* Error */
+	if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
+	if (!dma->pagelist)	   return NOPAGE_OOM ; /* Nothing allocated */
+
+	offset	 = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */
+	page	 = offset >> PAGE_SHIFT;
+	physical = dma->pagelist[page] + (offset & (~PAGE_MASK));
+	atomic_inc(&mem_map[MAP_NR(physical)].count); /* Dec. by kernel */
+
+	DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
+#if LINUX_VERSION_CODE < 0x020317
+	return physical;
+#else
+	return mem_map + MAP_NR(physical);
+#endif
+}
+
+void drm_vm_open(struct vm_area_struct *vma)
+{
+	drm_file_t	*priv	= vma->vm_file->private_data;
+	drm_device_t	*dev	= priv->dev;
+#if DRM_DEBUG_CODE
+	drm_vma_entry_t *vma_entry;
+#endif
+
+	DRM_DEBUG("0x%08lx,0x%08lx\n",
+		  vma->vm_start, vma->vm_end - vma->vm_start);
+	atomic_inc(&dev->vma_count);
+#if LINUX_VERSION_CODE < 0x020333
+				/* The map can exist after the fd is closed. */
+	MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+
+
+#if DRM_DEBUG_CODE
+	vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
+	if (vma_entry) {
+		down(&dev->struct_sem);
+		vma_entry->vma	= vma;
+		vma_entry->next = dev->vmalist;
+		vma_entry->pid	= current->pid;
+		dev->vmalist	= vma_entry;
+		up(&dev->struct_sem);
+	}
+#endif
+}
+
+void drm_vm_close(struct vm_area_struct *vma)
+{
+	drm_file_t	*priv	= vma->vm_file->private_data;
+	drm_device_t	*dev	= priv->dev;
+#if DRM_DEBUG_CODE
+	drm_vma_entry_t *pt, *prev;
+#endif
+
+	DRM_DEBUG("0x%08lx,0x%08lx\n",
+		  vma->vm_start, vma->vm_end - vma->vm_start);
+#if LINUX_VERSION_CODE < 0x020333
+	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
+#endif
+	atomic_dec(&dev->vma_count);
+
+#if DRM_DEBUG_CODE
+	down(&dev->struct_sem);
+	for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
+		if (pt->vma == vma) {
+			if (prev) {
+				prev->next = pt->next;
+			} else {
+				dev->vmalist = pt->next;
+			}
+			drm_free(pt, sizeof(*pt), DRM_MEM_VMAS);
+			break;
+		}
+	}
+	up(&dev->struct_sem);
+#endif
+}
+
+int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	 *priv	 = filp->private_data;
+	drm_device_t	 *dev;
+	drm_device_dma_t *dma;
+	unsigned long	 length	 = vma->vm_end - vma->vm_start;
+	
+	lock_kernel();
+	dev	 = priv->dev;
+	dma	 = dev->dma;
+	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+		  vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+
+				/* Length must match exact page count */
+	if ((length >> PAGE_SHIFT) != dma->page_count) {
+		unlock_kernel();
+		return -EINVAL;
+	}
+	unlock_kernel();
+
+	vma->vm_ops   = &drm_vm_dma_ops;
+	vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+	
+#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
+				/* In Linux 2.2.3 and above, this is
+				   handled in do_mmap() in mm/mmap.c. */
+	++filp->f_count;
+#endif
+	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */
+	drm_vm_open(vma);
+	return 0;
+}
+
+int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	drm_file_t	*priv	= filp->private_data;
+	drm_device_t	*dev	= priv->dev;
+	drm_map_t	*map	= NULL;
+	int		i;
+	
+	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+		  vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+
+	if (!VM_OFFSET(vma)) return drm_mmap_dma(filp, vma);
+
+				/* A sequential search of a linked list is
+				   fine here because: 1) there will only be
+				   about 5-10 entries in the list and, 2) a
+				   DRI client only has to do this mapping
+				   once, so it doesn't have to be optimized
+				   for performance, even if the list was a
+				   bit longer. */
+	for (i = 0; i < dev->map_count; i++) {
+		map = dev->maplist[i];
+		if (map->offset == VM_OFFSET(vma)) break;
+	}
+	
+	if (i >= dev->map_count) return -EINVAL;
+	if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
+		return -EPERM;
+
+				/* Check for valid size. */
+	if (map->size != vma->vm_end - vma->vm_start) return -EINVAL;
+	
+	if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
+		vma->vm_flags &= VM_MAYWRITE;
+#if defined(__i386__)
+		pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW;
+#else
+				/* Ye gads this is ugly.  With more thought
+                                   we could move this up higher and use
+                                   `protection_map' instead.  */
+		vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect(
+			__pte(pgprot_val(vma->vm_page_prot)))));
+#endif
+	}
+
+	switch (map->type) {
+	case _DRM_FRAME_BUFFER:
+	case _DRM_REGISTERS:
+	case _DRM_AGP:
+		if (VM_OFFSET(vma) >= __pa(high_memory)) {
+#if defined(__i386__)
+			if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
+				pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+				pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
+			}
+#endif
+			vma->vm_flags |= VM_IO;	/* not in core dump */
+		}
+		if (remap_page_range(vma->vm_start,
+				     VM_OFFSET(vma),
+				     vma->vm_end - vma->vm_start,
+				     vma->vm_page_prot))
+				return -EAGAIN;
+		DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx,"
+			  " offset = 0x%lx\n",
+			  map->type,
+			  vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+		vma->vm_ops = &drm_vm_ops;
+		break;
+	case _DRM_SHM:
+		vma->vm_ops = &drm_vm_shm_ops;
+				/* Don't let this area swap.  Change when
+				   DRM_KERNEL advisory is supported. */
+		vma->vm_flags |= VM_LOCKED;
+		break;
+	default:
+		return -EINVAL;	/* This should never happen. */
+	}
+	vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+
+#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */
+				/* In Linux 2.2.3 and above, this is
+				   handled in do_mmap() in mm/mmap.c. */
+	++filp->f_count;
+#endif
+	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */
+	drm_vm_open(vma);
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/i810_rng.c linux.18p8/drivers/char/i810_rng.c
--- linux.vanilla/drivers/char/i810_rng.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/i810_rng.c	Mon Sep 11 17:33:27 2000
@@ -0,0 +1,486 @@
+/*
+
+	Hardware driver for Intel i810 Random Number Generator (RNG)
+	Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+
+	Driver Web site:  http://gtf.org/garzik/drivers/i810_rng/
+
+
+
+	Based on:
+	Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet
+		May 1999 Order Number: 290658-002 R
+
+	Intel 82802 Firmware Hub: Random Number Generator
+	Programmer's Reference Manual
+		December 1999 Order Number: 298029-001 R
+
+	Intel 82802 Firmware HUB Random Number Generator Driver
+	Copyright (c) 2000 Matt Sottek <msottek@quiknet.com>
+
+	Special thanks to Matt Sottek.  I did the "guts", he
+	did the "brains" and all the testing.  (Anybody wanna send
+	me an i810 or i820?)
+
+	----------------------------------------------------------
+
+	This software may be used and distributed according to the terms
+        of the GNU Public License, incorporated herein by reference.
+
+	----------------------------------------------------------
+
+	From the firmware hub datasheet:
+
+	The Firmware Hub integrates a Random Number Generator (RNG)
+	using thermal noise generated from inherently random quantum
+	mechanical properties of silicon. When not generating new random
+	bits the RNG circuitry will enter a low power state. Intel will
+	provide a binary software driver to give third party software
+	access to our RNG for use as a security feature. At this time,
+	the RNG is only to be used with a system in an OS-present state.
+
+	----------------------------------------------------------
+
+	Theory of operation:
+
+	Character driver.  Using the standard open()
+	and read() system calls, you can read random data from
+	the i810 RNG device.  This data is NOT CHECKED by any
+	fitness tests, and could potentially be bogus (if the
+	hardware is faulty or has been tampered with).
+
+	/dev/intel_rng is char device major 10, minor 183.
+
+
+	----------------------------------------------------------
+
+	Driver notes:
+
+	* In order to unload the i810_rng module, you must first
+	make sure all users of the character device have closed
+
+	* FIXME:  Currently only one open() of the character device is allowed.
+	If another user tries to open() the device, they will get an
+	-EBUSY error.  Instead, this really should either support
+	multiple simultaneous users of the character device (not hard),
+	or simply block open() until the current user of the chrdev
+	calls close().
+
+	* FIXME: support poll()
+
+	* FIXME: should we be crazy and support mmap()?
+
+	----------------------------------------------------------
+
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/spinlock.h>
+#include <linux/random.h>
+#include <linux/sysctl.h>
+#include <linux/miscdevice.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+/*
+ * core module and version information
+ */
+#define RNG_VERSION "0.6.2-2.2.x"
+#define RNG_MODULE_NAME "i810_rng"
+#define RNG_DRIVER_NAME   RNG_MODULE_NAME " hardware driver " RNG_VERSION
+#define PFX RNG_MODULE_NAME ": "
+
+
+/*
+ * debugging macros
+ */
+#undef RNG_DEBUG /* define to 1 to enable copious debugging info */
+
+#ifdef RNG_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define RNG_NDEBUG 0        /* define to 1 to disable lightweight runtime checks */
+#if RNG_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+        if(!(expr)) {                                   \
+        printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+        #expr,__FILE__,__FUNCTION__,__LINE__);          \
+        }
+#endif
+
+
+/*
+ * misc helper macros
+ */
+#define arraysize(x)            (sizeof(x)/sizeof(*(x)))
+
+
+/*
+ * RNG registers (offsets from rng_mem)
+ */
+#define RNG_HW_STATUS			0
+#define		RNG_PRESENT		0x40
+#define		RNG_ENABLED		0x01
+#define RNG_STATUS			1
+#define		RNG_DATA_PRESENT	0x01
+#define RNG_DATA			2
+
+#define RNG_ADDR			0xFFBC015F
+#define RNG_ADDR_LEN			3
+
+#define RNG_MISCDEV_MINOR		183 /* official */
+
+
+/*
+ * various RNG status variables.  they are globals
+ * as we only support a single RNG device
+ */
+static int rng_allocated;		/* is someone using the RNG region? */
+static int rng_hw_enabled;		/* is the RNG h/w enabled? */
+static int rng_use_count;		/* number of times RNG has been enabled */
+static void *rng_mem;			/* token to our ioremap'd RNG register area */
+static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */
+static int rng_open;			/* boolean, 0 (false) if chrdev is closed, 1 (true) if open */
+
+/*
+ * inlined helper functions for accessing RNG registers
+ */
+static inline u8 rng_hwstatus (void)
+{
+	assert (rng_mem != NULL);
+	return readb (rng_mem + RNG_HW_STATUS);
+}
+
+
+static inline void rng_hwstatus_set (u8 hw_status)
+{
+	assert (rng_mem != NULL);
+	writeb (hw_status, rng_mem + RNG_HW_STATUS);
+}
+
+
+static inline int rng_data_present (void)
+{
+	assert (rng_mem != NULL);
+	assert (rng_hw_enabled == 1);
+
+	return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0;
+}
+
+
+static inline int rng_data_read (void)
+{
+	assert (rng_mem != NULL);
+	assert (rng_hw_enabled == 1);
+
+	return readb (rng_mem + RNG_DATA);
+}
+
+
+/*
+ * rng_enable - enable or disable the RNG hardware
+ */
+static int rng_enable (int enable)
+{
+	int rc = 0;
+	u8 hw_status;
+
+	DPRINTK ("ENTER\n");
+
+	spin_lock (&rng_lock);
+
+	hw_status = rng_hwstatus ();
+
+	if (enable) {
+		rng_hw_enabled = 1;
+		rng_use_count++;
+		MOD_INC_USE_COUNT;
+	} else {
+		rng_use_count--;
+		if (rng_use_count == 0)
+			rng_hw_enabled = 0;
+		MOD_DEC_USE_COUNT;
+	}
+
+	if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) {
+		rng_hwstatus_set (hw_status | RNG_ENABLED);
+		printk (KERN_INFO PFX "RNG h/w enabled\n");
+	}
+
+	else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) {
+		rng_hwstatus_set (hw_status & ~RNG_ENABLED);
+		printk (KERN_INFO PFX "RNG h/w disabled\n");
+	}
+
+	spin_unlock (&rng_lock);
+
+	if ((!!enable) != (!!(rng_hwstatus () & RNG_ENABLED))) {
+		printk (KERN_ERR PFX "Unable to %sable the RNG\n",
+			enable ? "en" : "dis");
+		rc = -EIO;
+	}
+
+	DPRINTK ("EXIT, returning %d\n", rc);
+	return rc;
+}
+
+
+static int rng_dev_open (struct inode *inode, struct file *filp)
+{
+	int rc = -EINVAL;
+
+	MOD_INC_USE_COUNT;
+
+	if ((filp->f_mode & FMODE_READ) == 0)
+		goto err_out;
+	if (filp->f_mode & FMODE_WRITE)
+		goto err_out;
+
+	spin_lock (&rng_lock);
+
+	/* only allow one open of this device, exit with -EBUSY if already open */
+	/* FIXME: we should sleep on a semaphore here, unless O_NONBLOCK */
+	if (rng_open) {
+		spin_unlock (&rng_lock);
+		rc = -EBUSY;
+		goto err_out;
+	}
+
+	rng_open = 1;
+
+	spin_unlock (&rng_lock);
+
+	if (rng_enable(1) != 0) {
+		spin_lock (&rng_lock);
+		rng_open = 0;
+		spin_unlock (&rng_lock);
+		rc = -EIO;
+		goto err_out;
+	}
+
+	return 0;
+
+err_out:
+	MOD_DEC_USE_COUNT;
+	return rc;
+}
+
+
+static int rng_dev_release (struct inode *inode, struct file *filp)
+{
+
+	if (rng_enable(0) != 0)
+		return -EIO;
+
+	spin_lock (&rng_lock);
+	rng_open = 0;
+	spin_unlock (&rng_lock);
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+static ssize_t rng_dev_read (struct file *filp, char * buf, size_t size,
+			     loff_t *offp)
+{
+	int have_data, copied = 0;
+	u8 data=0;
+	u8 *page;
+
+	if (size < 1)
+		return 0;
+
+	page = (unsigned char *) get_free_page (GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+read_loop:
+	/* using the fact that read() can return >0 but
+	 * less than the requested amount, we simply
+	 * read up to PAGE_SIZE or buffer size, whichever
+	 * is smaller, and return that data.
+	 */
+	if ((copied == size) || (copied == PAGE_SIZE)) {
+		size_t tmpsize = (copied == size) ? size : PAGE_SIZE;
+		int rc = copy_to_user (buf, page, tmpsize);
+		free_page ((long)page);
+		if (rc) return rc;
+		return tmpsize;
+	}
+
+	spin_lock (&rng_lock);
+
+	have_data = 0;
+	if (rng_data_present ()) {
+		data = rng_data_read ();
+		have_data = 1;
+	}
+
+	spin_unlock (&rng_lock);
+
+	if (have_data) {
+		page[copied] = data;
+		copied++;
+	} else {
+		if (filp->f_flags & O_NONBLOCK) {
+			free_page ((long)page);
+			return -EAGAIN;
+		}
+	}
+
+	if (current->need_resched)
+		schedule ();
+
+	if (signal_pending (current)) {
+		free_page ((long)page);
+		return -ERESTARTSYS;
+	}
+
+	goto read_loop;
+}
+
+
+/*
+ * rng_init_one - look for and attempt to init a single RNG
+ */
+static int __init rng_init_one (struct pci_dev *dev)
+{
+	int rc;
+	u8 hw_status;
+
+	DPRINTK ("ENTER\n");
+
+	if (rng_allocated) {
+		printk (KERN_ERR PFX "this driver only supports one RNG\n");
+		DPRINTK ("EXIT, returning -EBUSY\n");
+		return -EBUSY;
+	}
+
+	rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN);
+	if (rng_mem == NULL) {
+		printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
+		DPRINTK ("EXIT, returning -EBUSY\n");
+		rc = -EBUSY;
+		goto err_out;
+	}
+
+	/* Check for Intel 82802 */
+	hw_status = rng_hwstatus ();
+	if ((hw_status & RNG_PRESENT) == 0) {
+		printk (KERN_ERR PFX "RNG not detected\n");
+		DPRINTK ("EXIT, returning -ENODEV\n");
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	rng_allocated = 1;
+
+	rc = rng_enable (0);
+	if (rc) {
+		printk (KERN_ERR PFX "cannot disable RNG, aborting\n");
+		goto err_out;
+	}
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+
+err_out:
+	if (rng_mem)
+		iounmap (rng_mem);
+	return rc;
+}
+
+
+/*
+ * Data for PCI driver interface
+ */
+
+MODULE_AUTHOR("Jeff Garzik, Matt Sottek");
+MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver");
+
+
+static struct file_operations rng_chrdev_ops = {
+	open:		rng_dev_open,
+	release:	rng_dev_release,
+	read:		rng_dev_read,
+};
+
+
+static struct miscdevice rng_miscdev = {
+	RNG_MISCDEV_MINOR,
+	RNG_MODULE_NAME,
+	&rng_chrdev_ops,
+};
+
+
+/*
+ * rng_init - initialize RNG module
+ */
+int __init rng_init (void)
+{
+	int rc;
+	struct pci_dev *pdev;
+	
+	pdev = pci_find_device (0x8086, 0x2418, NULL);
+	if (!pdev)
+		pdev = pci_find_device (0x8086, 0x2428, NULL);
+	if (!pdev)
+		return -ENODEV;
+
+	DPRINTK ("ENTER\n");
+
+	rc = rng_init_one(pdev);
+	if (rc) {
+		DPRINTK ("EXIT, returning -ENODEV\n");
+		return rc;
+	}
+
+	rc = misc_register (&rng_miscdev);
+	if (rc) {
+		if (rng_mem)
+			iounmap (rng_mem);
+		DPRINTK ("EXIT, returning %d\n", rc);
+		return rc;
+	}
+
+	printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+#ifdef MODULE
+
+int init_module (void) { return rng_init (); }
+
+/*
+ * rng_init - shutdown RNG module
+ */
+void cleanup_module (void)
+{
+	DPRINTK ("ENTER\n");
+	
+	iounmap (rng_mem);
+
+	rng_hwstatus_set (rng_hwstatus() & ~RNG_ENABLED);
+
+	misc_deregister (&rng_miscdev);
+
+	DPRINTK ("EXIT\n");
+}
+
+#endif /* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/keyboard.c linux.18p8/drivers/char/keyboard.c
--- linux.vanilla/drivers/char/keyboard.c	Fri Apr 21 12:46:04 2000
+++ linux.18p8/drivers/char/keyboard.c	Fri Sep  1 13:51:29 2000
@@ -61,7 +61,9 @@
 #define KBD_DEFLOCK 0
 #endif
 
+void (*kbd_ledfunc)(unsigned int led) = NULL;
 EXPORT_SYMBOL(handle_scancode);
+EXPORT_SYMBOL(kbd_ledfunc);
 
 extern void ctrl_alt_del(void);
 
@@ -905,6 +907,7 @@
 	if (leds != ledstate) {
 		ledstate = leds;
 		kbd_leds(leds);
+		if (kbd_ledfunc) kbd_ledfunc(leds);
 	}
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/mem.c linux.18p8/drivers/char/mem.c
--- linux.vanilla/drivers/char/mem.c	Fri Apr 21 12:46:04 2000
+++ linux.18p8/drivers/char/mem.c	Fri Sep  1 13:51:29 2000
@@ -55,14 +55,8 @@
 #if defined(CONFIG_PPC) || defined(CONFIG_MAC)
 extern void adbdev_init(void);
 #endif
-#ifdef CONFIG_USB_UHCI
-int uhci_init(void);
-#endif
-#ifdef CONFIG_USB_OHCI
-int ohci_init(void);
-#endif
-#ifdef CONFIG_USB_OHCI_HCD
-int ohci_hcd_init(void);
+#ifdef CONFIG_USB
+int usb_init(void);
 #endif
      
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
@@ -621,15 +615,7 @@
 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 	rand_initialize();
 #ifdef CONFIG_USB
-#ifdef CONFIG_USB_UHCI
-	uhci_init();
-#endif
-#ifdef CONFIG_USB_OHCI
-	ohci_init();
-#endif
-#ifdef CONFIG_USB_OHCI_HCD
-        ohci_hcd_init(); 
-#endif
+	usb_init();
 #endif
 #if defined (CONFIG_FB)
 	fbmem_init();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/misc.c linux.18p8/drivers/char/misc.c
--- linux.vanilla/drivers/char/misc.c	Sat Sep  9 18:42:35 2000
+++ linux.18p8/drivers/char/misc.c	Mon Sep 11 17:33:47 2000
@@ -43,9 +43,6 @@
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/init.h>
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-#endif
 
 #include <linux/tty.h>
 #include <linux/selection.h>
@@ -87,6 +84,7 @@
 extern int pc110pad_init(void);
 extern int pmu_device_init(void);
 extern int tosh_init(void);
+extern int rng_init(void);
 
 static int misc_read_proc(char *buf, char **start, off_t offset,
 			  int len, int *eof, void *private)
@@ -241,9 +239,6 @@
 #ifdef CONFIG_DTLK
 	dtlk_init();
 #endif
-#ifdef CONFIG_APM
-	apm_init();
-#endif
 #ifdef CONFIG_H8
 	h8_init();
 #endif
@@ -279,6 +274,9 @@
 #endif
 #ifdef CONFIG_SGI
 	streamable_init ();
+#endif
+#ifdef CONFIG_INTEL_RNG
+	rng_init ();
 #endif
 #ifdef CONFIG_TOSHIBA
 	tosh_init();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/n_hdlc.c linux.18p8/drivers/char/n_hdlc.c
--- linux.vanilla/drivers/char/n_hdlc.c	Sun Jun 11 21:44:13 2000
+++ linux.18p8/drivers/char/n_hdlc.c	Fri Sep  1 22:03:12 2000
@@ -118,13 +118,6 @@
 #include <linux/kerneld.h>
 #endif
 
-#if LINUX_VERSION_CODE < VERSION(2,3,0) 
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
-#define init_waitqueue_head(head) *(head) = NULL
-#define set_current_state(a) current->state = (a)
-#endif
-
 #if LINUX_VERSION_CODE >= VERSION(2,1,4)
 #include <asm/segment.h>
 #define GET_USER(error,value,addr) error = get_user(value,addr)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/pc_keyb.c linux.18p8/drivers/char/pc_keyb.c
--- linux.vanilla/drivers/char/pc_keyb.c	Sat Sep  9 18:42:35 2000
+++ linux.18p8/drivers/char/pc_keyb.c	Fri Sep  1 13:51:29 2000
@@ -428,6 +428,8 @@
 #endif
 }
 
+static unsigned char kbd_exists = 1;
+
 /*
  * This reads the keyboard status port, and does the
  * appropriate action.
@@ -450,6 +452,7 @@
 		if (status & KBD_STAT_MOUSE_OBF) {
 			handle_mouse_event(scancode);
 		} else {
+			kbd_exists = 1;
 			if (do_acknowledge(scancode))
 				handle_scancode(scancode, !(scancode & 0x80));
 			mark_bh(KEYBOARD_BH);
@@ -506,7 +509,7 @@
 			mdelay(1);
 			if (!--timeout) {
 #ifdef KBD_REPORT_TIMEOUTS
-				printk(KERN_WARNING "Keyboard timeout[2]\n");
+				printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?\n");
 #endif
 				return 0;
 			}
@@ -520,8 +523,10 @@
 
 void pckbd_leds(unsigned char leds)
 {
-	if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))
-	    send_data(KBD_CMD_ENABLE);	/* re-enable kbd if any errors */
+	if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) {
+		send_data(KBD_CMD_ENABLE);	/* re-enable kbd if any errors */
+		kbd_exists = 0;
+	}
 }
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/qpmouse.c linux.18p8/drivers/char/qpmouse.c
--- linux.vanilla/drivers/char/qpmouse.c	Fri Apr 21 12:46:05 2000
+++ linux.18p8/drivers/char/qpmouse.c	Thu Aug 31 15:16:11 2000
@@ -349,9 +349,14 @@
 
 	printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n");
 /*	printk("82C710 address = %x (should be 0x310)\n", qp_data); */
+	queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+	if(queue==NULL)
+	{
+		printk(KERN_ERR "qpmouse: no queue memory.\n");
+		return -ENOMEM;
+	}	
 	qp_present = 1;
 	misc_register(&qp_mouse);
-	queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
 	queue->proc_list = NULL;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/radio-maestro.c linux.18p8/drivers/char/radio-maestro.c
--- linux.vanilla/drivers/char/radio-maestro.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/radio-maestro.c	Thu Sep 14 15:36:46 2000
@@ -0,0 +1,383 @@
+/* Maestro PCI sound card radio driver for Linux support
+ * (c) 2000 A. Tlalka, atlka@pg.gda.pl
+ * Notes on the hardware
+ *
+ *  + Frequency control is done digitally 
+ *  + No volume control - only mute/unmute - you have to use Aux line volume
+ *  control on Maestro card to set the volume
+ *  + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
+ *  frequency setting (>100ms) and only when the radio is unmuted.
+ *  version 0.02
+ *  + io port is automatically detected - only the first radio is used
+ *  version 0.03
+ *  + thread access locking additions
+ *  version 0.04
+ * + code improvements
+ * + VIDEO_TUNER_LOW is permanent
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <linux/pci.h>
+#include <linux/videodev.h>
+
+#define DRIVER_VERSION	"0.04"
+
+#define PCI_VENDOR_ESS                  0x125D
+#define PCI_DEVICE_ID_ESS_ESS1968       0x1968          /* Maestro 2    */
+#define PCI_DEVICE_ID_ESS_ESS1978       0x1978          /* Maestro 2E   */
+
+#define GPIO_DATA       0x60   /* port offset from ESS_IO_BASE */
+
+#define IO_MASK		4      /* mask      register offset from GPIO_DATA
+				bits 1=unmask write to given bit */
+#define IO_DIR		8      /* direction register offset from GPIO_DATA
+				bits 0/1=read/write direction */
+
+#define GPIO6           0x0040 /* mask bits for GPIO lines */
+#define GPIO7           0x0080
+#define GPIO8           0x0100
+#define GPIO9           0x0200
+
+#define STR_DATA        GPIO6  /* radio TEA5757 pins and GPIO bits */
+#define STR_CLK         GPIO7
+#define STR_WREN        GPIO8
+#define STR_MOST        GPIO9
+
+#define FREQ_LO		 50*16000
+#define FREQ_HI		150*16000
+
+#define FREQ_IF         171200 /* 10.7*16000   */
+#define FREQ_STEP       200    /* 12.5*16      */
+
+#define FREQ2BITS(x)	((((unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
+			/(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
+
+#define BITS2FREQ(x)	((x) * FREQ_STEP - FREQ_IF)
+
+
+
+static int radio_open(struct video_device *, int);
+static int radio_ioctl(struct video_device *, unsigned int, void *);
+static void radio_close(struct video_device *);
+
+static struct video_device maestro_radio=
+{
+	"Maestro radio",
+	VID_TYPE_TUNER,
+	VID_HARDWARE_SF16MI,
+	radio_open,
+	radio_close,
+	NULL,
+	NULL,
+	NULL,
+	radio_ioctl,
+	NULL,
+	NULL
+};
+
+static struct radio_device
+{
+	__u16	io,	/* base of Maestro card radio io (GPIO_DATA)*/
+		muted,	/* VIDEO_AUDIO_MUTE */
+		stereo,	/* VIDEO_TUNER_STEREO_ON */	
+		tuned;	/* signal strength (0 or 0xffff) */
+	struct  semaphore lock;
+} radio_unit = {0, 0, 0, 0, MUTEX};
+
+static int users = 0;
+
+static void sleep_125ms(void)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(HZ >> 3);
+}
+
+static void udelay2(void)
+{
+	udelay(2);
+}
+
+static void udelay4(void)
+{
+	udelay(4);
+}
+
+static void udelay16(void)
+{
+	udelay(16);
+}
+
+static __u32 radio_bits_get(struct radio_device *dev)
+{
+	register __u16 io=dev->io, l, rdata;
+	register __u32 data=0;
+	__u16 omask;
+	omask = inw(io + IO_MASK);
+	outw(~(STR_CLK | STR_WREN), io + IO_MASK);
+	outw(0, io);
+	udelay16();
+	for (l=24;l--;) {
+		outw(STR_CLK, io);		/* HI state */
+		udelay2();
+		if(!l) 
+			dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
+		outw(0, io);			/* LO state */
+		udelay2();
+		data <<= 1;			/* shift data */
+		rdata = inw(io);
+		if(!l)
+			dev->stereo =  rdata & STR_MOST ? 
+			0 : VIDEO_TUNER_STEREO_ON;
+		else
+			if(rdata & STR_DATA)
+				data++;
+		udelay2();
+	}
+	if(dev->muted)
+		outw(STR_WREN, io);
+	udelay4();
+	outw(omask, io + IO_MASK);
+	return data & 0x3ffe;
+}
+
+static void radio_bits_set(struct radio_device *dev, __u32 data)
+{
+	register __u16 io=dev->io, l, bits;
+	__u16 omask, odir;
+	omask = inw(io + IO_MASK);
+	odir  = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
+	outw(odir | STR_DATA, io + IO_DIR);
+	outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
+	udelay16();
+	for (l=25;l;l--) {
+		bits = ((data >> 18) & STR_DATA) | STR_WREN ;
+		data <<= 1;			/* shift data */
+		outw(bits, io);			/* start strobe */
+		udelay2();
+		outw(bits | STR_CLK, io);	/* HI level */
+		udelay2();   
+		outw(bits, io);			/* LO level */
+		udelay4();
+	}
+	if(!dev->muted)
+		outw(0, io);
+	udelay4();
+	outw(omask, io + IO_MASK);
+	outw(odir, io + IO_DIR);
+	sleep_125ms();
+}
+
+inline static int radio_function(struct video_device *dev, 
+				 unsigned int cmd, void *arg)
+{
+	struct radio_device *card=dev->priv;
+	switch(cmd) {
+		case VIDIOCGCAP: {
+			struct video_capability v;
+			strcpy(v.name, "Maestro radio");
+			v.type=VID_TYPE_TUNER;
+			v.channels=v.audios=1;
+			v.maxwidth=v.maxheight=v.minwidth=v.minheight=0;
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCGTUNER: {
+			struct video_tuner v;
+			if(copy_from_user(&v, arg,sizeof(v))!=0)
+				return -EFAULT;
+			if(v.tuner)
+				return -EINVAL;
+			(void)radio_bits_get(card);
+			v.flags = VIDEO_TUNER_LOW | card->stereo;
+			v.signal = card->tuned;
+			strcpy(v.name, "FM");
+			v.rangelow = FREQ_LO;
+			v.rangehigh = FREQ_HI;
+			v.mode = VIDEO_MODE_AUTO;
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+		        return 0;
+		}
+		case VIDIOCSTUNER: {
+			struct video_tuner v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.tuner!=0)
+				return -EINVAL;
+			return 0;
+		}
+		case VIDIOCGFREQ: {
+			unsigned long tmp=BITS2FREQ(radio_bits_get(card));
+			if(copy_to_user(arg, &tmp, sizeof(tmp)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSFREQ: {
+			unsigned long tmp;
+			if(copy_from_user(&tmp, arg, sizeof(tmp)))
+				return -EFAULT;
+			if ( tmp<FREQ_LO || tmp>FREQ_HI )
+				return -EINVAL;
+			radio_bits_set(card, FREQ2BITS(tmp));
+			return 0;
+		}
+		case VIDIOCGAUDIO: {	
+			struct video_audio v;
+			strcpy(v.name, "Radio");
+			v.audio=v.volume=v.bass=v.treble=v.balance=v.step=0;
+			v.flags=VIDEO_AUDIO_MUTABLE | card->muted;
+			v.mode=VIDEO_SOUND_STEREO;
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;		
+		}
+		case VIDIOCSAUDIO: {
+			struct video_audio v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.audio)
+				return -EINVAL;
+			{
+				register __u16 io=card->io;
+				register __u16 omask = inw(io + IO_MASK);
+				outw(~STR_WREN, io + IO_MASK);
+				outw((card->muted = v.flags & VIDEO_AUDIO_MUTE)
+				     ? STR_WREN : 0, io);
+				udelay4();
+				outw(omask, io + IO_MASK);
+				sleep_125ms();
+				return 0;
+			}
+		}
+		case VIDIOCGUNIT: {
+			struct video_unit v;
+			v.video=VIDEO_NO_UNIT;
+			v.vbi=VIDEO_NO_UNIT;
+			v.radio=dev->minor;
+			v.audio=0;
+			v.teletext=VIDEO_NO_UNIT;
+			if(copy_to_user(arg, &v, sizeof(v)))
+				return -EFAULT;
+			return 0;		
+		}
+		default: return -ENOIOCTLCMD;
+	}
+}
+
+static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct radio_device *card=dev->priv;
+	int ret;
+	down(&card->lock);
+	ret = radio_function(dev, cmd, arg);
+	up(&card->lock);
+	return ret;
+}
+
+static int radio_open(struct video_device *dev, int flags)
+{
+	if(users)
+		return -EBUSY;
+	users++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static void radio_close(struct video_device *dev)
+{
+	users--;
+	MOD_DEC_USE_COUNT;
+}
+
+
+inline static __u16 radio_install(struct pci_dev *pcidev);
+
+#ifdef MODULE
+MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
+MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
+
+EXPORT_NO_SYMBOLS;
+
+void cleanup_module(void)
+{
+	video_unregister_device(&maestro_radio);
+}
+
+int init_module(void)
+#else
+__initfunc(int maestro_radio_init(struct video_init *v))
+#endif
+{
+	register __u16 found=0;
+	struct pci_dev *pcidev = NULL;
+	if(!pci_present())
+		return -ENODEV;
+	while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS, 
+						  PCI_DEVICE_ID_ESS_ESS1968,
+						  pcidev)))
+		found |= radio_install(pcidev);
+	while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS,
+						  PCI_DEVICE_ID_ESS_ESS1978, 
+						  pcidev)))
+		found |= radio_install(pcidev);
+	if(!found) {
+		printk(KERN_INFO "radio-maestro: no devices found.\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+inline static __u16 radio_power_on(struct radio_device *dev)
+{
+	register __u16 io=dev->io;
+	register __u32 ofreq;
+	__u16 omask, odir;
+	omask = inw(io + IO_MASK);
+	odir  = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
+	outw(odir & ~STR_WREN, io + IO_DIR);
+	dev->muted = inw(io) & STR_WREN ? 0 : VIDEO_AUDIO_MUTE;
+	outw(odir, io + IO_DIR);
+	outw(~(STR_WREN | STR_CLK), io + IO_MASK);
+	outw(dev->muted ? 0 : STR_WREN, io);
+	udelay16();
+	outw(omask, io + IO_MASK);
+	ofreq = radio_bits_get(dev);
+	if((ofreq<FREQ2BITS(FREQ_LO)) || (ofreq>FREQ2BITS(FREQ_HI)))
+		ofreq = FREQ2BITS(FREQ_LO);
+	radio_bits_set(dev, ofreq);
+	return (ofreq == radio_bits_get(dev));
+}
+
+inline static __u16 radio_install(struct pci_dev *pcidev)
+{
+	if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
+		return 0;
+	
+	radio_unit.io = (pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)
+		+ GPIO_DATA;
+	maestro_radio.priv = &radio_unit;
+	if(radio_power_on(&radio_unit)) {
+		if(video_register_device(&maestro_radio, VFL_TYPE_RADIO)==-1) {
+			printk("radio-maestro: can't register device!");
+			return 0;
+		}
+		printk(KERN_INFO "radio-maestro: version "
+		       DRIVER_VERSION 
+		       " time " 
+		       __TIME__ "  "
+		       __DATE__
+		       "\n");
+		printk(KERN_INFO "radio-maestro: radio chip initialized\n");
+		return 1;
+	} else
+		return 0;   
+}
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/rtc.c linux.18p8/drivers/char/rtc.c
--- linux.vanilla/drivers/char/rtc.c	Fri Apr 21 12:46:06 2000
+++ linux.18p8/drivers/char/rtc.c	Tue Sep 12 13:14:58 2000
@@ -113,10 +113,15 @@
 unsigned char days_in_mo[] = 
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
+extern spinlock_t rtc_lock;
+
 /*
  *	A very tiny interrupt handler. It runs with SA_INTERRUPT set,
- *	so that there is no possibility of conflicting with the
- *	set_rtc_mmss() call that happens during some timer interrupts.
+ *	but there is possibility of conflicting with the set_rtc_mmss()
+ *	call (the rtc irq and the timer irq can easily run at the same
+ *	time in two different CPUs). So we need to serializes
+ *	accesses to the chip with the rtc_lock spinlock that each
+ *	architecture should implement in the timer code.
  *	(See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
  */
 
@@ -131,7 +136,10 @@
 
 	rtc_irq_data += 0x100;
 	rtc_irq_data &= ~0xff;
+	/* runs with irq locally disabled (see SA_INTERRUPT flag). */
+	spin_lock(&rtc_lock);
 	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
+	spin_unlock(&rtc_lock);
 	wake_up_interruptible(&rtc_wait);	
 
 	if (rtc_status & RTC_TIMER_ON)
@@ -276,8 +284,7 @@
 		if (sec >= 60)
 			sec = 0xff;
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&rtc_lock, flags);
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
 		    RTC_ALWAYS_BCD)
 		{
@@ -288,7 +295,7 @@
 		CMOS_WRITE(hrs, RTC_HOURS_ALARM);
 		CMOS_WRITE(min, RTC_MINUTES_ALARM);
 		CMOS_WRITE(sec, RTC_SECONDS_ALARM);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&rtc_lock, flags);
 
 		return 0;
 	}
@@ -336,12 +343,11 @@
 		if ((yrs -= epoch) > 255)    /* They are unsigned */
 			return -EINVAL;
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&rtc_lock, flags);
 		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
 		    || RTC_ALWAYS_BCD) {
 			if (yrs > 169) {
-				restore_flags(flags);
+				spin_unlock_irqrestore(&rtc_lock, flags);
 				return -EINVAL;
 			}
 			if (yrs >= 100)
@@ -370,7 +376,7 @@
 		CMOS_WRITE(save_control, RTC_CONTROL);
 		CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
 
-		restore_flags(flags);
+		spin_unlock_irqrestore(&rtc_lock, flags);
 		return 0;
 	}
 	case RTC_IRQP_READ:	/* Read the periodic IRQ rate.	*/
@@ -405,12 +411,11 @@
 
 		rtc_freq = arg;
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&rtc_lock, flags);
 		val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
 		val |= (16 - tmp);
 		CMOS_WRITE(val, RTC_FREQ_SELECT);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&rtc_lock, flags);
 		return 0;
 	}
 #ifdef __alpha__
@@ -465,15 +470,14 @@
 	unsigned char tmp;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	tmp = CMOS_READ(RTC_CONTROL);
 	tmp &=  ~RTC_PIE;
 	tmp &=  ~RTC_AIE;
 	tmp &=  ~RTC_UIE;
 	CMOS_WRITE(tmp, RTC_CONTROL);
 	CMOS_READ(RTC_INTR_FLAGS);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 
 	if (rtc_status & RTC_TIMER_ON) {
 		rtc_status &= ~RTC_TIMER_ON;
@@ -546,11 +550,10 @@
 		while (jiffies - uip_watchdog < 2*HZ/100)
 			barrier();
 	
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	year = CMOS_READ(RTC_YEAR);
 	ctrl = CMOS_READ(RTC_CONTROL);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 	
 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 		BCD_TO_BIN(year);       /* This should never happen... */
@@ -568,11 +571,10 @@
 	init_timer(&rtc_irq_timer);
 	rtc_irq_timer.function = rtc_dropped_irq;
 	rtc_wait = NULL;
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	/* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
 	CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 	rtc_freq = 1024;
 	return 0;
 }
@@ -596,12 +598,11 @@
 	printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", rtc_freq);
 	mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	rtc_irq_data += ((rtc_freq/HZ)<<8);
 	rtc_irq_data &= ~0xff;
 	rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);	/* restart */
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 }
 
 /*
@@ -615,11 +616,10 @@
 	unsigned char batt, ctrl;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	batt = CMOS_READ(RTC_VALID) & RTC_VRT;
 	ctrl = CMOS_READ(RTC_CONTROL);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 
 	p = buf;
 
@@ -690,10 +690,9 @@
 	unsigned long flags;
 	unsigned char uip;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 	return uip;
 }
 
@@ -723,8 +722,7 @@
 	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
 	 * by the RTC when initially set to a non-zero value.
 	 */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
 	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
 	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
@@ -732,7 +730,7 @@
 	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
 	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
 	ctrl = CMOS_READ(RTC_CONTROL);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 
 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 	{
@@ -763,13 +761,12 @@
 	 * Only the values that we read from the RTC are set. That
 	 * means only tm_hour, tm_min, and tm_sec.
 	 */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
 	alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM);
 	alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM);
 	ctrl = CMOS_READ(RTC_CONTROL);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 
 	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 	{
@@ -794,13 +791,12 @@
 	unsigned char val;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	val = CMOS_READ(RTC_CONTROL);
 	val &=  ~bit;
 	CMOS_WRITE(val, RTC_CONTROL);
 	CMOS_READ(RTC_INTR_FLAGS);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 	rtc_irq_data = 0;
 }
 
@@ -809,12 +805,11 @@
 	unsigned char val;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&rtc_lock, flags);
 	val = CMOS_READ(RTC_CONTROL);
 	val |= bit;
 	CMOS_WRITE(val, RTC_CONTROL);
 	CMOS_READ(RTC_INTR_FLAGS);
 	rtc_irq_data = 0;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&rtc_lock, flags);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/saa7111.c linux.18p8/drivers/char/saa7111.c
--- linux.vanilla/drivers/char/saa7111.c	Fri Apr 21 12:46:06 2000
+++ linux.18p8/drivers/char/saa7111.c	Mon Sep 11 17:49:08 2000
@@ -85,7 +85,7 @@
 
 static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len)
 {
-	int ack;
+	int ack = 0;
 	unsigned subaddr;
 	unsigned long flags;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/saa7185.c linux.18p8/drivers/char/saa7185.c
--- linux.vanilla/drivers/char/saa7185.c	Fri Apr 21 12:46:06 2000
+++ linux.18p8/drivers/char/saa7185.c	Mon Sep 11 17:49:08 2000
@@ -85,7 +85,7 @@
 
 static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len)
 {
-	int ack;
+	int ack=0;
 	unsigned subaddr;
 	unsigned long flags;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/synclink.c linux.18p8/drivers/char/synclink.c
--- linux.vanilla/drivers/char/synclink.c	Sat Sep  9 18:42:36 2000
+++ linux.18p8/drivers/char/synclink.c	Fri Sep  1 22:02:52 2000
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * ==FILEDATE 20000705==
+ * ==FILEDATE 20000821==
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -102,14 +102,6 @@
 #include <linux/termios.h>
 #include <linux/tqueue.h>
 
-#if LINUX_VERSION_CODE < VERSION(2,3,0) 
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
-#define init_waitqueue_head(head) *(head) = NULL
-#define DECLARE_MUTEX(name) struct semaphore (name) = MUTEX
-#define set_current_state(a) current->state = (a)
-#endif
-
 #ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
 #define CONFIG_SYNCLINK_SYNCPPP 1
 #endif
@@ -124,7 +116,6 @@
 #define netif_queue_stopped(a) ((a)->tbusy)
 #else
 #include "../net/wan/syncppp.h"
-#define netif_queue_stopped(a) test_bit(LINK_STATE_XOFF,&(a)->state)
 #endif
 #endif
 
@@ -401,8 +392,9 @@
 /*
  * The size of the serial xmit buffer is 1 page, or 4096 bytes
  */
+#ifndef SERIAL_XMIT_SIZE
 #define SERIAL_XMIT_SIZE 4096
-
+#endif
 
 /*
  * These macros define the offsets used in calculating the
@@ -965,7 +957,7 @@
 #endif
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "1.19";
+static char *driver_version = "1.22";
 
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
@@ -4528,6 +4520,12 @@
 	if (!serial_table || !serial_termios || !serial_termios_locked){
 		printk("%s(%d):Can't allocate tty/termios arrays.\n",
 			__FILE__,__LINE__);
+		if (serial_table)
+			kfree(serial_table);
+		if (serial_termios)
+			kfree(serial_termios);
+		if (serial_termios_locked)
+			kfree(serial_termios_locked);
 		return -ENOMEM;
 	}
 	
@@ -7396,12 +7394,7 @@
 void mgsl_load_pci_memory( char* TargetPtr, const char* SourcePtr, 
 	unsigned short count )
 {
-	/*******************************************************/
-	/* A load interval of 16 allows for 4 32-bit writes at */
-	/* 60ns each for a maximum latency of 240ns on the		 */
-	/* local bus.														 */
-	/*******************************************************/
-
+	/* 16 32-bit writes @ 60ns each = 960ns max latency on local bus */
 #define PCI_LOAD_INTERVAL 64
 
 	unsigned short Intervalcount = count / PCI_LOAD_INTERVAL;
@@ -7411,7 +7404,7 @@
 	for ( Index = 0 ; Index < Intervalcount ; Index++ )
 	{
 		memcpy(TargetPtr, SourcePtr, PCI_LOAD_INTERVAL);
-		Dummy = *((unsigned long *)TargetPtr);
+		Dummy = *((volatile unsigned long *)TargetPtr);
 		TargetPtr += PCI_LOAD_INTERVAL;
 		SourcePtr += PCI_LOAD_INTERVAL;
 	}
@@ -7582,7 +7575,7 @@
 	sppp_attach(&info->pppdev);
 
 	d = info->netdev;
-	d->name = info->netname;
+	strcpy(d->name, info->netname);
 	d->base_addr = info->io_base;
 	d->irq = info->irq_level;
 	d->dma = info->dma_level;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/wd501p.h linux.18p8/drivers/char/wd501p.h
--- linux.vanilla/drivers/char/wd501p.h	Fri Apr 21 23:14:54 2000
+++ linux.18p8/drivers/char/wd501p.h	Mon Sep 11 18:02:33 2000
@@ -25,11 +25,21 @@
 #define WDT_COUNT1		(io+1)
 #define WDT_COUNT2		(io+2)
 #define WDT_CR			(io+3)
-#define WDT_SR			(io+4)
-#define WDT_RT			(io+5)
-#define WDT_UNUSED		(io+6)
+#define WDT_SR			(io+4)		/* Buzzer start PCI */
+#define WDT_RT			(io+5)		/* Buzzer stop PCI */
+#define WDT_BUZZER		(io+6)		/* PCI only */
 #define WDT_DC			(io+7)
 
+/* The following are only on the PCI card, they're outside of I/O space on
+ * the ISA card: */
+#define WDT_CLOCK		(io+12)	/* COUNT2: rd=16.67MHz, wr=2.0833MHz */
+/* inverted opto isolated reset output: */
+#define WDT_OPTONOTRST		(io+13)	/* wr=enable, rd=disable */
+/* opto isolated reset output: */
+#define WDT_OPTORST		(io+14)	/* wr=enable, rd=disable */
+/* programmable outputs: */
+#define WDT_PROGOUT		(io+15)	/* wr=enable, rd=disable */
+
 #define WDC_SR_WCCR		1	/* Active low */
 #define WDC_SR_TGOOD		2
 #define WDC_SR_ISOI0		4
@@ -39,6 +49,8 @@
 #define WDC_SR_PSUUNDR		64	/* Active low */
 #define WDC_SR_IRQ		128	/* Active low */
 
+#ifndef WDT_IS_PCI
+
 /*
  *	Feature Map 1 is the active high inputs not supported on your card.
  *	Feature Map 2 is the active low inputs not supported on your card.
@@ -62,6 +74,13 @@
 #endif
 
 #ifdef CONFIG_WDT_500		/* Minimal board */
+#define FEATUREMAP1		(WDC_SR_TGOOD|WDC_SR_FANGOOD)
+#define FEATUREMAP2		(WDC_SR_PSUOVER|WDC_SR_PSUUNDR)
+#define WDT_OPTION_MASK		(WDIOF_OVERHEAT)
+#endif
+
+#else
+
 #define FEATUREMAP1		(WDC_SR_TGOOD|WDC_SR_FANGOOD)
 #define FEATUREMAP2		(WDC_SR_PSUOVER|WDC_SR_PSUUNDR)
 #define WDT_OPTION_MASK		(WDIOF_OVERHEAT)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/wdt_pci.c linux.18p8/drivers/char/wdt_pci.c
--- linux.vanilla/drivers/char/wdt_pci.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/char/wdt_pci.c	Wed Sep 13 17:10:47 2000
@@ -0,0 +1,561 @@
+/*
+ *	Industrial Computer Source WDT500/501 driver for Linux 2.1.x
+ *
+ *	(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.com
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *	
+ *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
+ *	warranty for any of this software. This material is provided 
+ *	"AS-IS" and at no charge.	
+ *
+ *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ *	Release 0.08.
+ *
+ *	Fixes
+ *		Dave Gregorich	:	Modularisation and minor bugs
+ *		Alan Cox	:	Added the watchdog ioctl() stuff
+ *		Alan Cox	:	Fixed the reboot problem (as noted by
+ *					Matt Crocker).
+ *		Alan Cox	:	Added wdt= boot option
+ *		Alan Cox	:	Cleaned up copy/user stuff
+ *		Tim Hockin	:	Added insmod parameters, comment cleanup
+ *					Parameterized timeout
+ *		JP Nollmann	:	Added support for PCI wdt501p
+ *		Alan Cox	:	Split ISA and PCI cards into two drivers
+ *		Jeff Garzik	:	PCI cleanups
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#define WDT_IS_PCI
+#include "wd501p.h"
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/kcomp.h>
+#include <linux/pci.h>
+
+#define PFX "wdt_pci: "
+
+/*
+ * Until Access I/O gets their application for a PCI vendor ID approved,
+ * I don't think that it's appropriate to move these constants into the
+ * regular pci_ids.h file. -- JPN 2000/01/18
+ */
+
+#ifndef PCI_VENDOR_ID_ACCESSIO
+#define PCI_VENDOR_ID_ACCESSIO 0x494f
+#endif
+#ifndef PCI_DEVICE_ID_WDG_CSM
+#define PCI_DEVICE_ID_WDG_CSM 0x22c0
+#endif
+
+static int wdt_is_open=0;
+
+/*
+ *	You must set these - there is no sane way to probe for this board.
+ *	You can use wdt=x,y to set these now.
+ */
+ 
+static int io=0x240;
+static int irq=11;
+
+#define WD_TIMO (100*60)		/* 1 minute */
+
+/*
+ *	Programming support
+ */
+ 
+static void wdtpci_ctr_mode(int ctr, int mode)
+{
+	ctr<<=6;
+	ctr|=0x30;
+	ctr|=(mode<<1);
+	outb_p(ctr, WDT_CR);
+}
+
+static void wdtpci_ctr_load(int ctr, int val)
+{
+	outb_p(val&0xFF, WDT_COUNT0+ctr);
+	outb_p(val>>8, WDT_COUNT0+ctr);
+}
+
+/*
+ *	Kernel methods.
+ */
+ 
+ 
+/**
+ *	wdtpci_status:
+ *	
+ *	Extract the status information from a WDT watchdog device. There are
+ *	several board variants so we have to know which bits are valid. Some
+ *	bits default to one and some to zero in order to be maximally painful.
+ *
+ *	we then map the bits onto the status ioctl flags.
+ */
+ 
+static int wdtpci_status(void)
+{
+	/*
+	 *	Status register to bit flags
+	 */
+	 
+	int flag=0;
+	unsigned char status=inb_p(WDT_SR);
+	status|=FEATUREMAP1;
+	status&=~FEATUREMAP2;	
+	
+	if(!(status&WDC_SR_TGOOD))
+		flag|=WDIOF_OVERHEAT;
+	if(!(status&WDC_SR_PSUOVER))
+		flag|=WDIOF_POWEROVER;
+	if(!(status&WDC_SR_PSUUNDR))
+		flag|=WDIOF_POWERUNDER;
+	if(!(status&WDC_SR_FANGOOD))
+		flag|=WDIOF_FANFAULT;
+	if(status&WDC_SR_ISOI0)
+		flag|=WDIOF_EXTERN1;
+	if(status&WDC_SR_ISII1)
+		flag|=WDIOF_EXTERN2;
+	return flag;
+}
+
+/**
+ *	wdtpci_interrupt:
+ *	@irq:		Interrupt number
+ *	@dev_id:	Unused as we don't allow multiple devices.
+ *	@regs:		Unused.
+ *
+ *	Handle an interrupt from the board. These are raised when the status
+ *	map changes in what the board considers an interesting way. That means
+ *	a failure condition occuring.
+ */
+ 
+static void wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/*
+	 *	Read the status register see what is up and
+	 *	then printk it. 
+	 */
+	 
+	unsigned char status=inb_p(WDT_SR);
+	
+	status|=FEATUREMAP1;
+	status&=~FEATUREMAP2;	
+	
+	printk(KERN_CRIT "WDT status %d\n", status);
+	
+	if(!(status&WDC_SR_TGOOD))
+		printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));
+	if(!(status&WDC_SR_PSUOVER))
+		printk(KERN_CRIT "PSU over voltage.\n");
+	if(!(status&WDC_SR_PSUUNDR))
+		printk(KERN_CRIT "PSU under voltage.\n");
+	if(!(status&WDC_SR_FANGOOD))
+		printk(KERN_CRIT "Possible fan fault.\n");
+	if(!(status&WDC_SR_WCCR))
+#ifdef SOFTWARE_REBOOT
+#ifdef ONLY_TESTING
+		printk(KERN_CRIT "Would Reboot.\n");
+#else		
+		printk(KERN_CRIT "Initiating system reboot.\n");
+		machine_restart(NULL);
+#endif		
+#else
+		printk(KERN_CRIT "Reset in 5ms.\n");
+#endif		
+}
+
+
+static long long wdtpci_llseek(struct file *file, long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+/**
+ *	wdtpci_ping:
+ *
+ *	Reload counter one with the watchdog timeout. We don't bother reloading
+ *	the cascade counter. 
+ */
+ 
+static void wdtpci_ping(void)
+{
+	/* Write a watchdog value */
+	inb_p(WDT_DC);
+	wdtpci_ctr_mode(1,2);
+	wdtpci_ctr_load(1,WD_TIMO);		/* Timeout */
+	outb_p(0, WDT_DC);
+}
+
+/**
+ *	wdtpci_write:
+ *	@file: file handle to the watchdog
+ *	@buf: buffer to write (unused as data does not matter here 
+ *	@count: count of bytes
+ *	@ppos: pointer to the position to write. No seeks allowed
+ *
+ *	A write to a watchdog device is defined as a keepalive signal. Any
+ *	write of data will do, as we we don't define content meaning.
+ */
+ 
+static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if(count)
+	{
+		wdtpci_ping();
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ *	wdtpci_read:
+ *	@file: file handle to the watchdog board
+ *	@buf: buffer to write 1 byte into
+ *	@count: length of buffer
+ *	@ptr: offset (no seek allowed)
+ *
+ *	Read reports the temperature in degrees Fahrenheit. The API is in
+ *	farenheit. It was designed by an imperial measurement luddite.
+ */
+ 
+static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+	unsigned short c=inb_p(WDT_RT);
+	unsigned char cp;
+	
+	/*  Can't seek (pread) on this device  */
+	if (ptr != &file->f_pos)
+		return -ESPIPE;
+
+	switch(MINOR(file->f_dentry->d_inode->i_rdev))
+	{
+		case TEMP_MINOR:
+			c*=11;
+			c/=15;
+			cp=c+7;
+			if(copy_to_user(buf,&cp,1))
+				return -EFAULT;
+			return 1;
+		default:
+			return -EINVAL;
+	}
+}
+
+/**
+ *	wdtpci_ioctl:
+ *	@inode: inode of the device
+ *	@file: file handle to the device
+ *	@cmd: watchdog command
+ *	@arg: argument pointer
+ *
+ *	The watchdog API defines a common set of functions for all watchdogs
+ *	according to their available features. We only actually usefully support
+ *	querying capabilities and current status. 
+ */
+ 
+static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	static struct watchdog_info ident=
+	{
+		WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
+			|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT,
+		1,
+		"WDT500/501PCI"
+	};
+	
+	ident.options&=WDT_OPTION_MASK;	/* Mask down to the card we have */
+	switch(cmd)
+	{
+		default:
+			return -ENOIOCTLCMD;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
+
+		case WDIOC_GETSTATUS:
+			return put_user(wdtpci_status(),(int *)arg);
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, (int *)arg);
+		case WDIOC_KEEPALIVE:
+			wdtpci_ping();
+			return 0;
+	}
+}
+
+/**
+ *	wdtpci_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ *	One of our two misc devices has been opened. The watchdog device is
+ *	single open and on opening we load the counters. Counter zero is a 
+ *	100Hz cascade, into counter 1 which downcounts to reboot. When the
+ *	counter triggers counter 2 downcounts the length of the reset pulse
+ *	which set set to be as long as possible. 
+ */
+ 
+static int wdtpci_open(struct inode *inode, struct file *file)
+{
+	switch(MINOR(inode->i_rdev))
+	{
+		case WATCHDOG_MINOR:
+			if(wdt_is_open)
+				return -EBUSY;
+#ifdef CONFIG_WATCHDOG_NOWAYOUT	
+			MOD_INC_USE_COUNT;
+#endif
+			/*
+			 *	Activate 
+			 */
+	 
+			wdt_is_open=1;
+
+			inb_p(WDT_DC);		/* Disable */
+
+			/*
+			 * "pet" the watchdog, as Access says.
+			 * This resets the clock outputs.
+			 */
+				
+			wdtpci_ctr_mode(2,0);
+			outb_p(0, WDT_DC);
+
+			inb_p(WDT_DC);
+
+			outb_p(0, WDT_CLOCK);	/* 2.0833MHz clock */
+			inb_p(WDT_BUZZER);	/* disable */
+			inb_p(WDT_OPTONOTRST);	/* disable */
+			inb_p(WDT_OPTORST);	/* disable */
+			inb_p(WDT_PROGOUT);	/* disable */
+			wdtpci_ctr_mode(0,3);
+			wdtpci_ctr_mode(1,2);
+			wdtpci_ctr_mode(2,1);
+			wdtpci_ctr_load(0,20833);	/* count at 100Hz */
+			wdtpci_ctr_load(1,WD_TIMO);/* Timeout 60 seconds */
+			/* DO NOT LOAD CTR2 on PCI card! -- JPN */
+			outb_p(0, WDT_DC);	/* Enable */
+			return 0;
+		case TEMP_MINOR:
+			return 0;
+		default:
+			return -ENODEV;
+	}
+}
+
+/**
+ *	wdtpci_close:
+ *	@inode: inode to board
+ *	@file: file handle to board
+ *
+ *	The watchdog has a configurable API. There is a religious dispute 
+ *	between people who want their watchdog to be able to shut down and 
+ *	those who want to be sure if the watchdog manager dies the machine
+ *	reboots. In the former case we disable the counters, in the latter
+ *	case you have to open it again very soon.
+ */
+ 
+static int wdtpci_release(struct inode *inode, struct file *file)
+{
+	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+	{
+		lock_kernel();
+#ifndef CONFIG_WATCHDOG_NOWAYOUT	
+		inb_p(WDT_DC);		/* Disable counters */
+		wdtpci_ctr_load(2,0);	/* 0 length reset pulses now */
+#endif		
+		wdt_is_open=0;
+		unlock_kernel();
+	}
+	return 0;
+}
+
+/**
+ *	notify_sys:
+ *	@this: our notifier block
+ *	@code: the event being reported
+ *	@unused: unused
+ *
+ *	Our notifier is called on system shutdowns. We want to turn the card
+ *	off at reboot otherwise the machine will reboot again during memory
+ *	test or worse yet during the following fsck. This would suck, in fact
+ *	trust me - if it happens it does suck.
+ */
+
+static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT)
+	{
+		/* Turn the card off */
+		inb_p(WDT_DC);
+		wdtpci_ctr_load(2,0);
+	}
+	return NOTIFY_DONE;
+}
+ 
+/*
+ *	Kernel Interfaces
+ */
+ 
+ 
+static struct file_operations wdtpci_fops = {
+	llseek:		wdtpci_llseek,
+	read:		wdtpci_read,
+	write:		wdtpci_write,
+	ioctl:		wdtpci_ioctl,
+	open:		wdtpci_open,
+	release:	wdtpci_release,
+};
+
+static struct miscdevice wdtpci_miscdev=
+{
+	WATCHDOG_MINOR,
+	"watchdog",
+	&wdtpci_fops
+};
+
+#ifdef CONFIG_WDT_501
+static struct miscdevice temp_miscdev=
+{
+	TEMP_MINOR,
+	"temperature",
+	&wdtpci_fops
+};
+#endif
+
+/*
+ *	The WDT card needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off. 
+ */
+ 
+static struct notifier_block wdtpci_notifier=
+{
+	wdtpci_notify_sys,
+	NULL,
+	0
+};
+
+
+static int __init wdtpci_init_one (struct pci_dev *dev)
+{
+	static int dev_count = 0;
+
+	dev_count++;
+	if (dev_count > 1) {
+		printk (KERN_ERR PFX
+			"this driver only supports 1 device\n");
+		return -ENODEV;
+	}
+
+	irq = dev->irq;
+	io = dev->base_address[2]&PCI_BASE_ADDRESS_IO_MASK;
+	
+	printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X "
+		"(Interrupt %d)\n", io, irq);
+
+	request_region (io, 16, "wdt-pci");
+	if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ,
+			 "wdt-pci", &wdtpci_miscdev)) {
+		printk (KERN_ERR PFX "IRQ %d is not free.\n", irq);
+		goto err_out_free_res;
+	}
+
+	misc_register (&wdtpci_miscdev);
+
+#ifdef CONFIG_WDT_501
+	misc_register (&temp_miscdev);
+#endif
+
+	register_reboot_notifier (&wdtpci_notifier);
+
+	return 0;
+
+err_out_free_res:
+	release_region (io, 16);
+}
+
+
+static void __exit wdtpci_remove_one (struct pci_dev *pdev)
+{
+	/* here we assume only one device will ever have
+	 * been picked up and registered by probe function */
+	unregister_reboot_notifier(&wdtpci_notifier);
+#ifdef CONFIG_WDT_501_PCI
+	misc_deregister(&temp_miscdev);
+#endif	
+	misc_deregister(&wdtpci_miscdev);
+	free_irq(irq, &wdtpci_miscdev);
+	release_region(io, 16);
+}
+
+/**
+ *	wdtpci_cleanup:
+ *
+ *	Unload the watchdog. You cannot do this with any file handles open.
+ *	If your watchdog is set to continue ticking on close and you unload
+ *	it, well it keeps ticking. We won't get the interrupt but the board
+ *	will not touch PC memory so all is fine. You just have to load a new
+ *	module in 60 seconds or reboot.
+ */
+
+static struct pci_dev *wdt_dev;
+ 
+static void __exit wdtpci_cleanup(void)
+{
+	if(wdt_dev)
+		wdtpci_remove_one(wdt_dev);
+	wdt_dev = NULL;
+}
+
+
+/**
+ * 	wdtpci_init:
+ *
+ *	Set up the WDT watchdog board. All we have to do is grab the
+ *	resources we require and bitch if anyone beat us to them.
+ *	The open() function will actually kick the board off.
+ */
+ 
+static int __init wdtpci_init(void)
+{
+	wdt_dev=pci_find_device(PCI_VENDOR_ID_ACCESSIO, PCI_DEVICE_ID_WDG_CSM, NULL);
+	if (wdt_dev ==NULL)
+		return -ENODEV;
+	if(wdtpci_init_one(wdt_dev)<0)
+	{
+		wdt_dev=NULL;
+		return -ENODEV;
+	}
+	return 0;
+}
+
+
+module_init(wdtpci_init);
+module_exit(wdtpci_cleanup);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_pci.c linux.18p8/drivers/isdn/hisax/hfc_pci.c
--- linux.vanilla/drivers/isdn/hisax/hfc_pci.c	Fri Apr 21 12:46:10 2000
+++ linux.18p8/drivers/isdn/hisax/hfc_pci.c	Mon Sep 11 17:06:28 2000
@@ -1761,6 +1761,7 @@
 			printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
 			return (0);
 		}
+#ifdef notdef
 		if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
 			printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n");
 			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
@@ -1794,6 +1795,7 @@
 			}
 			dev_hfcpci->base_address[1] = (int) cs->hw.hfcpci.pci_io;
 		}
+#endif
 		if (!cs->hw.hfcpci.pci_io) {
 			printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
 			return (0);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/misc/parport_pc.c linux.18p8/drivers/misc/parport_pc.c
--- linux.vanilla/drivers/misc/parport_pc.c	Sun Jun 11 21:44:14 2000
+++ linux.18p8/drivers/misc/parport_pc.c	Sun Sep  3 00:20:02 2000
@@ -902,11 +902,13 @@
 		  { { 0, -1 }, } },
 		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1,
 		  { { 0, -1 }, } },
+		{ PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR, 1,
+		  { { 0, -1 }, } },
 		{ PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902, 1,
 		  { { 0, 1 }, } },
-		{ PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, 1,
-		  { { 2, -1 }, } },
-		{ PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_4008A, 1,
+		{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954PP, 1,
+		  { { 0, -1 }, } },
+		{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_12PCI840, 1,
 		  { { 0, 1 }, } },
 		{ 0, }
 	};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c505.c linux.18p8/drivers/net/3c505.c
--- linux.vanilla/drivers/net/3c505.c	Fri Apr 21 12:46:14 2000
+++ linux.18p8/drivers/net/3c505.c	Mon Sep 11 17:58:02 2000
@@ -129,15 +129,15 @@
 #define INVALID_PCB_MSG(len) \
 	printk(invalid_pcb_msg, (len),filename,__FUNCTION__,__LINE__)
 
-static const char *search_msg = "%s: Looking for 3c505 adapter at address %#x...";
+static char *search_msg __initdata = "%s: Looking for 3c505 adapter at address %#x...";
 
-static const char *stilllooking_msg = "still looking...";
+static char *stilllooking_msg __initdata = "still looking...";
 
-static const char *found_msg = "found.\n";
+static char *found_msg __initdata = "found.\n";
 
-static const char *notfound_msg = "not found (reason = %d)\n";
+static char *notfound_msg __initdata = "not found (reason = %d)\n";
 
-static const char *couldnot_msg = "%s: 3c505 not found\n";
+static char *couldnot_msg __initdata = "%s: 3c505 not found\n";
 
 /*********************************************************
  *
@@ -179,7 +179,7 @@
  * Last element MUST BE 0!
  *****************************************************************/
 
-static const int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
+static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0};
 
 /* Dma Memory related stuff */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c509.c linux.18p8/drivers/net/3c509.c
--- linux.vanilla/drivers/net/3c509.c	Fri Apr 21 12:46:14 2000
+++ linux.18p8/drivers/net/3c509.c	Mon Sep 11 17:58:02 2000
@@ -64,6 +64,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>	/* for udelay() */
+#include <linux/init.h>
 
 #include <asm/spinlock.h>
 #include <asm/bitops.h>
@@ -156,7 +157,7 @@
 	int id;
 };
 
-struct el3_mca_adapters_struct el3_mca_adapters[] = {
+static struct el3_mca_adapters_struct el3_mca_adapters[] __initdata = {
 	{ "3Com 3c529 EtherLink III (10base2)", 0x627c },
 	{ "3Com 3c529 EtherLink III (10baseT)", 0x627d },
 	{ "3Com 3c529 EtherLink III (test mode)", 0x62db },
@@ -166,7 +167,7 @@
 };
 #endif
 
-int el3_probe(struct device *dev)
+int __init el3_probe(struct device *dev)
 {
 	short lrs_state = 0xff, i;
 	int ioaddr, irq, if_port;
@@ -396,7 +397,7 @@
 /* Read a word from the EEPROM using the regular EEPROM access register.
    Assume that we are in register window zero.
  */
-static ushort read_eeprom(int ioaddr, int index)
+static ushort __init read_eeprom(int ioaddr, int index)
 {
 	outw(EEPROM_READ + index, ioaddr + 10);
 	/* Pause for at least 162 us. for the read to take place. */
@@ -405,7 +406,7 @@
 }
 
 /* Read a word from the EEPROM when in the ISA ID probe state. */
-static ushort id_read_eeprom(int index)
+static ushort __init id_read_eeprom(int index)
 {
 	int bit, word = 0;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c515.c linux.18p8/drivers/net/3c515.c
--- linux.vanilla/drivers/net/3c515.c	Sun Jun 11 21:44:14 2000
+++ linux.18p8/drivers/net/3c515.c	Mon Sep 11 17:58:02 2000
@@ -62,6 +62,7 @@
 
 #define NEW_MULTICAST
 #include <linux/delay.h>
+#include <linux/init.h>
 
 /* Kernel version compatibility functions. */
 #define RUN_AT(x) (jiffies + (x))
@@ -399,7 +400,7 @@
 }
 
 #else
-int tc515_probe(struct device *dev)
+int __init tc515_probe(struct device *dev)
 {
 	int cards_found = 0;
 
@@ -412,7 +413,7 @@
 }
 #endif  /* not MODULE */
 
-static int vortex_scan(struct device *dev)
+static int __init vortex_scan(struct device *dev)
 {
 	int cards_found = 0;
 	static int ioaddr = 0x100;
@@ -452,7 +453,7 @@
 	return cards_found;
 }
 
-static struct device *vortex_found_device(struct device *dev, int ioaddr,
+static struct device * __init vortex_found_device(struct device *dev, int ioaddr,
 										  int irq, int product_index,
 										  int options)
 {
@@ -517,7 +518,7 @@
 	return dev;
 }
 
-static int vortex_probe1(struct device *dev)
+static int __init vortex_probe1(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c527.c linux.18p8/drivers/net/3c527.c
--- linux.vanilla/drivers/net/3c527.c	Fri Apr 21 12:46:15 2000
+++ linux.18p8/drivers/net/3c527.c	Mon Sep 11 17:58:02 2000
@@ -124,7 +124,7 @@
 	char		*name;
 };
 
-const struct mca_adapters_t mc32_adapters[] = {
+static struct mca_adapters_t mc32_adapters[] __initdata = {
 	{ 0x0041, "3COM EtherLink MC/32" },
 	{ 0x8EF5, "IBM High Performance Lan Adapter" },
 	{ 0x0000, NULL }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/Config.in linux.18p8/drivers/net/Config.in
--- linux.vanilla/drivers/net/Config.in	Sat Sep  9 18:42:38 2000
+++ linux.18p8/drivers/net/Config.in	Fri Sep  1 13:48:23 2000
@@ -184,7 +184,8 @@
 
 bool 'FDDI driver support' CONFIG_FDDI
 if [ "$CONFIG_FDDI" = "y" ]; then
-  bool 'Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+  bool '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
+  tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/Makefile linux.18p8/drivers/net/Makefile
--- linux.vanilla/drivers/net/Makefile	Sat Sep  9 18:42:38 2000
+++ linux.18p8/drivers/net/Makefile	Fri Sep  1 13:48:44 2000
@@ -5,7 +5,7 @@
 
 SUB_DIRS     := 
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc sk98lin lmc
+ALL_SUB_DIRS := $(SUB_DIRS) hamradio irda fc sk98lin lmc skfp
 
 L_TARGET := net.a
 L_OBJS   :=
@@ -620,6 +620,16 @@
 else
   ifeq ($(CONFIG_SK98LIN),m)
     MOD_IN_SUB_DIRS += sk98lin
+  endif
+endif
+
+ifeq ($(CONFIG_SKFP),y)
+  SUB_DIRS += skfp
+  MOD_IN_SUB_DIRS += skfp
+  L_OBJS += skfp/skfp.o
+else
+  ifeq ($(CONFIG_SKFP),m)
+    MOD_IN_SUB_DIRS += skfp
   endif
 endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/Space.c linux.18p8/drivers/net/Space.c
--- linux.vanilla/drivers/net/Space.c	Sat Sep  9 18:42:38 2000
+++ linux.18p8/drivers/net/Space.c	Fri Sep  1 13:48:23 2000
@@ -140,6 +140,7 @@
 /* FDDI adapters */
 extern int dfx_probe(struct device *dev);
 extern int apfddi_init(struct device *dev);
+extern int skfp_probe(struct device *dev);
 
 /* HIPPI boards */
 extern int rr_hippi_probe(struct device *);
@@ -583,6 +584,9 @@
 #endif
 #ifdef CONFIG_APFDDI
 	&& apfddi_init(dev)
+#endif
+#ifdef CONFIG_SKFP
+	&& skfp_probe(dev)
 #endif
 	&& 1 ) {
 	    return 1;	/* -ENODEV or -EAGAIN would be more accurate. */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/acenic.c linux.18p8/drivers/net/acenic.c
--- linux.vanilla/drivers/net/acenic.c	Sun Jun 11 21:44:14 2000
+++ linux.18p8/drivers/net/acenic.c	Mon Sep 11 17:05:04 2000
@@ -29,7 +29,12 @@
  *                                       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
+ *   Matt Domsch <Matt_Domsch@dell.com>: Detect Alteon 1000baseT cards
+ *   Chip Salzenberg <chip@valinux.com>: Fix race condition between tx
+ *                                       handler and close() cleanup.
+ *   Ken Aaker <kdaaker@rchland.vnet.ibm.com>: Correct check for whether
+ *                                       memory mapped IO is enabled to
+ *                                       make the driver work on RS/6000.
  */
 
 #include <linux/config.h>
@@ -83,8 +88,13 @@
 #define PCI_VENDOR_ID_NETGEAR		0x1385
 #define PCI_DEVICE_ID_NETGEAR_GA620	0x620a
 #endif
+#ifndef PCI_DEVICE_ID_NETGEAR_GA620T
+#define PCI_DEVICE_ID_NETGEAR_GA620T	0x630a
+#endif
+
 /*
- * They used the DEC vendor ID by mistake
+ * Farallon used the DEC vendor ID by mistake and they seem not
+ * to care - stinky!
  */
 #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX
 #define PCI_DEVICE_ID_FARALLON_PN9000SX	0x1a
@@ -124,7 +134,6 @@
 #endif
 
 #if (LINUX_VERSION_CODE < 0x02032a)
-typedef u32 dma_addr_t;
 
 static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
 					 dma_addr_t *dma_handle)
@@ -389,7 +398,7 @@
 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.44 05/11/2000  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
+  "acenic.c: v0.46 2000/09/05  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev = NULL;
@@ -429,7 +438,8 @@
 		    !((pdev->vendor == PCI_VENDOR_ID_3COM) &&
 		      (pdev->device == PCI_DEVICE_ID_3COM_3C985)) &&
 		    !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) &&
-		      (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620)) &&
+		      ((pdev->device == PCI_DEVICE_ID_NETGEAR_GA620) || 
+		       (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620T))) &&
 		/*
 		 * Farallon used the DEC vendor ID on their cards by
 		 * mistake for a while
@@ -480,7 +490,7 @@
 		pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
 
 		/* OpenFirmware on Mac's does not set this - DOH.. */ 
-		if (!ap->pci_command & PCI_COMMAND_MEMORY) {
+		if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
 			printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
 			       "access - was not enabled by BIOS/Firmware\n",
 			       dev->name);
@@ -597,7 +607,6 @@
 }
 
 
-#ifdef MODULE
 MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@cern.ch>");
 MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
 MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
@@ -606,7 +615,6 @@
 MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
-#endif
 
 
 void __exit ace_module_cleanup(void)
@@ -712,7 +720,7 @@
 	return status;
 }
 
-
+#ifdef MODULE
 #if (LINUX_VERSION_CODE < 0x02032a)
 int init_module(void)
 {
@@ -728,7 +736,7 @@
 module_init(ace_module_init);
 module_exit(ace_module_cleanup);
 #endif
-
+#endif
 
 static void ace_free_descriptors(struct net_device *dev)
 {
@@ -1010,7 +1018,7 @@
 	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",
+		       "(%i bytes) by BIOS/FW, correcting to %i\n",
 		       (cache << 2), SMP_CACHE_BYTES);
 		pci_write_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE,
 				      SMP_CACHE_BYTES >> 2);
@@ -1996,6 +2004,19 @@
 			struct sk_buff *skb;
 
 			skb = ap->skb->tx_skbuff[idx].skb;
+			/*
+			 * Race condition between the code cleaning
+			 * the tx queue in the interrupt handler and the
+			 * interface close,
+			 *
+			 * This is a kludge that really should be fixed 
+			 * by preventing the driver from generating a tx
+			 * interrupt when the packet has already been
+			 * removed from the tx queue.
+			 *
+			 * Nailed by Don Dugger and Chip Salzenberg of
+			 * VA Linux.
+			 */
 			if (skb) {
 				dma_addr_t mapping;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/acenic.h linux.18p8/drivers/net/acenic.h
--- linux.vanilla/drivers/net/acenic.h	Sun Jun 11 21:44:14 2000
+++ linux.18p8/drivers/net/acenic.h	Fri Sep  8 16:58:34 2000
@@ -609,7 +609,7 @@
 	struct timer_list	timer;
 
 	unsigned long		std_refill_busy
-				__attribute__ ((aligned (L1_CACHE_BYTES)));
+				__attribute__ ((aligned (SMP_CACHE_BYTES)));
 	unsigned long		mini_refill_busy, jumbo_refill_busy;
 	atomic_t		cur_rx_bufs,
 				cur_mini_bufs,
@@ -642,7 +642,7 @@
 	char			name[48];
 #ifdef INDEX_DEBUG
 	spinlock_t		debug_lock
-				__attribute__ ((aligned (L1_CACHE_BYTES)));;
+				__attribute__ ((aligned (SMP_CACHE_BYTES)));;
 	u32			last_tx, last_std_rx, last_mini_rx;
 #endif
 	struct net_device_stats stats;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/cosa.c linux.18p8/drivers/net/cosa.c
--- linux.vanilla/drivers/net/cosa.c	Sun Jun 11 21:44:14 2000
+++ linux.18p8/drivers/net/cosa.c	Fri Sep  1 22:09:03 2000
@@ -102,13 +102,6 @@
 #include "syncppp.h"
 #include "cosa.h"
 
-/* Linux version stuff */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(wait, current) \
-	struct wait_queue wait = { current, NULL }
-#endif
-
 /* Maximum length of the identification string. */
 #define COSA_MAX_ID_STRING	128
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/eepro100.c linux.18p8/drivers/net/eepro100.c
--- linux.vanilla/drivers/net/eepro100.c	Sat Sep  9 18:42:38 2000
+++ linux.18p8/drivers/net/eepro100.c	Tue Sep  5 22:15:08 2000
@@ -167,6 +167,9 @@
 #ifndef PCI_DEVICE_ID_INTEL_ID1030
 #define PCI_DEVICE_ID_INTEL_ID1030 0x1030
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_ID2449
+#define PCI_DEVICE_ID_INTEL_ID2449 0x2449
+#endif
 
 /* The total I/O port extent of the board.
    The registers beyond 0x18 only exist on the i82558. */
@@ -325,6 +328,10 @@
 	{ "Intel Corporation 82559 InBusiness 10/100",
 	  PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030,
 	  0 
+	},
+	{ "Intel PCI EtherExpress Pro100 82562EM",
+	  PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID2449,
+	  0
 	},
 	{0,}						/* 0 terminated list. */
 };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/hamradio/mkiss.c linux.18p8/drivers/net/hamradio/mkiss.c
--- linux.vanilla/drivers/net/hamradio/mkiss.c	Fri Apr 21 12:46:17 2000
+++ linux.18p8/drivers/net/hamradio/mkiss.c	Wed Sep 13 16:18:07 2000
@@ -802,7 +802,7 @@
 static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len)
 {
 	unsigned char *ptr = d;
-	unsigned char c;
+	unsigned char c=0;
 
 	*ptr++ = END;
 	while (len > 0) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ipddp.c linux.18p8/drivers/net/ipddp.c
--- linux.vanilla/drivers/net/ipddp.c	Fri Apr 21 12:46:17 2000
+++ linux.18p8/drivers/net/ipddp.c	Thu Aug 31 15:19:44 2000
@@ -242,7 +242,10 @@
         rt->next = NULL;
         rt->dev = atrtr_get_dev(&rt->at);
         if(rt->dev == NULL)
+        {
+        	kfree(rt);
                 return (-ENETUNREACH);
+        }
 
 	test = ipddp_find_route(rt);
 	if(test != NULL)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ne2.c linux.18p8/drivers/net/ne2.c
--- linux.vanilla/drivers/net/ne2.c	Fri Apr 21 12:46:19 2000
+++ linux.18p8/drivers/net/ne2.c	Mon Sep 11 17:58:02 2000
@@ -110,16 +110,16 @@
 #define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
 
 /* From the .ADF file: */
-static unsigned int addresses[7]=
+static unsigned int addresses[7] __initdata =
 		{0x1000, 0x2020, 0x8020, 0xa0a0, 0xb0b0, 0xc0c0, 0xc3d0};
-static int irqs[4] = {3, 4, 5, 9};
+static int irqs[4] __initdata = {3, 4, 5, 9};
 
 struct ne2_adapters_t {
 	unsigned int	id;
 	char		*name;
 };
 
-const struct ne2_adapters_t ne2_adapters[] = {
+static struct ne2_adapters_t ne2_adapters[] __initdata = {
 	{ 0x6354, "Arco Ethernet Adapter AE/2" },
 	{ 0x70DE, "Compex ENET-16 MC/P" },
 	{ 0x7154, "Novell Ethernet Adapter NE/2" },
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/rtl8139.c linux.18p8/drivers/net/rtl8139.c
--- linux.vanilla/drivers/net/rtl8139.c	Sat Sep  9 18:42:40 2000
+++ linux.18p8/drivers/net/rtl8139.c	Tue Sep 12 12:49:40 2000
@@ -1235,8 +1235,9 @@
 			/* Malloc up new buffer, compatible with net-2e. */
 			/* Omit the four octet CRC from the length. */
 			struct sk_buff *skb;
+			int pkt_size = rx_size - 4;
 
-			skb = dev_alloc_skb(rx_size + 2);
+			skb = dev_alloc_skb(pkt_size + 2);
 			if (skb == NULL) {
 				printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n",
 					   dev->name);
@@ -1247,12 +1248,12 @@
 			}
 			skb->dev = dev;
 			skb_reserve(skb, 2);	/* 16 byte align the IP fields. */
-			if (ring_offset+rx_size+4 > RX_BUF_LEN) {
+			if (ring_offset+rx_size > RX_BUF_LEN) {
 				int semi_count = RX_BUF_LEN - ring_offset - 4;
 				memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4],
 					   semi_count);
-				memcpy(skb_put(skb, rx_size-semi_count), rx_ring,
-					   rx_size-semi_count);
+				memcpy(skb_put(skb, pkt_size-semi_count), rx_ring,
+					   pkt_size-semi_count);
 				if (rtl8129_debug > 4) {
 					int i;
 					printk(KERN_DEBUG"%s:  Frame wrap @%d",
@@ -1265,17 +1266,17 @@
 			} else {
 #if 1  /* USE_IP_COPYSUM */
 				eth_copy_and_sum(skb, &rx_ring[ring_offset + 4],
-						 rx_size - 4, 0);
-				skb_put(skb, rx_size - 4);
+						 pkt_size, 0);
+				skb_put(skb, pkt_size);
 #else
-				memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4],
-					   rx_size);
+				memcpy(skb_put(skb, pkt_size), &rx_ring[ring_offset + 4],
+					   pkt_size);
 #endif
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 #if LINUX_VERSION_CODE > 0x20119
-			tp->stats.rx_bytes += rx_size;
+			tp->stats.rx_bytes += pkt_size;
 #endif
 			tp->stats.rx_packets++;
 		}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sbni.c linux.18p8/drivers/net/sbni.c
--- linux.vanilla/drivers/net/sbni.c	Fri Apr 21 12:46:19 2000
+++ linux.18p8/drivers/net/sbni.c	Sun Sep  3 13:54:34 2000
@@ -342,7 +342,7 @@
 	if(base_addr > 0x1ff)	/* Check a single specified location. */
 		return sbni_probe1(dev, base_addr);
 	else if(base_addr != 0)	/* Don't probe at all. */
-		return ENXIO;
+		return -ENXIO;
 	for(i = 0; (base_addr = netcard_portlist[i]); i++)
 	{ 
 		if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1)
@@ -353,7 +353,7 @@
 				return 0;
 		}
 	}
-	return ENODEV;
+	return -ENODEV;
 }
 
 #endif /* have devlist*/
@@ -416,7 +416,7 @@
 	}
 
 	if(bad_card)
-		return ENODEV;
+		return -ENODEV;
 	else
 		outb(0, ioaddr + CSR0); 
 	if(dev->irq < 2)
@@ -429,8 +429,8 @@
 
 		if(autoirq == 0)
 		{
-			printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr);
-			return EAGAIN;
+			printk(KERN_ERR "sbni probe at %#x failed to detect IRQ line\n", ioaddr);
+			return -EAGAIN;
 		}
 	}
 	/* clear FIFO buffer */
@@ -444,7 +444,7 @@
 		if (irqval) 
 		{
 			printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
-			return EAGAIN;
+			return -EAGAIN;
 		}
 	}
      
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sdla.c linux.18p8/drivers/net/sdla.c
--- linux.vanilla/drivers/net/sdla.c	Fri Apr 21 12:46:19 2000
+++ linux.18p8/drivers/net/sdla.c	Thu Aug 31 15:20:28 2000
@@ -1218,7 +1218,10 @@
 			return(-ENOMEM);
 		sdla_read(dev, mem.addr, temp, mem.len);
 		if(copy_to_user(mem.data, temp, mem.len))
+		{
+			kfree(temp);
 			return -EFAULT;
+		}
 		kfree(temp);
 	}
 	else
@@ -1227,7 +1230,10 @@
 		if (!temp)
 			return(-ENOMEM);
 		if(copy_from_user(temp, mem.data, mem.len))
+		{
+			kfree(temp);
 			return -EFAULT;
+		}
 		sdla_write(dev, mem.addr, temp, mem.len);
 		kfree(temp);
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sis900.c linux.18p8/drivers/net/sis900.c
--- linux.vanilla/drivers/net/sis900.c	Fri Apr 21 12:46:19 2000
+++ linux.18p8/drivers/net/sis900.c	Thu Aug 31 14:30:01 2000
@@ -1,8 +1,8 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
    Copyright 1999 Silicon Integrated System Corporation 
-   Revision:	1.05	Aug 7 1999
-   
-   Modified from the driver which is originally written by Donald Becker. 
+   Revision:	1.06.05	Aug 24 2000
+
+   Modified from the driver which is originally written by Donald Becker.
    
    This software may be used and distributed according to the terms
    of the GNU Public License (GPL), incorporated herein by reference.
@@ -17,11 +17,13 @@
    SiS 7014 Single Chip 100BASE-TX/10BASE-T Physical Layer Solution,
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
-   
-   Rev 1.06.02 Nov. 23 1999 Ollie Lho 
+
+   Rev 1.06.05 Aug. 22 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E equalier workaroung rule
+   Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release
+   Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed
    Rev 1.06.01 Nov. 16 1999 Ollie Lho CRC calculation provide by Joseph Zbiciak (im14u2c@primenet.com)
    Rev 1.06 Nov. 4 1999 Ollie Lho (ollie@sis.com.tw) Second release
-   Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx  
+   Rev 1.05.05 Oct. 29 1999 Ollie Lho (ollie@sis.com.tw) Single buffer Tx/Rx
    Chin-Shan Li (lcs@sis.com.tw) Added AMD Am79c901 HomePNA PHY support
    Rev 1.05 Aug. 7 1999 Jim Huang (cmhuang@sis.com.tw) Initial release
 */
@@ -41,7 +43,7 @@
 
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <asm/processor.h>      /* Processor type for cache alignment. */
+#include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <linux/delay.h>
@@ -49,22 +51,22 @@
 #include "sis900.h"
 
 static const char *version =
-"sis900.c: v1.06.03  12/23/99\n";
+"sis900.c: v1.06.05  08/24/00\n";
 
 static int max_interrupt_work = 20;
+static int multicast_filter_limit = 128;
+
 #define sis900_debug debug
 static int sis900_debug = 0;
 
-static int multicast_filter_limit = 128;
-
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (4*HZ)
 
 struct mac_chip_info {
-        const char *name;
-        u16 	vendor_id, device_id, flags;
-        int 	io_size;
-        struct device *(*probe) (struct mac_chip_info *mac, struct pci_dev * pci_dev, 
+	const char *name;
+	u16	vendor_id, device_id, flags;
+	int	io_size;
+	struct device *(*probe) (struct mac_chip_info *mac, struct pci_dev * pci_dev,
 				 struct device * net_dev);
 };
 static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev,
@@ -75,7 +77,7 @@
 	  PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
 	{ "SiS 7016 PCI Fast Ethernet",PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7016,
 	  PCI_COMMAND_IO|PCI_COMMAND_MASTER, SIS900_TOTAL_SIZE, sis900_mac_probe},
-	{0,},                                          /* 0 terminated list. */
+	{0,},					       /* 0 terminated list. */
 };
 
 static void sis900_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex);
@@ -102,37 +104,38 @@
 };
 
 typedef struct _BufferDesc {
-        u32     link;
-        u32     cmdsts;
-        u32     bufptr;
+	u32	link;
+	u32	cmdsts;
+	u32	bufptr;
 } BufferDesc;
 
 struct sis900_private {
-        struct device *next_module;
-        struct net_device_stats stats;
+	struct device *next_module;
+	struct net_device_stats stats;
 	struct pci_dev * pci_dev;
 
 	struct mac_chip_info * mac;
 	struct mii_phy * mii;
 	unsigned int cur_phy;
 
-        struct timer_list timer;        		/* Link status detection timer. */
-        unsigned int cur_rx, dirty_rx;		
-        unsigned int cur_tx, dirty_tx;
+	struct timer_list timer;		/* Link status detection timer. */
+
+	unsigned int cur_rx, dirty_rx;	/* producer/comsumer pointers for Tx/Rx ring */
+	unsigned int cur_tx, dirty_tx;
 
-        /* The saved address of a sent/receive-in-place packet buffer */
-        struct sk_buff *tx_skbuff[NUM_TX_DESC];
+	/* The saved address of a sent/receive-in-place packet buffer */
+	struct sk_buff *tx_skbuff[NUM_TX_DESC];
 	struct sk_buff *rx_skbuff[NUM_RX_DESC];
-	BufferDesc tx_ring[NUM_TX_DESC];	
-        BufferDesc rx_ring[NUM_RX_DESC];
-        unsigned int tx_full;			/* The Tx queue is full.    */
+	BufferDesc tx_ring[NUM_TX_DESC];
+	BufferDesc rx_ring[NUM_RX_DESC];
 
-        int LinkOn;
+	unsigned int tx_full;		/* The Tx queue is full.    */
+	int LinkOn;
 };
 
 #ifdef MODULE
 #if LINUX_VERSION_CODE > 0x20115
-MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>");
+MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>, Ollie Lho <ollie@sis.com.tw>");
 MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver");
 MODULE_PARM(multicast_filter_limit, "i");
 MODULE_PARM(max_interrupt_work, "i");
@@ -161,6 +164,7 @@
 static u16 sis900_compute_hashtable_index(u8 *addr);
 static void set_rx_mode(struct device *net_dev);
 static void sis900_reset(struct device *net_dev);
+static void sis630e_set_eq(struct device *net_dev);
 
 /* A list of all installed SiS900 devices, for removing the driver module. */
 static struct device *root_sis900_dev = NULL;
@@ -170,10 +174,10 @@
 {
 	int found = 0;
 	struct pci_dev * pci_dev = NULL;
-		
+
 	if (!pci_present())
 		return -ENODEV;
-		
+
 	while ((pci_dev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_dev)) != NULL) {
 		/* pci_dev contains all ethernet devices */
 		u32 pci_io_base;
@@ -185,23 +189,23 @@
 			    pci_dev->device == mac->device_id)
 				break;
 		}
-		
+
 		if (mac->vendor_id == 0)
 			/* pci_dev does not match any of our cards */
 			continue;
-		
+
 		/* now, pci_dev should be either 900 or 7016 */
 		pci_io_base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
-		if ((mac->flags & PCI_COMMAND_IO ) && 
+		if ((mac->flags & PCI_COMMAND_IO ) &&
 		    check_region(pci_io_base, mac->io_size))
 			continue;
-		
+
 		/* setup various bits in PCI command register */
 		pci_set_master(pci_dev);
 
 		/* do the real low level jobs */
 		net_dev = mac->probe(mac, pci_dev, net_dev);
-		
+
 		if (net_dev != NULL) {
 			found++;
 		}
@@ -210,15 +214,83 @@
 	return found ? 0 : -ENODEV;
 }
 
-static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev, 
+/* older SiS900 and friends, use EEPROM to store MAC address */
+static int sis900_get_mac_addr(struct pci_dev * pci_dev, struct device *net_dev)
+{
+	long ioaddr = pci_dev->base_address[0] & ~3;
+	u16 signature;
+	int i;
+
+	/* check to see if we have sane EEPROM */
+	signature = (u16) read_eeprom(ioaddr, EEPROMSignature);    
+	if (signature == 0xffff || signature == 0x0000) {
+		printk (KERN_INFO "%s: Error EERPOM read %x\n", 
+			net_dev->name, signature);
+		return 0;
+	}
+
+	/* get MAC address from EEPROM */
+	for (i = 0; i < 3; i++)
+	        ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
+
+	return 1;
+}
+
+/* SiS630E model, use APC CMOS RAM to store MAC address */
+static int sis630e_get_mac_addr(struct pci_dev * pci_dev, struct device *net_dev)
+{
+	struct pci_dev *isa_bridge = NULL;
+	u8 reg;
+	int i;
+
+	if ((isa_bridge = pci_find_device(0x1039, 0x0008, isa_bridge)) == NULL) {
+		printk("%s: Can not find ISA bridge\n", net_dev->name);
+		return 0;
+	}
+	pci_read_config_byte(isa_bridge, 0x48, &reg);
+	pci_write_config_byte(isa_bridge, 0x48, reg | 0x40);
+
+	for (i = 0; i < 6; i++) {
+		outb(0x09 + i, 0x70);
+		((u8 *)(net_dev->dev_addr))[i] = inb(0x71); 
+	}
+	pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40);
+
+	return 1;
+}
+
+/* SiS630E A1, The Mac address is hardcoded in the RFCR register so it is actually not necessary to
+   probe the MAC address */
+static int sis630ea1_get_mac_addr(struct pci_dev * pci_dev, struct device *net_dev)
+{
+	long ioaddr = pci_dev->base_address[0] & ~3;
+	u32 reg;
+	int i;
+
+	/* reload MAC address */
+	reg = inl(ioaddr + cr);
+	outl(reg | RELOAD, ioaddr + cr);
+
+	reg = inl(ioaddr + cr);
+	outl(reg & ~RELOAD, ioaddr + cr);
+
+	for (i = 0; i < 3; i++) {
+		outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
+		((u16 *)(net_dev->dev_addr))[i] = inl(ioaddr + rfdr);
+	}
+
+	return 1;
+}
+
+static struct device * sis900_mac_probe (struct mac_chip_info * mac, struct pci_dev * pci_dev,
 					 struct device * net_dev)
 {
 	struct sis900_private *sis_priv;
 	long ioaddr = pci_dev->base_address[0] & ~3;
 	int irq = pci_dev->irq;
 	static int did_version = 0;
-	u16 signature;
-	int i;
+	u8 revision;
+	int i, ret = 0;
 
 	if (did_version++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -226,21 +298,24 @@
 	if ((net_dev = init_etherdev(net_dev, 0)) == NULL)
 		return NULL;
 
-	/* check to see if we have sane EEPROM */
-	signature = (u16) read_eeprom(ioaddr, EEPROMSignature);    
-	if (signature == 0xffff || signature == 0x0000) {
-		printk (KERN_INFO "%s: Error EEPROM read: %x\n",
-			net_dev->name, signature);
+	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
+	if (revision == SIS630E_REV)
+		ret = sis630e_get_mac_addr(pci_dev, net_dev);
+	else if (revision == SIS630EA1_REV) {
+		ret = sis630e_get_mac_addr(pci_dev, net_dev);
+		printk(KERN_INFO "using 630ea1\n");
+	}
+	else
+		ret = sis900_get_mac_addr(pci_dev, net_dev);
+
+	if (ret == 0) {
 		unregister_netdevice(net_dev);
 		return NULL;
 	}
 
+	/* print some information about our NIC */
 	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, mac->name,
 	       ioaddr, irq);
-
-	/* get MAC address from EEPROM */
-	for (i = 0; i < 3; i++)
-		((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
 	for (i = 0; i < 5; i++)
 		printk("%2.2x:", (u8)net_dev->dev_addr[i]);
 	printk("%2.2x.\n", net_dev->dev_addr[i]);
@@ -286,247 +361,268 @@
 {
 	struct sis900_private * sis_priv = (struct sis900_private *)net_dev->priv;
 	int phy_addr;
-	
+	u8 revision;
+
 	sis_priv->mii = NULL;
-	
+
 	/* search for total of 32 possible mii phy addresses */
 	for (phy_addr = 0; phy_addr < 32; phy_addr++) {
 		u16 mii_status;
 		u16 phy_id0, phy_id1;
 		int i;
-		
+
 		mii_status = mdio_read(net_dev, phy_addr, MII_STATUS);
 		if (mii_status == 0xffff || mii_status == 0x0000)
 			/* the mii is not accessable, try next one */
 			continue;
-		
+
 		phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0);
 		phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);
-		
+
 		/* search our mii table for the current mii */ 
 		for (i = 0; mii_chip_table[i].phy_id1; i++)
 			if (phy_id0 == mii_chip_table[i].phy_id0) {
 				struct mii_phy * mii_phy;
-				
-				printk(KERN_INFO 
+
+				printk(KERN_INFO
 				       "%s: %s transceiver found at address %d.\n",
-				       net_dev->name, mii_chip_table[i].name, 
+				       net_dev->name, mii_chip_table[i].name,
 				       phy_addr);;
 				if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) {
 					mii_phy->chip_info = mii_chip_table+i;
 					mii_phy->phy_addr = phy_addr;
-					mii_phy->status = mdio_read(net_dev, phy_addr, 
+					mii_phy->status = mdio_read(net_dev, phy_addr,
 								    MII_STATUS);
 					mii_phy->next = sis_priv->mii;
 					sis_priv->mii = mii_phy;
 				}
-				/* the current mii is on our mii_info_table, 
+				/* the current mii is on our mii_info_table,
 				   try next address */
 				break;
 			}
 	}
-	
+
 	if (sis_priv->mii == NULL) {
-		printk(KERN_INFO "%s: No MII transceivers found!\n", 
+		printk(KERN_INFO "%s: No MII transceivers found!\n",
 		       net_dev->name);
 		return 0;
 	}
 
-	/* arbitrary choose that last PHY and current PHY */
+	/* arbitrary choose that last PHY as current PHY */
 	sis_priv->cur_phy = sis_priv->mii->phy_addr;
 	printk(KERN_INFO "%s: Using %s as default\n", net_dev->name,
 	       sis_priv->mii->chip_info->name);
 
-	if (sis_priv->mii->status & MII_STAT_LINK) 
+	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
+	if (revision == SIS630E_REV) {
+		/* SiS 630E has some bugs on default value of PHY registers */
+		mdio_write(net_dev, sis_priv->cur_phy, MII_ANADV, 0x05e1);
+		mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22);
+		mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG2, 0xff00);
+		mdio_write(net_dev, sis_priv->cur_phy, MII_MASK, 0xffc0);
+		mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000);	
+	}
+
+	if (sis_priv->mii->status & MII_STAT_LINK)
 		sis_priv->LinkOn = TRUE;
 	else
 		sis_priv->LinkOn = FALSE;
-
+	
 	return 1;
 }
 
 /* Delay between EEPROM clock transitions. */
-#define eeprom_delay()  inl(ee_addr)
+#define eeprom_delay()	inl(ee_addr)
 
-/* Read Serial EEPROM through EEPROM Access Register, Note that location is 
+/* Read Serial EEPROM through EEPROM Access Register, Note that location is
    in word (16 bits) unit */
 static u16 read_eeprom(long ioaddr, int location)
 {
 	int i;
-        u16 retval = 0;
-        long ee_addr = ioaddr + mear;
-        u32 read_cmd = location | EEread;
-
-        outl(0, ee_addr);
-        eeprom_delay();
-        outl(EECLK, ee_addr);
-        eeprom_delay();
-
-        /* Shift the read command (9) bits out. */
-        for (i = 8; i >= 0; i--) {
-                u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
-                outl(dataval, ee_addr);
-                eeprom_delay();
-                outl(dataval | EECLK, ee_addr);
-                eeprom_delay();
-        }
-        outb(EECS, ee_addr);
-        eeprom_delay();
+	u16 retval = 0;
+	long ee_addr = ioaddr + mear;
+	u32 read_cmd = location | EEread;
+
+	outl(0, ee_addr);
+	eeprom_delay();
+	outl(EECLK, ee_addr);
+	eeprom_delay();
+
+	/* Shift the read command (9) bits out. */
+	for (i = 8; i >= 0; i--) {
+		u32 dataval = (read_cmd & (1 << i)) ? EEDI | EECS : EECS;
+		outl(dataval, ee_addr);
+		eeprom_delay();
+		outl(dataval | EECLK, ee_addr);
+		eeprom_delay();
+	}
+	outb(EECS, ee_addr);
+	eeprom_delay();
 
 	/* read the 16-bits data in */
-        for (i = 16; i > 0; i--) {
-                outl(EECS, ee_addr);
-                eeprom_delay();
-                outl(EECS | EECLK, ee_addr);
-                eeprom_delay();
-                retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
-                eeprom_delay();
-        }
-		
-        /* Terminate the EEPROM access. */
-        outl(0, ee_addr);
-        eeprom_delay();
-        outl(EECLK, ee_addr);
+	for (i = 16; i > 0; i--) {
+		outl(EECS, ee_addr);
+		eeprom_delay();
+		outl(EECS | EECLK, ee_addr);
+		eeprom_delay();
+		retval = (retval << 1) | ((inl(ee_addr) & EEDO) ? 1 : 0);
+		eeprom_delay();
+	}
+
+	/* Terminate the EEPROM access. */
+	outl(0, ee_addr);
+	eeprom_delay();
+	outl(EECLK, ee_addr);
 
-        return (retval);
+	return (retval);
 }
 
 /* Read and write the MII management registers using software-generated
    serial MDIO protocol. Note that the command bits and data bits are
    send out seperately */
-#define mdio_delay()    inl(mdio_addr)
+#define mdio_delay()	inl(mdio_addr)
 
 static void mdio_idle(long mdio_addr)
 {
-        outl(MDIO | MDDIR, mdio_addr);
-        mdio_delay();
-        outl(MDIO | MDDIR | MDC, mdio_addr);
+	outl(MDIO | MDDIR, mdio_addr);
+	mdio_delay();
+	outl(MDIO | MDDIR | MDC, mdio_addr);
 }
 
 /* Syncronize the MII management interface by shifting 32 one bits out. */
 static void mdio_reset(long mdio_addr)
 {
-        int i;
+	int i;
 
-        for (i = 31; i >= 0; i--) {
-                outl(MDDIR | MDIO, mdio_addr);
-                mdio_delay();
-                outl(MDDIR | MDIO | MDC, mdio_addr);
-                mdio_delay();
-        }
-        return;
+	for (i = 31; i >= 0; i--) {
+		outl(MDDIR | MDIO, mdio_addr);
+		mdio_delay();
+		outl(MDDIR | MDIO | MDC, mdio_addr);
+		mdio_delay();
+	}
+	return;
 }
 
 static u16 mdio_read(struct device *net_dev, int phy_id, int location)
 {
-        long mdio_addr = net_dev->base_addr + mear;
-        int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
-        u16 retval = 0;
-        int i;
-
-        mdio_reset(mdio_addr);
-        mdio_idle(mdio_addr);
-
-        for (i = 15; i >= 0; i--) {
-                int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
-                outl(dataval, mdio_addr);
+	long mdio_addr = net_dev->base_addr + mear;
+	int mii_cmd = MIIread|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
+	u16 retval = 0;
+	int i;
+
+	mdio_reset(mdio_addr);
+	mdio_idle(mdio_addr);
+
+	for (i = 15; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
+		outl(dataval, mdio_addr);
 		mdio_delay();
-                outl(dataval | MDC, mdio_addr);
+		outl(dataval | MDC, mdio_addr);
 		mdio_delay();
-        }
+	}
 
-        /* Read the 16 data bits. */
-        for (i = 16; i > 0; i--) {
-                outl(0, mdio_addr);
-                mdio_delay();
-                retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
-                outl(MDC, mdio_addr);
-                mdio_delay();
-        }
-        return retval;
+	/* Read the 16 data bits. */
+	for (i = 16; i > 0; i--) {
+		outl(0, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inl(mdio_addr) & MDIO) ? 1 : 0);
+		outl(MDC, mdio_addr);
+		mdio_delay();
+	}
+	outl(0x00, mdio_addr);
+
+	return retval;
 }
 
 static void mdio_write(struct device *net_dev, int phy_id, int location, int value)
 {
-        long mdio_addr = net_dev->base_addr + mear;
-        int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
-        int i;
-
-        mdio_reset(mdio_addr);
-        mdio_idle(mdio_addr);
-
-        /* Shift the command bits out. */
-        for (i = 15; i >= 0; i--) {
-                int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
-                outb(dataval, mdio_addr);
-                mdio_delay();
-                outb(dataval | MDC, mdio_addr);
-                mdio_delay();
-        }
-        mdio_delay();
+	long mdio_addr = net_dev->base_addr + mear;
+	int mii_cmd = MIIwrite|(phy_id<<MIIpmdShift)|(location<<MIIregShift);
+	int i;
+
+	mdio_reset(mdio_addr);
+	mdio_idle(mdio_addr);
+
+	/* Shift the command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDDIR | MDIO : MDDIR;
+		outb(dataval, mdio_addr);
+		mdio_delay();
+		outb(dataval | MDC, mdio_addr);
+		mdio_delay();
+	}
+	mdio_delay();
 
 	/* Shift the value bits out. */
 	for (i = 15; i >= 0; i--) {
 		int dataval = (value & (1 << i)) ? MDDIR | MDIO : MDDIR;
-	        outl(dataval, mdio_addr);
-	        mdio_delay();
-	        outl(dataval | MDC, mdio_addr);
-	       	mdio_delay();
+		outl(dataval, mdio_addr);
+		mdio_delay();
+		outl(dataval | MDC, mdio_addr);
+		mdio_delay();
 	}
 	mdio_delay();
-	
-        /* Clear out extra bits. */
-        for (i = 2; i > 0; i--) {
-                outb(0, mdio_addr);
-                mdio_delay();
-                outb(MDC, mdio_addr);
-                mdio_delay();
-        }
-        return;
+
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		outb(0, mdio_addr);
+		mdio_delay();
+		outb(MDC, mdio_addr);
+		mdio_delay();
+	}
+	outl(0x00, mdio_addr);
+
+	return;
 }
 
 static int
 sis900_open(struct device *net_dev)
 {
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
-        long ioaddr = net_dev->base_addr;
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	long ioaddr = net_dev->base_addr;
+	u8 revision;
 
-        /* Soft reset the chip. */
+	/* Soft reset the chip. */
 	sis900_reset(net_dev);
+	
+	/* Equalizer workaroung Rule */
+	pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
+	if (revision == SIS630E_REV || revision == SIS630EA1_REV)
+		sis630e_set_eq(net_dev);
+	
+	if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) {
+		return -EAGAIN;
+	}
 
-        if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) {
-                return -EAGAIN;
-        }
-
-        MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 
 	sis900_init_rxfilter(net_dev);
 
 	sis900_init_tx_ring(net_dev);
 	sis900_init_rx_ring(net_dev);
 
-        set_rx_mode(net_dev);
+	set_rx_mode(net_dev);
 
-        net_dev->tbusy = 0;
-        net_dev->interrupt = 0;
-        net_dev->start = 1;
+	net_dev->tbusy = 0;
+	net_dev->interrupt = 0;
+	net_dev->start = 1;
 
-        /* Enable all known interrupts by setting the interrupt mask. */
+	/* Enable all known interrupts by setting the interrupt mask. */
 	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
-        outl(RxENA, ioaddr + cr);
-        outl(IE, ioaddr + ier);
+	outl(RxENA, ioaddr + cr);
+	outl(IE, ioaddr + ier);
 
 	sis900_check_mode(net_dev, sis_priv->mii);
 
-        /* Set the timer to switch to check for link beat and perhaps switch
-           to an alternate media type. */
-        init_timer(&sis_priv->timer);
-        sis_priv->timer.expires = jiffies + HZ;
-        sis_priv->timer.data = (unsigned long)net_dev;
-        sis_priv->timer.function = &sis900_timer;
-        add_timer(&sis_priv->timer);
+	/* Set the timer to switch to check for link beat and perhaps switch
+	   to an alternate media type. */
+	init_timer(&sis_priv->timer);
+	sis_priv->timer.expires = jiffies + HZ;
+	sis_priv->timer.data = (unsigned long)net_dev;
+	sis_priv->timer.function = &sis900_timer;
+	add_timer(&sis_priv->timer);
 
-        return 0;
+	return 0;
 }
 
 /* set receive filter address to our MAC address */
@@ -536,7 +632,7 @@
 	long ioaddr = net_dev->base_addr;
 	u32 rfcrSave;
 	u32 i;
-	
+
 	rfcrSave = inl(rfcr + ioaddr);
 
 	/* disable packet filtering before setting filter */
@@ -564,38 +660,38 @@
 static void
 sis900_init_tx_ring(struct device *net_dev)
 {
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
-        long ioaddr = net_dev->base_addr; 
-        int i;
-	
-        sis_priv->tx_full = 0;
-        sis_priv->dirty_tx = sis_priv->cur_tx = 0;
-	
-        for (i = 0; i < NUM_TX_DESC; i++) {
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	long ioaddr = net_dev->base_addr;
+	int i;
+
+	sis_priv->tx_full = 0;
+	sis_priv->dirty_tx = sis_priv->cur_tx = 0;
+
+	for (i = 0; i < NUM_TX_DESC; i++) {
 		sis_priv->tx_skbuff[i] = NULL;
 
 		sis_priv->tx_ring[i].link = (u32) virt_to_bus(&sis_priv->tx_ring[i+1]);
-                sis_priv->tx_ring[i].cmdsts = 0;
+		sis_priv->tx_ring[i].cmdsts = 0;
 		sis_priv->tx_ring[i].bufptr = 0;
-        }
+	}
 	sis_priv->tx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->tx_ring[0]);
 
 	/* load Transmit Descriptor Register */
-        outl(virt_to_bus(&sis_priv->tx_ring[0]), ioaddr + txdp); 
+	outl(virt_to_bus(&sis_priv->tx_ring[0]), ioaddr + txdp);
 	if (sis900_debug > 2)
-                printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n", 
+		printk(KERN_INFO "%s: TX descriptor register loaded with: %8.8x\n",
 		       net_dev->name, inl(ioaddr + txdp));
 }
 
-/* Initialize the Rx descriptor ring, pre-allocate recevie buffers */ 
+/* Initialize the Rx descriptor ring, pre-allocate recevie buffers */
 static void 
-sis900_init_rx_ring(struct device *net_dev) 
-{ 
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; 
-        long ioaddr = net_dev->base_addr; 
-        int i;
- 
-        sis_priv->cur_rx = 0; 
+sis900_init_rx_ring(struct device *net_dev)
+{
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	long ioaddr = net_dev->base_addr;
+	int i;
+
+	sis_priv->cur_rx = 0;
 	sis_priv->dirty_rx = 0;
 
 	/* init RX descriptor */
@@ -608,14 +704,14 @@
 	}
 	sis_priv->rx_ring[i-1].link = (u32) virt_to_bus(&sis_priv->rx_ring[0]);
 
-        /* allocate sock buffers */
+	/* allocate sock buffers */
 	for (i = 0; i < NUM_RX_DESC; i++) {
 		struct sk_buff *skb;
 
 		if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
 			/* not enough memory for skbuff, this makes a "hole"
-			   on the buffer ring, it is not clear how the 
-			   hardware will react to this kind of degenerated 
+			   on the buffer ring, it is not clear how the
+			   hardware will react to this kind of degenerated
 			   buffer */
 			break;
 		}
@@ -627,31 +723,97 @@
 	sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC);
 
 	/* load Receive Descriptor Register */
-        outl(virt_to_bus(&sis_priv->rx_ring[0]), ioaddr + rxdp);
+	outl(virt_to_bus(&sis_priv->rx_ring[0]), ioaddr + rxdp);
 	if (sis900_debug > 2)
-                printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", 
+		printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n",
 		       net_dev->name, inl(ioaddr + rxdp));
 }
+
+/* 630E equalizer workaroung rule(Cyrus Huang 08/15)
+   PHY register 14h(Test)
+   Bit 14: 0 -- Automatically dectect (default)
+           1 -- Manually set Equalizer filter
+   Bit 13: 0 -- (Default)
+           1 -- Speed up convergence of equalizer setting
+   Bit 9 : 0 -- (Default)
+           1 -- Disable Baseline Wander
+   Bit 3~7   -- Equalizer filter setting
+   
+   Link ON: Set Bit 9, 13 to 1, Bit 14 to 0
+            Then calculate equalizer value
+            Then set equalizer value, and set Bit 14 to 1, Bit 9 to 0
+   Link Off:Set Bit 13 to 1, Bit 14 to 0
+   
+   Calculate Equalizer value:
+    When Link is ON and Bit 14 is 0, SIS900PHY will auto-dectect proper equalizer value.
+    When the equalizer is stable, this value is not a fixed value. It will be within
+    a small range(eg. 7~9). Then we get a minimum and a maximum value(eg. min=7, max=9)
+    0 <= max <= 4  --> set equalizer to max
+    5 <= max <= 14 --> set equalizer to max+1 or
+                       set equalizer to max+2 if max == min
+    max >= 15      --> set equalizer to max+5 or
+                       set equalizer to max+6 if max == min
+*/
+static void sis630e_set_eq(struct device *net_dev)
+{
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	u16 reg14h, eq_value, max_value=0, min_value=0;
+	int i, maxcount=10;
+
+	if (sis_priv->LinkOn == TRUE) {
+		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
+		mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (0x2200 | reg14h) & 0xBFFF);
+		for (i=0; i < maxcount; i++) {
+			eq_value=(0x00F8 & mdio_read(net_dev, sis_priv->cur_phy, MII_RESV)) >> 3;
+			max_value=(eq_value > max_value) ? eq_value : max_value;
+			min_value=(eq_value < min_value) ? eq_value : min_value;
+		} 
+		if (max_value < 5)
+			eq_value=max_value;
+		else if (max_value >= 5 && max_value < 15)
+			eq_value=(max_value == min_value) ? max_value+2 : max_value+1;
+		else if (max_value >= 15)
+			eq_value=(max_value == min_value) ? max_value+6 : max_value+5;
+		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
+		reg14h=(reg14h & 0xFF07) | ((eq_value << 3) & 0x00F8);
+		reg14h=(reg14h | 0x6000) & 0xFDFF;
+		mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, reg14h);
+	}
+	else {
+		reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
+		mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF);
+	}
+	return;
+}
+
 /* on each timer ticks we check two things, Link Status (ON/OFF) and 
    Link Mode (10/100/Full/Half)
  */
 static void sis900_timer(unsigned long data)
 {
-        struct device *net_dev = (struct device *)data;
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	struct device *net_dev = (struct device *)data;
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
 	struct mii_phy *mii_phy = sis_priv->mii;
-        static int next_tick = 5*HZ;
-        u16 status;
+	static int next_tick = 5*HZ;
+	u16 status;
+	u8  revision;
 
 	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
+	status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
 
 	/* current mii phy is failed to link, try another one */
-	while (!(status & MII_STAT_LINK)) {		
-		if (mii_phy->next == NULL) { 
+	while (!(status & MII_STAT_LINK)) {
+		if (mii_phy->next == NULL) {
 			if (sis_priv->LinkOn) {
 				/* link stat change from ON to OFF */
 				next_tick = HZ;
 				sis_priv->LinkOn = FALSE;
+				
+				/* Equalizer workaroung Rule */
+				pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
+				if (revision == SIS630E_REV || revision == SIS630EA1_REV)
+					sis630e_set_eq(net_dev);
+
 				printk(KERN_INFO "%s: Media Link Off\n",
 				       net_dev->name);
 			}
@@ -667,19 +829,28 @@
 		/* link stat change forn OFF to ON, read and report link mode */
 		sis_priv->LinkOn = TRUE;
 		next_tick = 5*HZ;
+		
+		/* Equalizer workaroung Rule */
+		pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision);
+		if (revision == SIS630E_REV || revision == SIS630EA1_REV)
+			sis630e_set_eq(net_dev);
+		
 		/* change what cur_phy means */
 		if (mii_phy->phy_addr != sis_priv->cur_phy) {
-			printk(KERN_INFO "%s: Changing transceiver to %s\n", net_dev->name,
-			       mii_phy->chip_info->name);
+			printk(KERN_INFO "%s: Changing transceiver to %s\n",
+			       net_dev->name, mii_phy->chip_info->name);
+			/* disable previous PHY */
 			status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
-			mdio_write(net_dev, sis_priv->cur_phy, 
+			mdio_write(net_dev, sis_priv->cur_phy,
 				   MII_CONTROL, status | MII_CNTL_ISOLATE);
+			/* enable next PHY */
 			status = mdio_read(net_dev, mii_phy->phy_addr, MII_CONTROL);
-			mdio_write(net_dev, mii_phy->phy_addr, 
+			mdio_write(net_dev, mii_phy->phy_addr,
 				   MII_CONTROL, status & ~MII_CNTL_ISOLATE);
 			sis_priv->cur_phy = mii_phy->phy_addr;
 		}
 		sis900_check_mode(net_dev, mii_phy);
+
 	}
 
 	sis_priv->timer.expires = jiffies + next_tick;
@@ -688,7 +859,7 @@
 static void sis900_check_mode (struct device *net_dev, struct mii_phy *mii_phy)
 {
 	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
-        long ioaddr = net_dev->base_addr;
+	long ioaddr = net_dev->base_addr;
 	int speed, duplex;
 	u32 tx_flags = 0, rx_flags = 0;
 
@@ -718,7 +889,7 @@
 {
 	int i = 0;
 	u32 status;
-	
+
 	/* STSOUT register is Latched on Transition, read operation updates it */
 	while (i++ < 2)
 		status = mdio_read(net_dev, phy_addr, MII_STSOUT);
@@ -736,9 +907,9 @@
 	if (status & MII_STSOUT_LINK_FAIL)
 		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
 	else
-		printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", 
+		printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",
 		       net_dev->name,
-		       *speed == HW_SPEED_100_MBPS ? 
+		       *speed == HW_SPEED_100_MBPS ?
 		       "100mbps" : "10mbps",
 		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
 		       "full" : "half");
@@ -747,7 +918,7 @@
 {
 	int i;
 	u16 status;
-	
+
 	for (i = 0; i < 2; i++)
 		status = mdio_read(net_dev, phy_addr, MII_STATUS);
 
@@ -765,9 +936,9 @@
 			*duplex = FDX_CAPABLE_HALF_SELECTED;
 
 		if (status & MII_STSSUM_LINK)
-			printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", 
+			printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",
 			       net_dev->name,
-			       *speed == HW_SPEED_100_MBPS ? 
+			       *speed == HW_SPEED_100_MBPS ?
 			       "100mbps" : "10mbps",
 			       *duplex == FDX_CAPABLE_FULL_SELECTED ?
 			       "full" : "half");
@@ -779,7 +950,7 @@
 		*speed = HW_SPEED_HOME;
 		*duplex = FDX_CAPABLE_HALF_SELECTED;
 		if (status & MII_STAT_LINK)
-			printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n", 
+			printk(KERN_INFO "%s: Media Link On 1mbps half-duplex \n",
 			       net_dev->name);
 		else
 			printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
@@ -787,188 +958,189 @@
 }
 static void sis900_tx_timeout(struct device *net_dev)
 {
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
-        long ioaddr = net_dev->base_addr;
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	long ioaddr = net_dev->base_addr;
 	int i;
 
 	printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",
 	       net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr));
-	
-        /* Disable interrupts by clearing the interrupt mask. */
-        outl(0x0000, ioaddr + imr);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outl(0x0000, ioaddr + imr);
 
 	/* discard unsent packets, should this code section be protected by
 	   cli(), sti() ?? */
 	sis_priv->dirty_tx = sis_priv->cur_tx = 0;
 	for (i = 0; i < NUM_TX_DESC; i++) {
 		if (sis_priv->tx_skbuff[i] != NULL) {
-		    dev_kfree_skb(sis_priv->tx_skbuff[i]);
-		    sis_priv->tx_skbuff[i] = 0;
+			dev_kfree_skb(sis_priv->tx_skbuff[i]);
+			sis_priv->tx_skbuff[i] = 0;
 			sis_priv->tx_ring[i].cmdsts = 0;
 			sis_priv->tx_ring[i].bufptr = 0;
 			sis_priv->stats.tx_dropped++;
 		}
 	}
-        net_dev->trans_start = jiffies;
+	net_dev->trans_start = jiffies;
 	net_dev->tbusy = sis_priv->tx_full = 0;
 
 	/* FIXME: Should we restart the transmission thread here  ?? */
+	outl(TxENA, ioaddr + cr);
 
-        /* Enable all known interrupts by setting the interrupt mask. */
+	/* Enable all known interrupts by setting the interrupt mask. */
 	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
-        return;
+	return;
 }
 
 static int
 sis900_start_xmit(struct sk_buff *skb, struct device *net_dev)
 {
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
-        long ioaddr = net_dev->base_addr;
-        unsigned int  entry;
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	long ioaddr = net_dev->base_addr;
+	unsigned int  entry;
 
 	/* test tbusy to see if we have timeout situation then set it */
-        if (test_and_set_bit(0, (void*)&net_dev->tbusy) != 0) {
-                if (jiffies - net_dev->trans_start > TX_TIMEOUT)
+	if (test_and_set_bit(0, (void*)&net_dev->tbusy) != 0) {
+		if (jiffies - net_dev->trans_start > TX_TIMEOUT)
 			sis900_tx_timeout(net_dev);
-                return 1;
-        }
+		return 1;
+	}
 
-        /* Calculate the next Tx descriptor entry. */
-        entry = sis_priv->cur_tx % NUM_TX_DESC;
-        sis_priv->tx_skbuff[entry] = skb;
+	/* Calculate the next Tx descriptor entry. */
+	entry = sis_priv->cur_tx % NUM_TX_DESC;
+	sis_priv->tx_skbuff[entry] = skb;
 
 	/* set the transmit buffer descriptor and enable Transmit State Machine */
 	sis_priv->tx_ring[entry].bufptr = virt_to_bus(skb->data);
-        sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
-        outl(TxENA, ioaddr + cr);
+	sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
+	outl(TxENA, ioaddr + cr);
 
-        if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {
+	if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {
 		/* Typical path, clear tbusy to indicate more 
 		   transmission is possible */
-                clear_bit(0, (void*)&net_dev->tbusy);
-        } else {
+		clear_bit(0, (void*)&net_dev->tbusy);
+	} else {
 		/* no more transmit descriptor avaiable, tbusy remain set */
-                sis_priv->tx_full = 1;
-        }
+		sis_priv->tx_full = 1;
+	}
 
-        net_dev->trans_start = jiffies;
+	net_dev->trans_start = jiffies;
 
-        if (sis900_debug > 3)
-                printk(KERN_INFO "%s: Queued Tx packet at %p size %d "
+	if (sis900_debug > 3)
+		printk(KERN_INFO "%s: Queued Tx packet at %p size %d "
 		       "to slot %d.\n",
 		       net_dev->name, skb->data, (int)skb->len, entry);
 
-        return 0;
+	return 0;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static void sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
-        struct device *net_dev = (struct device *)dev_instance;
-        int boguscnt = max_interrupt_work;
+	struct device *net_dev = (struct device *)dev_instance;
+	int boguscnt = max_interrupt_work;
 	long ioaddr = net_dev->base_addr;
 	u32 status;
 
 #if defined(__i386__)
-        /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-        if (test_and_set_bit(0, (void*)&net_dev->interrupt)) {
-                printk(KERN_INFO "%s: SMP simultaneous entry of "
+	/* A lock to prevent simultaneous entry bug on Intel SMP machines. */
+	if (test_and_set_bit(0, (void*)&net_dev->interrupt)) {
+		printk(KERN_INFO "%s: SMP simultaneous entry of "
 		       "an interrupt handler.\n", net_dev->name);
-                net_dev->interrupt = 0;     /* Avoid halting machine. */
-                return;
-        }
+		net_dev->interrupt = 0;		/* Avoid halting machine. */
+		return;
+	}
 #else
-        if (net_dev->interrupt) {
-                printk(KERN_INFO "%s: Re-entering the interrupt handler.\n", 
+	if (net_dev->interrupt) {
+		printk(KERN_INFO "%s: Re-entering the interrupt handler.\n",
 		       net_dev->name);
-                return;
-        }
-        net_dev->interrupt = 1;
+		return;
+	}
+	net_dev->interrupt = 1;
 #endif
 
-        do {
-                status = inl(ioaddr + isr);
-		
+	do {
+		status = inl(ioaddr + isr);
+
 		if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
 			/* nothing intresting happened */
-                        break;
+			break;
 
 		/* why dow't we break after Tx/Rx case ?? keyword: full-duplex */
-                if (status & (RxORN | RxERR | RxOK))
+		if (status & (RxORN | RxERR | RxOK))
 			/* Rx interrupt */
-                        sis900_rx(net_dev);
+			sis900_rx(net_dev);
 
 		if (status & (TxURN | TxERR | TxIDLE))
 			/* Tx interrupt */
 			sis900_finish_xmit(net_dev);
 
-                /* something strange happened !!! */
-                if (status & HIBERR) {
+		/* something strange happened !!! */
+		if (status & HIBERR) {
 			printk(KERN_INFO "%s: Abnormal interrupt,"
 			       "status %#8.8x.\n", net_dev->name, status);
 			break;
 		}
-                if (--boguscnt < 0) {
-                        printk(KERN_INFO "%s: Too much work at interrupt, "
+		if (--boguscnt < 0) {
+			printk(KERN_INFO "%s: Too much work at interrupt, "
 			       "interrupt status = %#8.8x.\n",
 			       net_dev->name, status);
-                        break;
-                }
-        } while (1);
-	
-        if (sis900_debug > 3)
-                printk(KERN_INFO "%s: exiting interrupt, "
+			break;
+		}
+	} while (1);
+
+	if (sis900_debug > 3)
+		printk(KERN_INFO "%s: exiting interrupt, "
 		       "interrupt status = 0x%#8.8x.\n",
 		       net_dev->name, inl(ioaddr + isr));
 	
 #if defined(__i386__)
-        clear_bit(0, (void*)&net_dev->interrupt);
+	clear_bit(0, (void*)&net_dev->interrupt);
 #else
-        net_dev->interrupt = 0;
+	net_dev->interrupt = 0;
 #endif
-        return;
+	return;
 }
 
 /* Process receive interrupt events, put buffer to higher layer and refill buffer pool 
    Note: This fucntion is called by interrupt handler, don't do "too much" work here */
 static int sis900_rx(struct device *net_dev)
 {
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
-        long ioaddr = net_dev->base_addr;
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	long ioaddr = net_dev->base_addr;
 	unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC;
-        u32 rx_status = sis_priv->rx_ring[entry].cmdsts;
-	
-        if (sis900_debug > 3)
-                printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
+	u32 rx_status = sis_priv->rx_ring[entry].cmdsts;
+
+	if (sis900_debug > 3)
+		printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
 		       "status:0x%8.8x\n",
-		       sis_priv->cur_rx, sis_priv->dirty_rx,rx_status);
-	
-        while (rx_status & OWN) {
-                unsigned int rx_size;
-		
+		       sis_priv->cur_rx, sis_priv->dirty_rx, rx_status);
+
+	while (rx_status & OWN) {
+		unsigned int rx_size;
+
 		rx_size = (rx_status & DSIZE) - CRC_SIZE;
-		
+
 		if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) {
 			/* corrupted packet received */
-                        if (sis900_debug > 3)
-                                printk(KERN_INFO "%s: Corrupted packet "
+			if (sis900_debug > 3)
+				printk(KERN_INFO "%s: Corrupted packet "
 				       "received, buffer status = 0x%8.8x.\n",
 				       net_dev->name, rx_status);
-                        sis_priv->stats.rx_errors++;
+			sis_priv->stats.rx_errors++;
 			if (rx_status & OVERRUN)
 				sis_priv->stats.rx_over_errors++;
 			if (rx_status & (TOOLONG|RUNT))
-                                sis_priv->stats.rx_length_errors++;
-                        if (rx_status & (RXISERR | FAERR))
-                                sis_priv->stats.rx_frame_errors++;
+				sis_priv->stats.rx_length_errors++;
+			if (rx_status & (RXISERR | FAERR))
+				sis_priv->stats.rx_frame_errors++;
 			if (rx_status & CRCERR) 
 				sis_priv->stats.rx_crc_errors++;
 			/* reset buffer descriptor state */
 			sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
-                } else {
+		} else {
 			struct sk_buff * skb;
-			
+
 			/* This situation should never happen, but due to
 			   some unknow bugs, it is possible that
 			   we are working on NULL sk_buff :-( */
@@ -976,41 +1148,62 @@
 				printk(KERN_INFO "%s: NULL pointer " 
 				       "encountered in Rx ring, skipping\n",
 				       net_dev->name);
-				break;			
+				break;
 			}
+
+			/* gvie the socket buffer to upper layers */
 			skb = sis_priv->rx_skbuff[entry];
-			sis_priv->rx_skbuff[entry] = NULL;
-			/* reset buffer descriptor state */
-			sis_priv->rx_ring[entry].cmdsts = 0;
-			sis_priv->rx_ring[entry].bufptr = 0;
-			
 			skb_put(skb, rx_size);
-                        skb->protocol = eth_type_trans(skb, net_dev);
-                        netif_rx(skb);
-			
+			skb->protocol = eth_type_trans(skb, net_dev);
+			netif_rx(skb);
+
+			/* some network statistics */
 			if ((rx_status & BCAST) == MCAST)
 				sis_priv->stats.multicast++;
 			net_dev->last_rx = jiffies;
-                        sis_priv->stats.rx_bytes += rx_size;
-                        sis_priv->stats.rx_packets++;
-                }
-                sis_priv->cur_rx++;
+			sis_priv->stats.rx_bytes += rx_size;
+			sis_priv->stats.rx_packets++;
+
+			/* refill the Rx buffer, what if there is not enought memory for
+			   new socket buffer ?? */
+			if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
+				/* not enough memory for skbuff, this makes a "hole"
+				   on the buffer ring, it is not clear how the
+				   hardware will react to this kind of degenerated
+				   buffer */
+				printk(KERN_INFO "%s: Memory squeeze,"
+				       "deferring packet.\n",
+				       net_dev->name);
+				sis_priv->rx_skbuff[entry] = NULL;
+				/* reset buffer descriptor state */
+				sis_priv->rx_ring[entry].cmdsts = 0;
+				sis_priv->rx_ring[entry].bufptr = 0;
+				sis_priv->stats.rx_dropped++;
+				break;
+			}
+			skb->dev = net_dev;
+			sis_priv->rx_skbuff[entry] = skb;
+			sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
+			sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail);
+			sis_priv->dirty_rx++;
+		}
+		sis_priv->cur_rx++;
 		entry = sis_priv->cur_rx % NUM_RX_DESC;
-                rx_status = sis_priv->rx_ring[entry].cmdsts;
-        } // while
-	
+		rx_status = sis_priv->rx_ring[entry].cmdsts;
+	} // while
+
 	/* refill the Rx buffer, what if the rate of refilling is slower than 
 	   consuming ?? */
 	for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) {
 		struct sk_buff *skb;
-		
+
 		entry = sis_priv->dirty_rx % NUM_RX_DESC;
-		
+
 		if (sis_priv->rx_skbuff[entry] == NULL) {
 			if ((skb = dev_alloc_skb(RX_BUF_SIZE)) == NULL) {
 				/* not enough memory for skbuff, this makes a "hole"
-				   on the buffer ring, it is not clear how the 
-				   hardware will react to this kind of degenerated 
+				   on the buffer ring, it is not clear how the
+				   hardware will react to this kind of degenerated
 				   buffer */
 				printk(KERN_INFO "%s: Memory squeeze,"
 				       "deferring packet.\n",
@@ -1024,10 +1217,11 @@
 			sis_priv->rx_ring[entry].bufptr = virt_to_bus(skb->tail);
 		}
 	}
+
 	/* re-enable the potentially idle receive state matchine */
 	outl(RxENA , ioaddr + cr );
-	
-        return 0;
+
+	return 0;
 }
 
 /* finish up transmission of packets, check for error condition and free skbuff etc.
@@ -1035,21 +1229,21 @@
 static void sis900_finish_xmit (struct device *net_dev)
 {
 	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
-	
+
 	for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) {
 		unsigned int entry;
 		u32 tx_status;
-		
+
 		entry = sis_priv->dirty_tx % NUM_TX_DESC;
-	        tx_status = sis_priv->tx_ring[entry].cmdsts;
-		
+		tx_status = sis_priv->tx_ring[entry].cmdsts;
+
 		if (tx_status & OWN) {
 			/* The packet is not transmited yet (owned by hardware) !
 			   Note: the interrupt is generated only when Tx Machine
 			   is idle, so this is an almost impossible case */
 			break;
 		}
-		
+
 		if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
 			/* packet unsuccessfully transmited */
 			if (sis900_debug > 3)
@@ -1077,7 +1271,7 @@
 		sis_priv->tx_ring[entry].bufptr = 0;
 		sis_priv->tx_ring[entry].cmdsts = 0;
 	}
-	
+
 	if (sis_priv->tx_full && net_dev->tbusy && 
 	    sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
 		/* The ring is no longer full, clear tbusy, tx_full and 
@@ -1091,23 +1285,23 @@
 static int
 sis900_close(struct device *net_dev)
 {
-        long ioaddr = net_dev->base_addr;
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
-        int i;
-	
-        net_dev->start = 0;
-        net_dev->tbusy = 1;
+	long ioaddr = net_dev->base_addr;
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	int i;
+
+	net_dev->start = 0;
+	net_dev->tbusy = 1;
 
-        /* Disable interrupts by clearing the interrupt mask. */
-        outl(0x0000, ioaddr + imr);
+	/* Disable interrupts by clearing the interrupt mask. */
+	outl(0x0000, ioaddr + imr);
 	outl(0x0000, ioaddr + ier);
 
-        /* Stop the chip's Tx and Rx Status Machine */
-        outl(RxDIS | TxDIS, ioaddr + cr);
+	/* Stop the chip's Tx and Rx Status Machine */
+	outl(RxDIS | TxDIS, ioaddr + cr);
 
-        del_timer(&sis_priv->timer);
+	del_timer(&sis_priv->timer);
 
-        free_irq(net_dev->irq, net_dev);
+	free_irq(net_dev->irq, net_dev);
 
 	/* Free Tx and RX skbuff */
 	for (i = 0; i < NUM_RX_DESC; i++) {
@@ -1115,47 +1309,47 @@
 			dev_kfree_skb(sis_priv->rx_skbuff[i]);
 		sis_priv->rx_skbuff[i] = 0;
 	}
-        for (i = 0; i < NUM_TX_DESC; i++) {
-                if (sis_priv->tx_skbuff[i] != NULL)
-                        dev_kfree_skb(sis_priv->tx_skbuff[i]);
-                sis_priv->tx_skbuff[i] = 0;
-        }
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		if (sis_priv->tx_skbuff[i] != NULL)
+			dev_kfree_skb(sis_priv->tx_skbuff[i]);
+		sis_priv->tx_skbuff[i] = 0;
+	}
 
-        /* Green! Put the chip in low-power mode. */
+	/* Green! Put the chip in low-power mode. */
 
-        MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 
-        return 0;
+	return 0;
 }
 
 static int mii_ioctl(struct device *net_dev, struct ifreq *rq, int cmd)
 {
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
-        u16 *data = (u16 *)&rq->ifr_data;
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	u16 *data = (u16 *)&rq->ifr_data;
 
-        switch(cmd) {
-        case SIOCDEVPRIVATE:            	/* Get the address of the PHY in use. */
-                data[0] = sis_priv->mii->phy_addr;
-                /* Fall Through */
-        case SIOCDEVPRIVATE+1:          	/* Read the specified MII register. */
-                data[3] = mdio_read(net_dev, data[0] & 0x1f, data[1] & 0x1f);
-                return 0;
-        case SIOCDEVPRIVATE+2:          	/* Write the specified MII register */
-                if (!suser())
-                        return -EPERM;
-                mdio_write(net_dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-                return 0;
-        default:
-                return -EOPNOTSUPP;
-        }
+	switch(cmd) {
+	case SIOCDEVPRIVATE:			/* Get the address of the PHY in use. */
+		data[0] = sis_priv->mii->phy_addr;
+		/* Fall Through */
+	case SIOCDEVPRIVATE+1:			/* Read the specified MII register. */
+		data[3] = mdio_read(net_dev, data[0] & 0x1f, data[1] & 0x1f);
+		return 0;
+	case SIOCDEVPRIVATE+2:			/* Write the specified MII register */
+		if (!suser())
+			return -EPERM;
+		mdio_write(net_dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static struct enet_statistics *
 sis900_get_stats(struct device *net_dev)
 {
-        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
+	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
 
-        return &sis_priv->stats;
+	return &sis_priv->stats;
 }
 
 /* SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast hash table, which makes
@@ -1183,49 +1377,49 @@
 			byte >>= 1;
 		}
 	}
-	/* leave 7 most siginifant bits */ 
+	/* leave 7 most siginifant bits */
 	return ((int)(crc >> 25));
 }
 
 static void set_rx_mode(struct device *net_dev)
 {
-        long ioaddr = net_dev->base_addr;
-        u16 mc_filter[8];			/* 128 bits multicast hash table */
-        int i;
-        u32 rx_mode;
+	long ioaddr = net_dev->base_addr;
+	u16 mc_filter[8];			/* 128 bits multicast hash table */
+	int i;
+	u32 rx_mode;
 
-        if (net_dev->flags & IFF_PROMISC) {
+	if (net_dev->flags & IFF_PROMISC) {
 		/* Accept any kinds of packets */
 		rx_mode = RFPromiscuous;
-                for (i = 0; i < 8; i++)
-                        mc_filter[i] = 0xffff;
-        } else if ((net_dev->mc_count > multicast_filter_limit) ||
+		for (i = 0; i < 8; i++)
+			mc_filter[i] = 0xffff;
+	} else if ((net_dev->mc_count > multicast_filter_limit) ||
 		   (net_dev->flags & IFF_ALLMULTI)) {
 		/* too many multicast addresses or accept all multicast packets */
-                rx_mode = RFAAB | RFAAM;
-                for (i = 0; i < 8; i++)
-                        mc_filter[i] = 0xffff;
-        } else {
+		rx_mode = RFAAB | RFAAM;
+		for (i = 0; i < 8; i++)
+			mc_filter[i] = 0xffff;
+	} else {
 		/* Accept Broadcast packets, destination addresses match our MAC address,
 		   use Receive Filter to reject unwanted MCAST packets */
-                struct dev_mc_list *mclist;
-                rx_mode = RFAAB;
-                for (i = 0; i < 8; i++)
-                        mc_filter[i]=0;
-                for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count;
+		struct dev_mc_list *mclist;
+		rx_mode = RFAAB;
+		for (i = 0; i < 8; i++)
+			mc_filter[i]=0;
+		for (i = 0, mclist = net_dev->mc_list; mclist && i < net_dev->mc_count;
 		     i++, mclist = mclist->next)
-                        set_bit(sis900_compute_hashtable_index(mclist->dmi_addr),
+			set_bit(sis900_compute_hashtable_index(mclist->dmi_addr),
 				mc_filter);
-        }
+	}
 
 	/* update Multicast Hash Table in Receive Filter */
-        for (i = 0; i < 8; i++) {
+	for (i = 0; i < 8; i++) {
 		/* why plus 0x04 ??, That makes the correct value for hash table. */
-                outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
-                outl(mc_filter[i], ioaddr + rfdr);
-        }
+		outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr);
+		outl(mc_filter[i], ioaddr + rfdr);
+	}
 
-        outl(RFEN | rx_mode, ioaddr + rfcr);
+	outl(RFEN | rx_mode, ioaddr + rfcr);
 
 	/* sis900 is capatable of looping back packet at MAC level for debugging purpose */
 	if (net_dev->flags & IFF_LOOPBACK) {
@@ -1240,33 +1434,33 @@
 		outl(cr_saved, ioaddr + cr);
 	}		
 
-        return;
+	return;
 }
 
 static void sis900_reset(struct device *net_dev)
 {
-        long ioaddr = net_dev->base_addr;
+	long ioaddr = net_dev->base_addr;
 	int i = 0;
 	u32 status = TxRCMP | RxRCMP;
 
-        outl(0, ioaddr + ier);
-        outl(0, ioaddr + imr);
-        outl(0, ioaddr + rfcr);
+	outl(0, ioaddr + ier);
+	outl(0, ioaddr + imr);
+	outl(0, ioaddr + rfcr);
 
-        outl(RxRESET | TxRESET | RESET, ioaddr + cr);
+	outl(RxRESET | TxRESET | RESET, ioaddr + cr);
 	
 	/* Check that the chip has finished the reset. */
 	while (status && (i++ < 1000)) {
 		status ^= (inl(isr + ioaddr) & status);
-        }
+	}
 
-        outl(PESEL, ioaddr + cfg);
+	outl(PESEL, ioaddr + cfg);
 }
 
 #ifdef MODULE
 int init_module(void)
 {
-        return sis900_probe(NULL);
+	return sis900_probe(NULL);
 }
 
 void
@@ -1277,7 +1471,7 @@
 		struct sis900_private *sis_priv =
 			(struct sis900_private *)root_sis900_dev->priv;
 		struct device *next_dev = sis_priv->next_module;
-		
+
 		unregister_netdev(root_sis900_dev);
 		release_region(root_sis900_dev->base_addr,
 			       sis_priv->mac->io_size);
@@ -1285,7 +1479,7 @@
 		kfree(root_sis900_dev);
 
 		root_sis900_dev = next_dev;
-        }
+	}
 }
 
-#endif  /* MODULE */
+#endif	/* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sis900.h linux.18p8/drivers/net/sis900.h
--- linux.vanilla/drivers/net/sis900.h	Fri Apr 21 12:46:19 2000
+++ linux.18p8/drivers/net/sis900.h	Thu Aug 31 14:30:01 2000
@@ -38,6 +38,7 @@
 
 /* Symbolic names for bits in various registers */
 enum sis900_command_register_bits {
+	RELOAD  = 0x00000400,
 	RESET   = 0x00000100, SWI = 0x00000080, RxRESET = 0x00000020,
 	TxRESET = 0x00000010, RxDIS = 0x00000008, RxENA = 0x00000004,
 	TxDIS   = 0x00000002, TxENA = 0x00000001
@@ -164,7 +165,7 @@
 /* mii registers specific to SiS 900 */
 enum sis_mii_registers {
 	MII_CONFIG1 = 0x0010, MII_CONFIG2 = 0x0011, MII_STSOUT = 0x0012,
-	MII_MASK    = 0x0013
+	MII_MASK    = 0x0013, MII_RESV    = 0x0014
 };
 
 /* mii registers specific to AMD 79C901 */
@@ -214,6 +215,10 @@
 enum mii_stssum_register_bits {
 	MII_STSSUM_LINK = 0x0008, MII_STSSUM_DPLX = 0x0004,
 	MII_STSSUM_AUTO = 0x0002, MII_STSSUM_SPD  = 0x0001
+};
+
+enum sis630_revision_id {
+	SIS630E_REV = 0x81, SIS630EA1_REV = 0x83
 };
 
 #define FDX_CAPABLE_DUPLEX_UNKNOWN      0
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sk98lin/skge.c linux.18p8/drivers/net/sk98lin/skge.c
--- linux.vanilla/drivers/net/sk98lin/skge.c	Fri Apr 21 12:46:19 2000
+++ linux.18p8/drivers/net/sk98lin/skge.c	Fri Sep  1 13:48:23 2000
@@ -431,6 +431,7 @@
 		pci_set_master(pdev);
 
 		base_address = pdev->base_address[0];
+		base_address &= PCI_BASE_ADDRESS_MEM_MASK;
 
 #ifdef __sparc_v9__
 		/* SPARC machines do not initialize the chache line size */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/Makefile linux.18p8/drivers/net/skfp/Makefile
--- linux.vanilla/drivers/net/skfp/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/Makefile	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,39 @@
+#
+# Makefile for the SysKonnect FDDI PCI adapter driver
+#
+
+ifeq ($(CONFIG_SKFP),y)
+    O_TARGET := skfp.o
+    O_OBJS =  skfddi.o    hwmtm.o    fplustm.o  smt.o      cfm.o     \
+              ecm.o       pcmplc.o   pmf.o      queue.o    rmt.o     \
+	      smtdef.o    smtinit.o  smttimer.o srf.o      lnkstat.o \
+              smtparse.o  hwt.o      drvfbi.o   ess.o
+else
+  ifeq ($(CONFIG_SKFP),m)
+    MOD_LIST_NAME := SKFP_MODULES
+    M_OBJS := skfp.o
+    O_TARGET := skfp.o
+    O_OBJS =  skfddi.o    hwmtm.o    fplustm.o  smt.o      cfm.o     \
+              ecm.o       pcmplc.o   pmf.o      queue.o    rmt.o     \
+	      smtdef.o    smtinit.o  smttimer.o srf.o      lnkstat.o \
+              smtparse.o  hwt.o      drvfbi.o   ess.o
+  endif
+endif
+
+# NOTE:
+#   Compiling this driver produces some warnings (and some more are 
+#   switched off below), but I did not fix this, because the Hardware
+#   Module source (see skfddi.c for details) is used for different
+#   drivers, and fixing it for Linux might bring problems on other
+#   projects. To keep the source common for all those drivers (and
+#   thus simplify fixes to it), please do not clean it up!
+ 
+EXTRA_CFLAGS += -I. -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes 
+
+include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
+
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/can.c linux.18p8/drivers/net/skfp/can.c
--- linux.vanilla/drivers/net/skfp/can.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/can.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	lint
+static const char xID_sccs[] = "@(#)can.c	1.5 97/04/07 (C) SK " ;
+#endif
+
+/*
+ * canonical bit order
+ */
+const u_char canonical[256] = {
+	0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
+	0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
+	0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
+	0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
+	0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
+	0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
+	0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
+	0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
+	0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
+	0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
+	0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
+	0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
+	0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
+	0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
+	0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
+	0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
+	0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
+	0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
+	0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
+	0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
+	0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
+	0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
+	0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
+	0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
+	0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
+	0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
+	0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
+	0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
+	0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
+	0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
+	0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
+	0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
+} ;
+
+#ifdef	MAKE_TABLE
+int byte_reverse(x)
+int x ;
+{
+	int     y = 0 ;
+
+	if (x & 0x01)
+		y |= 0x80 ;
+	if (x & 0x02)
+		y |= 0x40 ;
+	if (x & 0x04)
+		y |= 0x20 ;
+	if (x & 0x08)
+		y |= 0x10 ;
+	if (x & 0x10)
+		y |= 0x08 ;
+	if (x & 0x20)
+		y |= 0x04 ;
+	if (x & 0x40)
+		y |= 0x02 ;
+	if (x & 0x80)
+		y |= 0x01 ;
+	return(y) ;
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/cfm.c linux.18p8/drivers/net/skfp/cfm.c
--- linux.vanilla/drivers/net/skfp/cfm.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/cfm.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,642 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT CFM
+	Configuration Management
+	DAS with single MAC
+*/
+
+/*
+ *	Hardware independant state machine implemantation
+ *	The following external SMT functions are referenced :
+ *
+ *		queue_event()
+ *
+ *	The following external HW dependant functions are referenced :
+ *		config_mux()
+ *
+ *	The following HW dependant events are required :
+ *		NONE 
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)cfm.c	2.18 98/10/06 (C) SK " ;
+#endif
+
+/*
+ * FSM Macros
+ */
+#define AFLAG	0x10
+#define GO_STATE(x)	(smc->mib.fddiSMTCF_State = (x)|AFLAG)
+#define ACTIONS_DONE()	(smc->mib.fddiSMTCF_State &= ~AFLAG)
+#define ACTIONS(x)	(x|AFLAG)
+
+#ifdef	DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const cfm_states[] = {
+	"SC0_ISOLATED","CF1","CF2","CF3","CF4",
+	"SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S",
+	"SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const cfm_events[] = {
+	"NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B"
+} ;
+#endif
+
+/*
+ * map from state to downstream port type
+ */
+static const u_char cf_to_ptype[] = {
+	TNONE,TNONE,TNONE,TNONE,TNONE,
+	TNONE,TB,TB,TS,
+	TA,TB,TS,TB
+} ;
+
+/*
+ * CEM port states
+ */
+#define	CEM_PST_DOWN	0
+#define	CEM_PST_UP	1
+#define	CEM_PST_HOLD	2
+/* define portstate array only for A and B port */
+/* Do this within the smc structure (use in multiple cards) */
+
+/*
+ * all Globals  are defined in smc.h
+ * struct s_cfm
+ */
+
+/*
+ * function declarations
+ */
+static void cfm_fsm() ;
+
+/*
+	init CFM state machine
+	clear all CFM vars and flags
+*/
+void cfm_init(smc)
+struct s_smc *smc ;
+{
+	smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ;
+	smc->r.rm_join = 0 ;
+	smc->r.rm_loop = 0 ;
+	smc->y[PA].scrub = 0 ;
+	smc->y[PB].scrub = 0 ;
+	smc->y[PA].cem_pst = CEM_PST_DOWN ;
+	smc->y[PB].cem_pst = CEM_PST_DOWN ;
+}
+
+/* Some terms conditions used by the selection criteria */
+#define THRU_ENABLED(smc)	(smc->y[PA].pc_mode != PM_TREE && \
+				 smc->y[PB].pc_mode != PM_TREE)
+/* Selection criteria for the ports */
+static void	selection_criteria (smc,phy)
+struct s_smc	*smc ;
+struct s_phy	*phy ;
+{
+
+	switch (phy->mib->fddiPORTMy_Type) {
+	case TA:
+		if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) {
+			phy->wc_flag = TRUE ;
+		} else {
+			phy->wc_flag = FALSE ;
+		}
+
+		break;
+	case TB:
+		/* take precedence over PA */
+		phy->wc_flag = FALSE ;
+		break;
+	case TS:
+		phy->wc_flag = FALSE ;
+		break;
+	case TM:
+		phy->wc_flag = FALSE ;
+		break;
+	}
+
+}
+
+void	all_selection_criteria (smc)
+struct s_smc *smc ;
+{
+	struct s_phy	*phy ;
+	int		p ;
+
+	for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) {
+		/* Do the selection criteria */
+		selection_criteria (smc,phy);
+	}
+}
+
+static void	cem_priv_state (smc, event)
+struct s_smc *smc ;
+int event ;
+/* State machine for private PORT states: used to optimize dual homing */
+{
+	int	np;	/* Number of the port */
+	int	i;
+
+	/* Do this only in a DAS */
+	if (smc->s.sas != SMT_DAS )
+		return ;
+
+	np = event - CF_JOIN;
+
+	if (np != PA && np != PB) {
+		return ;
+	}
+	/* Change the port state according to the event (portnumber) */
+	if (smc->y[np].cf_join) {
+		smc->y[np].cem_pst = CEM_PST_UP ;
+	} else if (!smc->y[np].wc_flag) {
+		/* set the port to done only if it is not withheld */
+		smc->y[np].cem_pst = CEM_PST_DOWN ;
+	}
+
+	/* Don't set an hold port to down */
+
+	/* Check all ports of restart conditions */
+	for (i = 0 ; i < 2 ; i ++ ) {
+		/* Check all port for PORT is on hold and no withhold is done */
+		if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) {
+			smc->y[i].cem_pst = CEM_PST_DOWN;
+			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
+		}
+		if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) {
+			smc->y[i].cem_pst = CEM_PST_HOLD;
+			queue_event(smc,(int)(EVENT_PCM+i),PC_START) ;
+		}
+		if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) {
+			/*
+			 * The port must be restarted when the wc_flag
+			 * will be reset. So set the port on hold.
+			 */
+			smc->y[i].cem_pst = CEM_PST_HOLD;
+		}
+	}
+	return ;
+}
+
+/*
+	CFM state machine
+	called by dispatcher
+
+	do
+		display state change
+		process event
+	until SM is stable
+*/
+void cfm(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+	int	state ;		/* remember last state */
+	int	cond ;
+	int	oldstate ;
+
+	/* We will do the following: */
+	/*  - compute the variable WC_Flag for every port (This is where */
+	/*    we can extend the requested path checking !!) */
+	/*  - do the old (SMT 6.2 like) state machine */
+	/*  - do the resulting station states */
+
+	all_selection_criteria (smc);
+
+	/* We will check now whether a state transition is allowed or not */
+	/*  - change the portstates */
+	cem_priv_state (smc, event);
+
+	oldstate = smc->mib.fddiSMTCF_State ;
+	do {
+		DB_CFM("CFM : state %s%s",
+			(smc->mib.fddiSMTCF_State & AFLAG) ? "ACTIONS " : "",
+			cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG]) ;
+		DB_CFM(" event %s\n",cfm_events[event],0) ;
+		state = smc->mib.fddiSMTCF_State ;
+		cfm_fsm(smc,event) ;
+		event = 0 ;
+	} while (state != smc->mib.fddiSMTCF_State) ;
+
+#ifndef	SLIM_SMT
+	/*
+	 * check peer wrap condition
+	 */
+	cond = FALSE ;
+	if (	(smc->mib.fddiSMTCF_State == SC9_C_WRAP_A &&
+		smc->y[PA].pc_mode == PM_PEER) 	||
+		(smc->mib.fddiSMTCF_State == SC10_C_WRAP_B &&
+		smc->y[PB].pc_mode == PM_PEER) 	||
+		(smc->mib.fddiSMTCF_State == SC11_C_WRAP_S &&
+		smc->y[PS].pc_mode == PM_PEER &&
+		smc->y[PS].mib->fddiPORTNeighborType != TS ) ) {
+			cond = TRUE ;
+	}
+	if (cond != smc->mib.fddiSMTPeerWrapFlag)
+		smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ;
+
+#if	0
+	/*
+	 * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired
+	 * to the primary path.
+	 */
+	/*
+	 * path change
+	 */
+	if (smc->mib.fddiSMTCF_State != oldstate) {
+		smt_srf_event(smc,SMT_EVENT_MAC_PATH_CHANGE,INDEX_MAC,0) ;
+	}
+#endif
+#endif	/* no SLIM_SMT */
+
+	/*
+	 * set MAC port type
+	 */
+	smc->mib.m[MAC0].fddiMACDownstreamPORTType =
+		cf_to_ptype[smc->mib.fddiSMTCF_State] ;
+	cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ;
+}
+
+/*
+	process CFM event
+*/
+/*ARGSUSED1*/
+static void cfm_fsm(smc,cmd)
+struct s_smc *smc ;
+int cmd ;
+{
+	switch(smc->mib.fddiSMTCF_State) {
+	case ACTIONS(SC0_ISOLATED) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
+		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;
+		config_mux(smc,MUX_ISOLATE) ;	/* configure PHY Mux */
+		smc->r.rm_loop = FALSE ;
+		smc->r.rm_join = FALSE ;
+		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		/* Don't do the WC-Flag changing here */
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break;
+	case SC0_ISOLATED :
+		/*SC07*/
+		/*SAS port can be PA or PB ! */
+		if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop ||
+				smc->y[PB].cf_join || smc->y[PB].cf_loop)) {
+			GO_STATE(SC11_C_WRAP_S) ;
+			break ;
+		}
+		/*SC01*/
+		if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join &&
+		     !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) {
+			GO_STATE(SC9_C_WRAP_A) ;
+			break ;
+		}
+		/*SC02*/
+		if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join &&
+		     !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) {
+			GO_STATE(SC10_C_WRAP_B) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC9_C_WRAP_A) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
+		config_mux(smc,MUX_WRAPA) ;		/* configure PHY mux */
+		if (smc->y[PA].cf_loop) {
+			smc->r.rm_join = FALSE ;
+			smc->r.rm_loop = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
+		}
+		if (smc->y[PA].cf_join) {
+			smc->r.rm_loop = FALSE ;
+			smc->r.rm_join = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		}
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC9_C_WRAP_A :
+		/*SC10*/
+		if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) &&
+		      !smc->y[PA].cf_loop ) {
+			GO_STATE(SC0_ISOLATED) ;
+			break ;
+		}
+		/*SC12*/
+		else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join &&
+			   smc->y[PA].cem_pst == CEM_PST_UP) ||
+			  ((smc->y[PB].cf_loop ||
+			   (smc->y[PB].cf_join &&
+			    smc->y[PB].cem_pst == CEM_PST_UP)) &&
+			    (smc->y[PA].pc_mode == PM_TREE ||
+			     smc->y[PB].pc_mode == PM_TREE))) {
+			smc->y[PA].scrub = TRUE ;
+			GO_STATE(SC10_C_WRAP_B) ;
+			break ;
+		}
+		/*SC14*/
+		else if (!smc->s.attach_s &&
+			  smc->y[PA].cf_join &&
+			  smc->y[PA].cem_pst == CEM_PST_UP &&
+			  smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join &&
+			  smc->y[PB].cem_pst == CEM_PST_UP &&
+			  smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PA].scrub = TRUE ;
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC4_THRU_A) ;
+			break ;
+		}
+		/*SC15*/
+		else if ( smc->s.attach_s &&
+			  smc->y[PA].cf_join &&
+			  smc->y[PA].cem_pst == CEM_PST_UP &&
+			  smc->y[PA].pc_mode == PM_PEER &&
+			  smc->y[PB].cf_join &&
+			  smc->y[PB].cem_pst == CEM_PST_UP &&
+			  smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PA].scrub = TRUE ;
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC5_THRU_B) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC10_C_WRAP_B) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
+		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
+		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
+		config_mux(smc,MUX_WRAPB) ;		/* configure PHY mux */
+		if (smc->y[PB].cf_loop) {
+			smc->r.rm_join = FALSE ;
+			smc->r.rm_loop = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
+		}
+		if (smc->y[PB].cf_join) {
+			smc->r.rm_loop = FALSE ;
+			smc->r.rm_join = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		}
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC10_C_WRAP_B :
+		/*SC20*/
+		if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) {
+			GO_STATE(SC0_ISOLATED) ;
+			break ;
+		}
+		/*SC21*/
+		else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER &&
+			  smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC9_C_WRAP_A) ;
+			break ;
+		}
+		/*SC24*/
+		else if (!smc->s.attach_s &&
+			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
+			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PA].scrub = TRUE ;
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC4_THRU_A) ;
+			break ;
+		}
+		/*SC25*/
+		else if ( smc->s.attach_s &&
+			 smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER &&
+			 smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) {
+			smc->y[PA].scrub = TRUE ;
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC5_THRU_B) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC4_THRU_A) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
+		smc->mib.p[PA].fddiPORTMACPlacement = 0 ;
+		smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
+		config_mux(smc,MUX_THRUA) ;		/* configure PHY mux */
+		smc->r.rm_loop = FALSE ;
+		smc->r.rm_join = TRUE ;
+		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC4_THRU_A :
+		/*SC41*/
+		if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) {
+			smc->y[PA].scrub = TRUE ;
+			GO_STATE(SC9_C_WRAP_A) ;
+			break ;
+		}
+		/*SC42*/
+		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC10_C_WRAP_B) ;
+			break ;
+		}
+		/*SC45*/
+		else if (smc->s.attach_s) {
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC5_THRU_B) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC5_THRU_B) :
+		smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ;
+		smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ;
+		smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.p[PB].fddiPORTMACPlacement = 0 ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ;
+		config_mux(smc,MUX_THRUB) ;		/* configure PHY mux */
+		smc->r.rm_loop = FALSE ;
+		smc->r.rm_join = TRUE ;
+		queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC5_THRU_B :
+		/*SC51*/
+		if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) {
+			smc->y[PA].scrub = TRUE ;
+			GO_STATE(SC9_C_WRAP_A) ;
+			break ;
+		}
+		/*SC52*/
+		else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) {
+			smc->y[PB].scrub = TRUE ;
+			GO_STATE(SC10_C_WRAP_B) ;
+			break ;
+		}
+		/*SC54*/
+		else if (!smc->s.attach_s) {
+			smc->y[PA].scrub = TRUE ;
+			GO_STATE(SC4_THRU_A) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(SC11_C_WRAP_S) :
+		smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ;
+		smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ;
+		smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ;
+		config_mux(smc,MUX_WRAPS) ;		/* configure PHY mux */
+		if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) {
+			smc->r.rm_join = FALSE ;
+			smc->r.rm_loop = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */
+		}
+		if (smc->y[PA].cf_join || smc->y[PB].cf_join) {
+			smc->r.rm_loop = FALSE ;
+			smc->r.rm_join = TRUE ;
+			queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */
+		}
+		ACTIONS_DONE() ;
+		DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ;
+		break ;
+	case SC11_C_WRAP_S :
+		/*SC70*/
+		if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop &&
+		     !smc->y[PB].cf_join && !smc->y[PB].cf_loop) {
+			GO_STATE(SC0_ISOLATED) ;
+			break ;
+		}
+		break ;
+	default:
+		SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ;
+		break;
+	}
+}
+
+/*
+ * get MAC's input Port
+ *	return :
+ *		PA or PB
+ */
+int cfm_get_mac_input(smc)
+struct s_smc *smc ;
+{
+	return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
+		smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA) ;
+}
+
+/*
+ * get MAC's output Port
+ *	return :
+ *		PA or PB
+ */
+int cfm_get_mac_output(smc)
+struct s_smc *smc ;
+{
+	return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B ||
+		smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA) ;
+}
+
+static char path_iso[] = {
+	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
+	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
+} ;
+
+static char path_wrap_a[] = {
+	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
+	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_ISO
+} ;
+
+static char path_wrap_b[] = {
+	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
+	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_ISO
+} ;
+
+static char path_thru[] = {
+	0,0,	0,RES_PORT,	0,PA + INDEX_PORT,	0,PATH_PRIM,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
+	0,0,	0,RES_PORT,	0,PB + INDEX_PORT,	0,PATH_PRIM
+} ;
+
+static char path_wrap_s[] = {
+	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_PRIM,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_PRIM,
+} ;
+
+static char path_iso_s[] = {
+	0,0,	0,RES_PORT,	0,PS + INDEX_PORT,	0,PATH_ISO,
+	0,0,	0,RES_MAC,	0,INDEX_MAC,		0,PATH_ISO,
+} ;
+
+int cem_build_path(smc,to,path_index)
+struct s_smc *smc ;
+char *to ;
+int path_index ;
+{
+	char	*path ;
+	int	len ;
+
+	switch (smc->mib.fddiSMTCF_State) {
+	default :
+	case SC0_ISOLATED :
+		path = smc->s.sas ? path_iso_s : path_iso ;
+		len = smc->s.sas ? sizeof(path_iso_s) :  sizeof(path_iso) ;
+		break ;
+	case SC9_C_WRAP_A :
+		path = path_wrap_a ;
+		len = sizeof(path_wrap_a) ;
+		break ;
+	case SC10_C_WRAP_B :
+		path = path_wrap_b ;
+		len = sizeof(path_wrap_b) ;
+		break ;
+	case SC4_THRU_A :
+		path = path_thru ;
+		len = sizeof(path_thru) ;
+		break ;
+	case SC11_C_WRAP_S :
+		path = path_wrap_s ;
+		len = sizeof(path_wrap_s) ;
+		break ;
+	}
+	memcpy(to,path,len) ;
+
+	LINT_USE(path_index);
+
+	return(len) ;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/drvfbi.c linux.18p8/drivers/net/skfp/drvfbi.c
--- linux.vanilla/drivers/net/skfp/drvfbi.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/drvfbi.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,1612 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * FBI board dependent Driver for SMT and LLC
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#include "h/skfbiinc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)drvfbi.c	1.63 99/02/11 (C) SK " ;
+#endif
+
+/*
+ * PCM active state
+ */
+#define PC8_ACTIVE	8
+
+#define	LED_Y_ON	0x11	/* Used for ring up/down indication */
+#define	LED_Y_OFF	0x10
+
+
+#define MS2BCLK(x)	((x)*12500L)
+
+/*
+ * valid configuration values are:
+ */
+#ifdef	ISA
+const int opt_ints[] = {8,	3, 4, 5, 9, 10, 11, 12, 15} ;
+const int opt_iops[] = {8,
+	0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340};
+const int opt_dmas[] = {4,	3, 5, 6, 7} ;
+const int opt_eproms[] = {15,	0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
+			0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
+#endif
+#ifdef	EISA
+const int opt_ints[] = {5, 9, 10, 11} ;
+const int opt_dmas[] = {0, 5, 6, 7} ;
+const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
+				0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
+#endif
+
+#ifdef	MCA
+int	opt_ints[] = {3, 11, 10, 9} ;			/* FM1 */
+int	opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ;
+#endif	/* MCA */
+
+/*
+ *	xPOS_ID:xxxx
+ *	|	\  /
+ *	|	 \/
+ *	|	  --------------------- the patched POS_ID of the Adapter
+ *	|				xxxx = (Vendor ID low byte,
+ *	|					Vendor ID high byte,
+ *	|					Device ID low byte,
+ *	|					Device ID high byte)
+ *	+------------------------------ the patched oem_id must be
+ *					'S' for SK or 'I' for IBM
+ *					this is a short id for the driver.
+ */
+#ifndef MULT_OEM
+#ifndef	OEM_CONCEPT
+#ifndef MCA
+const u_char oem_id[] = "xPOS_ID:xxxx" ;
+#else
+const u_char oem_id[] = "xPOSID1:xxxx" ;	/* FM1 card id. */
+#endif
+#else	/* OEM_CONCEPT */
+#ifndef MCA
+const u_char oem_id[] = OEM_ID ;
+#else
+const u_char oem_id[] = OEM_ID1 ;	/* FM1 card id. */
+#endif	/* MCA */
+#endif	/* OEM_CONCEPT */
+#define	ID_BYTE0	8
+#define	OEMID(smc,i)	oem_id[ID_BYTE0 + i]
+#else	/* MULT_OEM */
+const struct s_oem_ids oem_ids[] = {
+#include "oemids.h"
+{0}
+};
+#define	OEMID(smc,i)	smc->hw.oem_id->oi_id[i]
+#endif	/* MULT_OEM */
+
+/* Prototypes of external functions */
+extern void hwt_restart() ;
+#ifdef AIX
+extern int AIX_vpdReadByte() ;
+#endif
+
+
+/* Prototypes of local functions. */
+void smt_stop_watchdog() ;
+
+#ifdef MCA
+static int read_card_id() ;
+static void DisableSlotAccess() ;
+static void EnableSlotAccess() ;
+#ifdef AIX
+extern int attach_POS_addr() ;
+extern int detach_POS_addr() ;
+extern u_char read_POS() ;
+extern void write_POS() ;
+extern int AIX_vpdReadByte() ;
+#else
+#define	read_POS(smc,a1,a2)	((u_char) inp(a1))
+#define	write_POS(smc,a1,a2,a3)	outp((a1),(a3))
+#endif
+#endif	/* MCA */
+
+
+/*
+ * FDDI card reset
+ */
+static void card_start(smc)
+struct s_smc *smc ;
+{
+	int i ;
+#ifdef	PCI
+	u_char	rev_id ;
+	u_short word;
+#endif
+
+	smt_stop_watchdog(smc) ;
+
+#ifdef	ISA
+	outpw(CSR_A,0) ;			/* reset for all chips */
+	for (i = 10 ; i ; i--)			/* delay for PLC's */
+		(void)inpw(ISR_A) ;
+	OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ;
+					/* counter 2, mode 2 */
+	OUT_82c54_TIMER(2,97) ;		/* LSB */
+	OUT_82c54_TIMER(2,0) ;		/* MSB ( 15.6 us ) */
+	outpw(CSR_A,CS_CRESET) ;
+#endif
+#ifdef	EISA
+	outpw(CSR_A,0) ;			/* reset for all chips */
+	for (i = 10 ; i ; i--)			/* delay for PLC's */
+		(void)inpw(ISR_A) ;
+	outpw(CSR_A,CS_CRESET) ;
+	smc->hw.led = (2<<6) ;
+	outpw(CSR_A,CS_CRESET | smc->hw.led) ;
+#endif
+#ifdef	MCA
+	outp(ADDR(CARD_DIS),0) ;		/* reset for all chips */
+	for (i = 10 ; i ; i--)			/* delay for PLC's */
+		(void)inpw(ISR_A) ;
+	outp(ADDR(CARD_EN),0) ;
+	/* first I/O after reset must not be a access to FORMAC or PLC */
+
+	/*
+	 * bus timeout (MCA)
+	 */
+	OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ;
+					/* counter 2, mode 3 */
+	OUT_82c54_TIMER(2,(2*24)) ;	/* 3.9 us * 2 square wave */
+	OUT_82c54_TIMER(2,0) ;		/* MSB */
+
+	/* POS 102 indicated an activ Check Line or Buss Error monitoring */
+	if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) {
+		outp(ADDR(IRQ_CHCK_EN),0) ;
+	}
+
+	if (!((i = inpw(CSR_A)) & CS_SAS)) {
+		if (!(i & CS_BYSTAT)) {
+			outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
+		}
+	}
+	outpw(LEDR_A,LED_1) ;	/* yellow */
+#endif	/* MCA */
+#ifdef	PCI
+	/*
+	 * make sure no transfer activity is pending
+	 */
+	outpw(FM_A(FM_MDREG1),FM_MINIT) ;
+	outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
+	hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
+	/*
+	 * now reset everything
+	 */
+	outp(ADDR(B0_CTRL),CTRL_RST_SET) ;	/* reset for all chips */
+	i = (int) inp(ADDR(B0_CTRL)) ;		/* do dummy read */
+	SK_UNUSED(i) ;				/* Make LINT happy. */
+	outp(ADDR(B0_CTRL), CTRL_RST_CLR) ;
+
+	/*
+	 * Reset all bits in the PCI STATUS register
+	 */
+	outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ;	/* enable for writes */
+	word = inpw(PCI_C(PCI_STATUS)) ;
+	outpw(PCI_C(PCI_STATUS), word | PCI_ERRBITS) ;
+	outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ;	/* disable writes */
+
+	/*
+	 * Release the reset of all the State machines
+	 * Release Master_Reset
+	 * Release HPI_SM_Reset
+	 */
+	outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ;
+
+	/*
+	 * determine the adapter type
+	 * Note: Do it here, because some drivers may call card_start() once
+	 *	 at very first before any other initialization functions is
+	 *	 executed.
+	 */
+	rev_id = inp(PCI_C(PCI_REV_ID)) ;
+	if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) {
+		smc->hw.hw_is_64bit = TRUE ;
+	} else {
+		smc->hw.hw_is_64bit = FALSE ;
+	}
+
+	/*
+	 * Watermark initialization
+	 */
+	if (!smc->hw.hw_is_64bit) {
+		outpd(ADDR(B4_R1_F), RX_WATERMARK) ;
+		outpd(ADDR(B5_XA_F), TX_WATERMARK) ;
+		outpd(ADDR(B5_XS_F), TX_WATERMARK) ;
+	}
+
+	outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;	/* clear the reset chips */
+	outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */
+
+	/* init the timer value for the watch dog 2,5 minutes */
+	outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ;
+
+	/* initialize the ISR mask */
+	smc->hw.is_imask = ISR_MASK ;
+	smc->hw.hw_state = STOPPED ;
+#endif
+	GET_PAGE(0) ;		/* necessary for BOOT */
+}
+
+void card_stop(smc)
+struct s_smc *smc ;
+{
+	smt_stop_watchdog(smc) ;
+	smc->hw.mac_ring_is_up = 0 ;		/* ring down */
+#ifdef	ISA
+	outpw(CSR_A,0) ;			/* reset for all chips */
+#endif
+#ifdef	EISA
+	outpw(CSR_A,0) ;			/* reset for all chips */
+#endif
+#ifdef	MCA
+	outp(ADDR(CARD_DIS),0) ;		/* reset for all chips */
+#endif
+#ifdef	PCI
+	/*
+	 * make sure no transfer activity is pending
+	 */
+	outpw(FM_A(FM_MDREG1),FM_MINIT) ;
+	outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
+	hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ;
+	/*
+	 * now reset everything
+	 */
+	outp(ADDR(B0_CTRL),CTRL_RST_SET) ;	/* reset for all chips */
+	outp(ADDR(B0_CTRL),CTRL_RST_CLR) ;	/* reset for all chips */
+	outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */
+	smc->hw.hw_state = STOPPED ;
+#endif
+}
+/*--------------------------- ISR handling ----------------------------------*/
+
+#ifndef PCI
+void mac1_irq(smc,stu, stl)
+struct s_smc *smc ;
+u_short stu;
+u_short stl;
+{
+	int	restart_tx = 0 ;
+again:
+#ifndef ISA
+/*
+ * FORMAC+ bug modified the queue pointer if many read/write accesses happens!?
+ */
+	if (stl & (FM_SPCEPDS  |	/* parit/coding err. syn.q.*/
+		   FM_SPCEPDA0 |	/* parit/coding err. a.q.0 */
+		   FM_SPCEPDA1 |	/* parit/coding err. a.q.1 */
+		   FM_SPCEPDA2)) {	/* parit/coding err. a.q.2 */
+		SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ;
+	}
+	if (stl & (FM_STBURS  |	/* tx buffer underrun syn.q.*/
+		   FM_STBURA0 |	/* tx buffer underrun a.q.0 */
+		   FM_STBURA1 |	/* tx buffer underrun a.q.1 */
+		   FM_STBURA2)) {	/* tx buffer underrun a.q.2 */
+		SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
+	}
+#endif
+	if ( (stu & (FM_SXMTABT |		/* transmit abort */
+#ifdef	SYNC
+		     FM_STXABRS |	/* syn. tx abort */
+#endif	/* SYNC */
+		     FM_STXABRA0)) ||	/* asyn. tx abort */
+	     (stl & (FM_SQLCKS |		/* lock for syn. q. */
+		     FM_SQLCKA0)) ) {	/* lock for asyn. q. */
+		formac_tx_restart(smc) ;		/* init tx */
+		restart_tx = 1 ;
+		stu = inpw(FM_A(FM_ST1U)) ;
+		stl = inpw(FM_A(FM_ST1L)) ;
+		stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
+		if (stu || stl)
+			goto again ;
+	}
+
+#ifndef	SYNC
+	if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */
+		   FM_STEFRMA0)) { /* end of frame asyn tx */
+		/* free tx_queue */
+		smc->hw.n_a_send = 0 ;
+		if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) {
+			start_next_send(smc);
+		}
+		restart_tx = 1 ;
+	}
+#else	/* SYNC */
+	if (stu & (FM_STEFRMA0 |	/* end of asyn tx */
+		    FM_STEFRMS)) {	/* end of sync tx */
+		restart_tx = 1 ;
+	}
+#endif	/* SYNC */
+	if (restart_tx)
+		llc_restart_tx(smc) ;
+}
+#else	/* PCI */
+
+void mac1_irq(smc,stu, stl)
+struct s_smc *smc ;
+u_short stu;
+u_short stl;
+{
+	int	restart_tx = 0 ;
+again:
+
+	/*
+	 * parity error: note encoding error is not possible in tag mode
+	 */
+	if (stl & (FM_SPCEPDS  |	/* parity err. syn.q.*/
+		   FM_SPCEPDA0 |	/* parity err. a.q.0 */
+		   FM_SPCEPDA1)) {	/* parity err. a.q.1 */
+		SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ;
+	}
+	/*
+	 * buffer underrun: can only occur if a tx threshold is specified
+	 */
+	if (stl & (FM_STBURS  |		/* tx buffer underrun syn.q.*/
+		   FM_STBURA0 |		/* tx buffer underrun a.q.0 */
+		   FM_STBURA1)) {	/* tx buffer underrun a.q.2 */
+		SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
+	}
+
+	if ( (stu & (FM_SXMTABT |		/* transmit abort */
+		     FM_STXABRS |		/* syn. tx abort */
+		     FM_STXABRA0)) ||		/* asyn. tx abort */
+	     (stl & (FM_SQLCKS |		/* lock for syn. q. */
+		     FM_SQLCKA0)) ) {		/* lock for asyn. q. */
+		formac_tx_restart(smc) ;	/* init tx */
+		restart_tx = 1 ;
+		stu = inpw(FM_A(FM_ST1U)) ;
+		stl = inpw(FM_A(FM_ST1L)) ;
+		stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
+		if (stu || stl)
+			goto again ;
+	}
+
+	if (stu & (FM_STEFRMA0 |	/* end of asyn tx */
+		    FM_STEFRMS)) {	/* end of sync tx */
+		restart_tx = 1 ;
+	}
+
+	if (restart_tx)
+		llc_restart_tx(smc) ;
+}
+#endif	/* PCI */
+/*
+ * interrupt source= plc1
+ * this function is called in nwfbisr.asm
+ */
+void plc1_irq(smc)
+struct s_smc *smc ;
+{
+	u_short	st = inpw(PLC(PB,PL_INTR_EVENT)) ;
+
+#if	(defined(ISA) || defined(EISA))
+	/* reset PLC Int. bits */
+	outpw(PLC1_I,inpw(PLC1_I)) ;
+#endif
+	plc_irq(smc,PB,st) ;
+}
+
+/*
+ * interrupt source= plc2
+ * this function is called in nwfbisr.asm
+ */
+void plc2_irq(smc)
+struct s_smc *smc ;
+{
+	u_short	st = inpw(PLC(PA,PL_INTR_EVENT)) ;
+
+#if	(defined(ISA) || defined(EISA))
+	/* reset PLC Int. bits */
+	outpw(PLC2_I,inpw(PLC2_I)) ;
+#endif
+	plc_irq(smc,PA,st) ;
+}
+
+
+/*
+ * interrupt source= timer
+ */
+void timer_irq(smc)
+struct s_smc *smc ;
+{
+	hwt_restart(smc);
+	smc->hw.t_stop = smc->hw.t_start;
+	smt_timer_done(smc) ;
+}
+
+/*
+ * return S-port (PA or PB)
+ */
+int pcm_get_s_port(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;
+	return(PS) ;
+}
+
+/*
+ * Station Label = "FDDI-XYZ" where
+ *
+ *	X = connector type
+ *	Y = PMD type
+ *	Z = port type
+ */
+#define STATION_LABEL_CONNECTOR_OFFSET	5
+#define STATION_LABEL_PMD_OFFSET	6
+#define STATION_LABEL_PORT_OFFSET	7
+
+void read_address(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ;
+{
+	char ConnectorType ;
+	char PmdType ;
+	int	i ;
+
+	extern const u_char canonical[256] ;
+
+#if	(defined(ISA) || defined(MCA))
+	for (i = 0; i < 4 ;i++) {	/* read mac address from board */
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ;
+	}
+	for (i = 4; i < 6; i++) {
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ;
+	}
+#endif
+#ifdef	EISA
+	/*
+	 * Note: We get trouble on an Alpha machine if we make a inpw()
+	 * instead of inp()
+	 */
+	for (i = 0; i < 4 ;i++) {	/* read mac address from board */
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[inp(PR_A(i+SA_MAC))] ;
+	}
+	for (i = 4; i < 6; i++) {
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ;
+	}
+#endif
+#ifdef	PCI
+	for (i = 0; i < 6; i++) {	/* read mac address from board */
+		smc->hw.fddi_phys_addr.a[i] =
+			canonical[inp(ADDR(B2_MAC_0+i))] ;
+	}
+#endif
+#ifndef	PCI
+	ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ;
+	PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ;
+#else
+	ConnectorType = inp(ADDR(B2_CONN_TYP)) ;
+	PmdType = inp(ADDR(B2_PMD_TYP)) ;
+#endif
+
+	smc->y[PA].pmd_type[PMD_SK_CONN] =
+	smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ;
+	smc->y[PA].pmd_type[PMD_SK_PMD ] =
+	smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ;
+
+	if (mac_addr) {
+		for (i = 0; i < 6 ;i++) {
+			smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
+			smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ;
+		}
+		return ;
+	}
+	smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ;
+
+	for (i = 0; i < 6 ;i++) {
+		smc->hw.fddi_canon_addr.a[i] =
+			canonical[smc->hw.fddi_phys_addr.a[i]] ;
+	}
+}
+
+/*
+ * FDDI card soft reset
+ */
+void init_board(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ;
+{
+	card_start(smc) ;
+	read_address(smc,mac_addr) ;
+
+#ifndef	PCI
+	if (inpw(CSR_A) & CS_SAS)
+#else
+	if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL))
+#endif
+		smc->s.sas = SMT_SAS ;	/* Single att. station */
+	else
+		smc->s.sas = SMT_DAS ;	/* Dual att. station */
+
+#ifndef	PCI
+	if (inpw(CSR_A) & CS_BYSTAT)
+#else
+	if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST))
+#endif
+		smc->mib.fddiSMTBypassPresent = 0 ;
+		/* without opt. bypass */
+	else
+		smc->mib.fddiSMTBypassPresent = 1 ;
+		/* with opt. bypass */
+}
+
+/*
+ * insert or deinsert optical bypass (called by ECM)
+ */
+void sm_pm_bypass_req(smc,mode)
+struct s_smc *smc ;
+int mode;
+{
+#if	(defined(ISA) || defined(EISA))
+	int csra_v ;
+#endif
+
+	DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ?
+					"BP_INSERT" : "BP_DEINSERT",0) ;
+
+	if (smc->s.sas != SMT_DAS)
+		return ;
+
+#if	(defined(ISA) || defined(EISA))
+
+	csra_v = inpw(CSR_A) & ~CS_BYPASS ;
+#ifdef	EISA
+	csra_v |= smc->hw.led ;
+#endif
+
+	switch(mode) {
+	case BP_INSERT :
+		outpw(CSR_A,csra_v | CS_BYPASS) ;
+		break ;
+	case BP_DEINSERT :
+		outpw(CSR_A,csra_v) ;
+		break ;
+	}
+#endif	/* ISA / EISA */
+#ifdef	MCA
+	switch(mode) {
+	case BP_INSERT :
+		outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
+		break ;
+	case BP_DEINSERT :
+		outp(ADDR(BYPASS(STAT_BYP)),0) ;	/* bypass station */
+		break ;
+	}
+#endif
+#ifdef	PCI
+	switch(mode) {
+	case BP_INSERT :
+		outp(ADDR(B0_DAS),DAS_BYP_INS) ;	/* insert station */
+		break ;
+	case BP_DEINSERT :
+		outp(ADDR(B0_DAS),DAS_BYP_RMV) ;	/* bypass station */
+		break ;
+	}
+#endif
+}
+
+/*
+ * check if bypass connected
+ */
+int sm_pm_bypass_present(smc)
+struct s_smc *smc ;
+{
+#ifndef	PCI
+	return(	(inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ;
+#else
+	return(	(inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ;
+#endif
+}
+
+void plc_clear_irq(smc,p)
+struct s_smc *smc ;
+int p ;
+{
+	SK_UNUSED(p) ;
+
+#if	(defined(ISA) || defined(EISA))
+	switch (p) {
+	case PA :
+		/* reset PLC Int. bits */
+		outpw(PLC2_I,inpw(PLC2_I)) ;
+		break ;
+	case PB :
+		/* reset PLC Int. bits */
+		outpw(PLC1_I,inpw(PLC1_I)) ;
+		break ;
+	}
+#else
+	SK_UNUSED(smc) ;
+#endif
+}
+
+
+/*
+ * led_indication called by rmt_indication() and
+ * pcm_state_change()
+ *
+ * Input:
+ *	smc:	SMT context
+ *	led_event:
+ *	0	Only switch green LEDs according to their respective PCM state
+ *	LED_Y_OFF	just switch yellow LED off
+ *	LED_Y_ON	just switch yello LED on
+ */
+void led_indication(smc,led_event)
+struct s_smc	*smc ;
+int		led_event;
+{
+	/* use smc->hw.mac_ring_is_up == TRUE 
+	 * as indication for Ring Operational
+	 */
+	u_short			led_state ;
+	struct s_phy		*phy ;
+	struct fddi_mib_p	*mib_a ;
+	struct fddi_mib_p	*mib_b ;
+
+	phy = &smc->y[PA] ;
+	mib_a = phy->mib ;
+	phy = &smc->y[PB] ;
+	mib_b = phy->mib ;
+
+#ifdef	EISA
+	/* Ring up = yellow led OFF*/
+	if (led_event == LED_Y_ON) {
+		smc->hw.led |= CS_LED_1 ;
+	}
+	else if (led_event == LED_Y_OFF) {
+		smc->hw.led &= ~CS_LED_1 ;
+	}
+	else {
+		/* Link at Port A or B = green led ON */
+		if (mib_a->fddiPORTPCMState == PC8_ACTIVE ||
+		    mib_b->fddiPORTPCMState == PC8_ACTIVE) {
+			smc->hw.led |= CS_LED_0 ;
+		}
+		else {
+			smc->hw.led &= ~CS_LED_0 ;
+		}
+	}
+#endif
+#ifdef	MCA
+	led_state = inpw(LEDR_A) ;
+	
+	/* Ring up = yellow led OFF*/
+	if (led_event == LED_Y_ON) {
+		led_state |= LED_1 ;
+	}
+	else if (led_event == LED_Y_OFF) {
+		led_state &= ~LED_1 ;
+	}
+	else {
+                led_state &= ~(LED_2|LED_0) ;
+
+		/* Link at Port A = green led A ON */
+		if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {	
+			led_state |= LED_2 ;
+		}
+		
+		/* Link at Port B/S = green led B ON */
+		if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
+			led_state |= LED_0 ;
+		}
+	}
+
+        outpw(LEDR_A, led_state) ;
+#endif	/* MCA */
+#ifdef	PCI
+        led_state = 0 ;
+	
+	/* Ring up = yellow led OFF*/
+	if (led_event == LED_Y_ON) {
+		led_state |= LED_MY_ON ;
+	}
+	else if (led_event == LED_Y_OFF) {
+		led_state |= LED_MY_OFF ;
+	}
+	else {	/* PCM state changed */
+		/* Link at Port A/S = green led A ON */
+		if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {	
+			led_state |= LED_GA_ON ;
+		}
+		else {
+			led_state |= LED_GA_OFF ;
+		}
+		
+		/* Link at Port B = green led B ON */
+		if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
+			led_state |= LED_GB_ON ;
+		}
+		else {
+			led_state |= LED_GB_OFF ;
+		}
+	}
+
+        outp(ADDR(B0_LED), led_state) ;
+#endif	/* PCI */
+
+}
+
+
+void pcm_state_change(smc,plc,p_state)
+struct s_smc *smc;
+int plc;
+int p_state;
+{
+	/*
+	 * the current implementation of pcm_state_change() in the driver
+	 * parts must be renamed to drv_pcm_state_change() which will be called
+	 * now after led_indication.
+	 */
+	DRV_PCM_STATE_CHANGE(smc,plc,p_state) ;
+	
+	led_indication(smc,0) ;
+}
+
+
+void rmt_indication(smc,i)
+struct s_smc *smc ;
+int i;
+{
+	/* Call a driver special function if defined */
+	DRV_RMT_INDICATION(smc,i) ;
+
+        led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ;
+}
+
+
+/*
+ * llc_recover_tx called by init_tx (fplus.c)
+ */
+void llc_recover_tx(smc)
+struct s_smc *smc ;
+{
+#ifdef	LOAD_GEN
+	extern	int load_gen_flag ;
+
+	load_gen_flag = 0 ;
+#endif
+#ifndef	SYNC
+	smc->hw.n_a_send= 0 ;
+#else
+	SK_UNUSED(smc) ;
+#endif
+}
+
+/*--------------------------- DMA init ----------------------------*/
+#ifdef	ISA
+
+/*
+ * init DMA
+ */
+void init_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+
+	/*
+	 * set cascade mode,
+	 * clear mask bit (enable DMA cannal)
+	 */
+	if (dma > 3) {
+		outp(0xd6,(dma & 0x03) | 0xc0) ;
+		outp(0xd4, dma & 0x03) ;
+	}
+	else {
+		outp(0x0b,(dma & 0x03) | 0xc0) ;
+		outp(0x0a,dma & 0x03) ;
+	}
+}
+
+/*
+ * disable DMA
+ */
+void dis_dma(smc,dma)
+struct s_smc *smc ;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+
+	/*
+	 * set mask bit (disable DMA cannal)
+	 */
+	if (dma > 3) {
+		outp(0xd4,(dma & 0x03) | 0x04) ;
+	}
+	else {
+		outp(0x0a,(dma & 0x03) | 0x04) ;
+	}
+}
+
+#endif	/* ISA */
+
+#ifdef	EISA
+
+/*arrays with io adresses of dma controller length and adress registers*/
+static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ;
+static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ;
+static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ;
+
+void init_dma(smc,dma)
+struct s_smc *smc ;
+int	dma;
+{
+	/*
+	 * extended mode register
+	 * 32 bit IO
+	 * type c
+	 * TC output
+	 * disable stop
+	 */
+
+	/* mode read (write) demand */
+	smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ;
+	smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ;
+
+	/* 32 bit IO's, burst DMA mode (type "C") */
+	smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ;
+
+	outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ;
+
+	/* disable chaining */
+	outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ;
+
+	/*load dma controller addresses for fast access during set dma*/
+	smc->hw.dma_base_word_count = cntr[smc->hw.dma];
+	smc->hw.dma_base_address = base[smc->hw.dma];
+	smc->hw.dma_base_address_page = page[smc->hw.dma];
+
+}
+
+void dis_dma(smc,dma)
+struct s_smc *smc ;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+
+	outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */
+}
+#endif	/* EISA */
+
+#ifdef	MCA
+void init_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dma) ;
+}
+void dis_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dma) ;
+}
+#endif
+
+#ifdef	PCI
+void init_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dma) ;
+}
+void dis_dma(smc,dma)
+struct s_smc *smc;
+int	dma;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dma) ;
+}
+#endif
+
+#ifdef MULT_OEM
+static int is_equal_num(comp1,comp2,num)
+char comp1[] ;
+char comp2[] ;
+int num ;
+{
+	int i ;
+
+	for (i = 0 ; i < num ; i++) {
+		if (comp1[i] != comp2[i])
+			return (0) ;
+	}
+		return (1) ;
+}	/* is_equal_num */
+
+
+/*
+ * set the OEM ID defaults, and test the contents of the OEM data base
+ * The default OEM is the first ACTIVE entry in the OEM data base 
+ *
+ * returns:	0	success
+ *		1	error in data base
+ *		2	data base empty
+ *		3	no active entry	
+ */
+int set_oi_id_def(smc)
+struct s_smc *smc ;
+{
+	int sel_id ;
+	int i ;
+	int act_entries ;
+
+	i = 0 ;
+	sel_id = -1 ;
+	act_entries = FALSE ;
+	smc->hw.oem_id = 0 ;
+	smc->hw.oem_min_status = OI_STAT_ACTIVE ;
+	
+	/* check OEM data base */
+	while (oem_ids[i].oi_status) {
+		switch (oem_ids[i].oi_status) {
+		case OI_STAT_ACTIVE:
+			act_entries = TRUE ;	/* we have active IDs */
+			if (sel_id == -1)
+				sel_id = i ;	/* save the first active ID */
+		case OI_STAT_VALID:
+		case OI_STAT_PRESENT:
+			i++ ;
+			break ;			/* entry ok */
+		default:
+			return (1) ;		/* invalid oi_status */
+		}
+	}
+
+	if (i == 0)
+		return (2) ;
+	if (!act_entries)
+		return (3) ;
+
+	/* ok, we have a valid OEM data base with an active entry */
+	smc->hw.oem_id = (struct s_oem_ids *)  &oem_ids[sel_id] ;
+	return (0) ;
+}
+#endif	/* MULT_OEM */
+
+
+#ifdef	MCA
+/************************
+ *
+ * BEGIN_MANUAL_ENTRY()
+ *
+ *	exist_board
+ *
+ *	Check if an MCA board is present in the specified slot.
+ *
+ *	int exist_board(
+ *		struct s_smc *smc,
+ *		int slot) ;
+ * In
+ *	smc - A pointer to the SMT Context struct.
+ *
+ *	slot - The number of the slot to inspect.
+ * Out
+ *	0 = No adapter present.
+ *	1 = Found FM1 adapter.
+ *
+ * Pseudo
+ *      Read MCA ID
+ *	for all valid OEM_IDs
+ *		compare with ID read
+ *		if equal, return 1
+ *	return(0
+ *
+ * Note
+ *	The smc pointer must be valid now.
+ *
+ * END_MANUAL_ENTRY()
+ *
+ ************************/
+#define LONG_CARD_ID(lo, hi)	((((hi) & 0xff) << 8) | ((lo) & 0xff))
+int exist_board(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+#ifdef MULT_OEM
+	SK_LOC_DECL(u_char,id[2]) ;
+	int idi ;
+#endif	/* MULT_OEM */
+
+	/* No longer valid. */
+	if (smc == NULL)
+		return(0) ;
+
+#ifndef MULT_OEM
+	if (read_card_id(smc, slot)
+		== LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1)))
+		return (1) ;	/* Found FM adapter. */
+
+#else	/* MULT_OEM */
+	idi = read_card_id(smc, slot) ;
+	id[0] = idi & 0xff ;
+	id[1] = idi >> 8 ;
+
+        smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+			continue ;
+
+		if (is_equal_num(&id[0],&OEMID(smc,0),2))
+			return (1) ;
+	}
+#endif	/* MULT_OEM */
+	return (0) ;	/* No adapter found. */
+}
+
+/************************
+ *
+ *	read_card_id
+ *
+ *	Read the MCA card id from the specified slot.
+ * In
+ *	smc - A pointer to the SMT Context struct.
+ *	CAVEAT: This pointer may be NULL and *must not* be used within this
+ *	function. It's only purpose is for drivers that need some information
+ *	for the inp() and outp() macros.
+ *
+ *	slot - The number of the slot for which the card id is returned.
+ * Out
+ *	Returns the card id read from the specified slot. If an illegal slot
+ *	number is specified, the function returns zero.
+ *
+ ************************/
+static int read_card_id(smc,slot)
+struct s_smc *smc ;	/* Do not use. */
+int slot ;
+{
+	int card_id ;
+
+	SK_UNUSED(smc) ;	/* Make LINT happy. */
+	if ((slot < 1) || (slot > 15))	/* max 16 slots, 0 = motherboard */
+		return (0) ;	/* Illegal slot number specified. */
+
+	EnableSlotAccess(smc, slot) ;
+
+	card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) |
+				(read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ;
+
+	DisableSlotAccess(smc) ;
+
+	return (card_id) ;
+}
+
+/************************
+ *
+ * BEGIN_MANUAL_ENTRY()
+ *
+ *	get_board_para
+ *
+ *	Get adapter configuration information. Fill all board specific
+ *	parameters within the 'smc' structure.
+ *
+ *	int get_board_para(
+ *		struct s_smc *smc,
+ *		int slot) ;
+ * In
+ *	smc - A pointer to the SMT Context struct, to which this function will
+ *	write some adapter configuration data.
+ *
+ *	slot - The number of the slot, in which the adapter is installed.
+ * Out
+ *	0 = No adapter present.
+ *	1 = Ok.
+ *	2 = Adapter present, but card enable bit not set.
+ *
+ * END_MANUAL_ENTRY()
+ *
+ ************************/
+int get_board_para(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+	int val ;
+	int i ;
+
+	/* Check if adapter present & get type of adapter. */
+	switch (exist_board(smc, slot)) {
+	case 0:	/* Adapter not present. */
+		return (0) ;
+	case 1:	/* FM Rev. 1 */
+		smc->hw.rev = FM1_REV ;
+		smc->hw.VFullRead = 0x0a ;
+		smc->hw.VFullWrite = 0x05 ;
+		smc->hw.DmaWriteExtraBytes = 8 ;	/* 2 extra words. */
+		break ;
+	}
+	smc->hw.slot = slot ;
+
+	EnableSlotAccess(smc, slot) ;
+
+	if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) {
+		DisableSlotAccess(smc) ;
+		return (2) ;	/* Card enable bit not set. */
+	}
+
+	val = read_POS(smc,POS_104, slot - 1) ;	/* I/O, IRQ */
+
+#ifndef MEM_MAPPED_IO	/* is defined by the operating system */
+	i = val & POS_IOSEL ;	/* I/O base addr. (0x0200 .. 0xfe00) */
+	smc->hw.iop = (i + 1) * 0x0400 - 0x200 ;
+#endif
+	i = ((val & POS_IRQSEL) >> 6) & 0x03 ;	/* IRQ <0, 1> */
+	smc->hw.irq = opt_ints[i] ;
+
+	/* FPROM base addr. */
+	i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ;
+	smc->hw.eprom = opt_eproms[i] ;
+
+	DisableSlotAccess(smc) ;
+
+	/* before this, the smc->hw.iop must be set !!! */
+	smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ;
+
+	return (1) ;
+}
+
+/* Enable access to specified MCA slot. */
+static void EnableSlotAccess(smc,slot)
+struct s_smc *smc ;
+int slot ;
+{
+	SK_UNUSED(slot) ;
+
+#ifndef AIX
+	SK_UNUSED(smc) ;
+
+	/* System mode. */
+	outp(POS_SYS_SETUP, POS_SYSTEM) ;
+
+	/* Select slot. */
+	outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ;
+#else
+	attach_POS_addr (smc) ;
+#endif
+}
+
+/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */
+static void DisableSlotAccess(smc)
+struct s_smc *smc ;
+{
+#ifndef AIX
+	SK_UNUSED(smc) ;
+
+	outp(POS_CHANNEL_POS, 0) ;
+#else
+	detach_POS_addr (smc) ;
+#endif
+}
+#endif	/* MCA */
+
+#ifdef	EISA
+#ifndef	MEM_MAPPED_IO
+#define	SADDR(slot)	(((slot)<<12)&0xf000)
+#else	/* MEM_MAPPED_IO */
+#define	SADDR(slot)	(smc->hw.iop)
+#endif	/* MEM_MAPPED_IO */
+
+/************************
+ *
+ * BEGIN_MANUAL_ENTRY()
+ *
+ *	exist_board
+ *
+ *	Check if an EISA board is present in the specified slot.
+ *
+ *	int exist_board(
+ *		struct s_smc *smc,
+ *		int slot) ;
+ * In
+ *	smc - A pointer to the SMT Context struct.
+ *
+ *	slot - The number of the slot to inspect.
+ * Out
+ *	0 = No adapter present.
+ *	1 = Found adapter.
+ *
+ * Pseudo
+ *      Read EISA ID
+ *	for all valid OEM_IDs
+ *		compare with ID read
+ *		if equal, return 1
+ *	return(0
+ *
+ * Note
+ *	The smc pointer must be valid now.
+ *
+ ************************/
+int exist_board(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+	int i ;
+#ifdef MULT_OEM
+	SK_LOC_DECL(u_char,id[4]) ;
+#endif	/* MULT_OEM */
+
+	/* No longer valid. */
+	if (smc == NULL)
+		return(0);
+
+	SK_UNUSED(slot) ;
+
+#ifndef MULT_OEM
+	for (i = 0 ; i < 4 ; i++) {
+		if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i))
+			return(0) ;
+	}
+	return(1) ;
+#else	/* MULT_OEM */
+	for (i = 0 ; i < 4 ; i++)
+		id[i] = inp(SADDR(slot)+PRA(i)) ;
+
+	smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+
+	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+			continue ;
+
+		if (is_equal_num(&id[0],&OEMID(smc,0),4))
+			return (1) ;
+	}
+	return (0) ;	/* No adapter found. */
+#endif	/* MULT_OEM */
+}
+
+
+int get_board_para(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+	int	i ;
+
+	if (!exist_board(smc,slot))
+		return(0) ;
+
+	smc->hw.slot = slot ;
+#ifndef	MEM_MAPPED_IO		/* if defined by the operating system */
+	smc->hw.iop = SADDR(slot) ;
+#endif
+
+	if (!(inp(C0_A(0))&CFG_CARD_EN)) {
+		return(2) ;			/* CFG_CARD_EN bit not set! */
+	}
+
+	smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ;
+	smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ;
+
+	if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f)
+		smc->hw.eprom = opt_eproms[i] ;
+	else
+		smc->hw.eprom = 0 ;
+
+	smc->hw.DmaWriteExtraBytes = 8 ;
+
+	return(1) ;
+}
+#endif	/* EISA */
+
+#ifdef	ISA
+#ifndef MULT_OEM
+const u_char sklogo[6] = SKLOGO_STR ;
+#define	SIZE_SKLOGO(smc)	sizeof(sklogo)
+#define	SKLOGO(smc,i)		sklogo[i]
+#else	/* MULT_OEM */
+#define	SIZE_SKLOGO(smc)	smc->hw.oem_id->oi_logo_len
+#define	SKLOGO(smc,i)		smc->hw.oem_id->oi_logo[i]
+#endif	/* MULT_OEM */
+
+
+int exist_board(smc,port)
+struct s_smc *smc ;
+HW_PTR	port ;
+{
+	int	i ;
+#ifdef MULT_OEM
+	int	bytes_read ;
+	u_char	board_logo[15] ;
+	SK_LOC_DECL(u_char,id[4]) ;
+#endif	/* MULT_OEM */
+
+	/* No longer valid. */
+	if (smc == NULL)
+		return(0);
+
+	SK_UNUSED(smc) ;
+#ifndef MULT_OEM
+	for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) {
+		if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) {
+			return(0) ;
+		}
+	}
+
+	/* check MAC address (S&K or other) */
+	for (i = 0 ; i < 3 ; i++) {
+		if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i))
+			return(0) ;
+	}
+	return(1) ;
+#else	/* MULT_OEM */
+        smc->hw.oem_id = (struct s_oem_ids *)  &oem_ids[0] ;
+	board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ;
+	bytes_read = 1 ;
+
+	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+			continue ;
+
+		/* Test all read bytes with current OEM_entry */
+		/* for (i=0; (i<bytes_read) && (i < SIZE_SKLOGO(smc)); i++) { */
+		for (i = 0; i < bytes_read; i++) {
+			if (board_logo[i] != SKLOGO(smc,i))
+				break ;
+		}
+
+		/* If mismatch, switch to next OEM entry */
+		if ((board_logo[i] != SKLOGO(smc,i)) && (i < bytes_read))
+			continue ;
+
+		--i ;
+		while (bytes_read < SIZE_SKLOGO(smc)) {
+			//   inpw next byte SK_Logo
+			i++ ;
+			board_logo[i] = (u_char)inpw((PRA(SADDRL+i)+port)) ;
+			bytes_read++ ;
+			if (board_logo[i] != SKLOGO(smc,i))
+				break ;
+		}
+
+		for (i = 0 ; i < 3 ; i++)
+			id[i] = (u_char)inpw((PRA(i)+port)) ;
+
+		if ((board_logo[i] == SKLOGO(smc,i))
+			&& (bytes_read == SIZE_SKLOGO(smc))) {
+
+			if (is_equal_num(&id[0],&OEMID(smc,0),3))
+				return(1);
+		}
+	}	/* for */
+	return(0) ;
+#endif	/* MULT_OEM */
+}
+
+int get_board_para(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(slot) ;
+	return(0) ;	/* for ISA not supported */
+}
+#endif	/* ISA */
+
+#ifdef PCI
+#ifdef USE_BIOS_FUN
+int exist_board(smc,slot)
+struct s_smc *smc ;
+int	slot ;
+{
+	u_short dev_id ;
+	u_short ven_id ;
+	int found ; 
+	int i ;
+
+	found = FALSE ;		/* make sure we returned with adatper not found*/
+				/* if an empty oemids.h was included */
+
+#ifdef MULT_OEM
+        smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
+	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
+		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
+			continue ;
+#endif
+		ven_id = OEMID(smc,0) + (OEMID(smc,1) << 8) ; 
+		dev_id = OEMID(smc,2) + (OEMID(smc,3) << 8) ; 
+		for (i = 0; i < slot; i++) {
+			if (pci_find_device(i,&smc->hw.pci_handle,
+				dev_id,ven_id) != 0) {
+
+				found = FALSE ;
+			} else {
+				found = TRUE ;
+			}
+		}
+		if (found) {
+			return(1) ;	/* adapter was found */
+		}
+#ifdef MULT_OEM
+	}
+#endif
+	return(0) ;	/* adapter was not found */
+}
+#endif	/* PCI */
+#endif	/* USE_BIOS_FUNC */
+
+void driver_get_bia(smc, bia_addr)
+struct s_smc *smc ;
+struct fddi_addr *bia_addr ;
+{
+	int i ;
+
+	extern const u_char canonical[256] ;
+
+	for (i = 0 ; i < 6 ; i++) {
+		bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ;
+	}
+}
+
+void smt_start_watchdog(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;	/* Make LINT happy. */
+
+#ifndef	DEBUG
+
+#ifdef	PCI
+	if (smc->hw.wdog_used) {
+		outpw(ADDR(B2_WDOG_CRTL),TIM_START) ;	/* Start timer. */
+	}
+#endif
+
+#endif	/* DEBUG */
+}
+
+void smt_stop_watchdog(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;	/* Make LINT happy. */
+#ifndef	DEBUG
+
+#ifdef	PCI
+	if (smc->hw.wdog_used) {
+		outpw(ADDR(B2_WDOG_CRTL),TIM_STOP) ;	/* Stop timer. */
+	}
+#endif
+
+#endif	/* DEBUG */
+}
+
+#ifdef	PCI
+static char get_rom_byte(smc,addr)
+struct s_smc *smc ;
+u_short	addr ;
+{
+	GET_PAGE(addr) ;
+	return (READ_PROM(ADDR(B2_FDP))) ;
+}
+
+/*
+ * ROM image defines
+ */
+#define	ROM_SIG_1	0
+#define ROM_SIG_2	1
+#define PCI_DATA_1	0x18
+#define PCI_DATA_2	0x19
+
+/*
+ * PCI data structure defines
+ */
+#define	VPD_DATA_1	0x08
+#define	VPD_DATA_2	0x09
+#define IMAGE_LEN_1	0x10
+#define IMAGE_LEN_2	0x11
+#define	CODE_TYPE	0x14
+#define	INDICATOR	0x15
+
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_vpd_read)
+ *	mac_drv_vpd_read(smc,buf,size,image)
+ *
+ * function	DOWNCALL	(FDDIWARE)
+ *		reads the VPD data of the FPROM and writes it into the
+ *		buffer
+ *
+ * para	buf	points to the buffer for the VPD data
+ *	size	size of the VPD data buffer
+ *	image	boot image; code type of the boot image
+ *		image = 0	Intel x86, PC-AT compatible
+ *			1	OPENBOOT standard for PCI
+ *			2-FF	reserved
+ *
+ * returns	len	number of VPD data bytes read form the FPROM
+ *		<0	number of read bytes
+ *		>0	error: data invalid
+ *
+ *	END_MANUAL_ENTRY
+ */
+int mac_drv_vpd_read(smc,buf,size,image)
+struct s_smc *smc ;
+char *buf ;
+int size ;
+char image ;
+{
+	u_short	ibase ;
+	u_short pci_base ;
+	u_short vpd ;
+	int	len ;
+
+	len = 0 ;
+	ibase = 0 ;
+	/*
+	 * as long images defined
+	 */
+	while (get_rom_byte(smc,ibase+ROM_SIG_1) == 0x55 &&
+		(u_char) get_rom_byte(smc,ibase+ROM_SIG_2) == 0xaa) {
+		/*
+		 * get the pointer to the PCI data structure
+		 */
+		pci_base = ibase + get_rom_byte(smc,ibase+PCI_DATA_1) +
+				(get_rom_byte(smc,ibase+PCI_DATA_2) << 8) ;
+
+		if (image == get_rom_byte(smc,pci_base+CODE_TYPE)) {
+			/*
+			 * we have the right image, read the VPD data
+			 */
+			vpd = ibase + get_rom_byte(smc,pci_base+VPD_DATA_1) +
+				(get_rom_byte(smc,pci_base+VPD_DATA_2) << 8) ;
+			if (vpd == ibase) {
+				break ;		/* no VPD data */
+			}
+			for (len = 0; len < size; len++,buf++,vpd++) {
+				*buf = get_rom_byte(smc,vpd) ;
+			}
+			break ;
+		}
+		else {
+			/*
+			 * try the next image
+			 */
+			if (get_rom_byte(smc,pci_base+INDICATOR) & 0x80) {
+				break ;		/* this was the last image */
+			}
+			ibase = ibase + get_rom_byte(smc,ibase+IMAGE_LEN_1) +
+				(get_rom_byte(smc,ibase+IMAGE_LEN_2) << 8) ;
+		}
+	}
+
+	return(len) ;
+}
+
+void mac_drv_pci_fix(smc,fix_value)
+struct s_smc *smc ;
+u_long fix_value ;
+{
+	smc->hw.pci_fix_value = fix_value ;
+}
+
+void mac_do_pci_fix(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;
+}
+#endif	/* PCI */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/ecm.c linux.18p8/drivers/net/skfp/ecm.c
--- linux.vanilla/drivers/net/skfp/ecm.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/ecm.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,547 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT ECM
+	Entity Coordination Management
+	Hardware independant state machine
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * 		queue_event()
+ * 		smt_timer_start()
+ * 		smt_timer_stop()
+ *
+ * 	The following external HW dependant functions are referenced :
+ * 		sm_pm_bypass_req()
+ * 		sm_pm_ls_latch()
+ * 		sm_pm_get_ls()
+ * 
+ * 	The following HW dependant events are required :
+ *		NONE
+ *
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)ecm.c	2.7 99/08/05 (C) SK " ;
+#endif
+
+/*
+ * FSM Macros
+ */
+#define AFLAG	0x10
+#define GO_STATE(x)	(smc->mib.fddiSMTECMState = (x)|AFLAG)
+#define ACTIONS_DONE()	(smc->mib.fddiSMTECMState &= ~AFLAG)
+#define ACTIONS(x)	(x|AFLAG)
+
+#define EC0_OUT		0			/* not inserted */
+#define EC1_IN		1			/* inserted */
+#define EC2_TRACE	2			/* tracing */
+#define EC3_LEAVE	3			/* leaving the ring */
+#define EC4_PATH_TEST	4			/* performing path test */
+#define EC5_INSERT	5			/* bypass being turned on */
+#define EC6_CHECK	6			/* checking bypass */
+#define EC7_DEINSERT	7			/* bypass being turnde off */
+
+#ifdef	DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const ecm_states[] = {
+	"EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",
+	"EC5_INSERT","EC6_CHECK","EC7_DEINSERT"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const ecm_events[] = {
+	"NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",
+	"EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",
+	"EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"
+} ;
+#endif
+
+/*
+ * all Globals  are defined in smc.h
+ * struct s_ecm
+ */
+
+/*
+ * function declarations
+ */
+
+static void ecm_fsm() ;
+static void start_ecm_timer() ;
+static void stop_ecm_timer() ;
+static void prop_actions() ;
+
+/*
+	init ECM state machine
+	clear all ECM vars and flags
+*/
+void ecm_init(smc)
+struct s_smc *smc ;
+{
+	smc->e.path_test = PT_PASSED ;
+	smc->e.trace_prop = 0 ;
+	smc->e.sb_flag = 0 ;
+	smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;
+	smc->e.ecm_line_state = FALSE ;
+}
+
+/*
+	ECM state machine
+	called by dispatcher
+
+	do
+		display state change
+		process event
+	until SM is stable
+*/
+void ecm(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+	int	state ;
+
+	do {
+		DB_ECM("ECM : state %s%s",
+			(smc->mib.fddiSMTECMState & AFLAG) ? "ACTIONS " : "",
+			ecm_states[smc->mib.fddiSMTECMState & ~AFLAG]) ;
+		DB_ECM(" event %s\n",ecm_events[event],0) ;
+		state = smc->mib.fddiSMTECMState ;
+		ecm_fsm(smc,event) ;
+		event = 0 ;
+	} while (state != smc->mib.fddiSMTECMState) ;
+	ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;
+}
+
+/*
+	process ECM event
+*/
+static void ecm_fsm(smc,cmd)
+struct s_smc *smc ;
+int cmd ;
+{
+	int ls_a ;			/* current line state PHY A */
+	int ls_b ;			/* current line state PHY B */
+	int	p ;			/* ports */
+
+
+	smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;
+	if (cmd == EC_CONNECT)
+		smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
+
+	/* For AIX event notification: */
+	/* Is a disconnect  command remotely issued ? */
+	if (cmd == EC_DISCONNECT &&
+		smc->mib.fddiSMTRemoteDisconnectFlag == TRUE)
+		AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)
+			FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),
+			smt_get_error_word(smc) );
+
+	/*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/
+	if (cmd == EC_CONNECT) {
+		smc->e.DisconnectFlag = FALSE ;
+	}
+	else if (cmd == EC_DISCONNECT) {
+		smc->e.DisconnectFlag = TRUE ;
+	}
+	
+	switch(smc->mib.fddiSMTECMState) {
+	case ACTIONS(EC0_OUT) :
+		/*
+		 * We do not perform a path test
+		 */
+		smc->e.path_test = PT_PASSED ;
+		smc->e.ecm_line_state = FALSE ;
+		stop_ecm_timer(smc) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC0_OUT:
+		/*EC01*/
+		if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent
+			&& smc->e.path_test==PT_PASSED) {
+			GO_STATE(EC1_IN) ;
+			break ;
+		}
+		/*EC05*/
+		else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&
+			smc->mib.fddiSMTBypassPresent &&
+			(smc->s.sas == SMT_DAS)) {
+			GO_STATE(EC5_INSERT) ;
+			break ;
+		}
+		break;
+	case ACTIONS(EC1_IN) :
+		stop_ecm_timer(smc) ;
+		smc->e.trace_prop = 0 ;
+		sm_ma_control(smc,MA_TREQ) ;
+		for (p = 0 ; p < NUMPHYS ; p++)
+			if (smc->mib.p[p].fddiPORTHardwarePresent)
+				queue_event(smc,EVENT_PCMA+p,PC_START) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC1_IN:
+		/*EC12*/
+		if (cmd == EC_TRACE_PROP) {
+			prop_actions(smc) ;
+			GO_STATE(EC2_TRACE) ;
+			break ;
+		}
+		/*EC13*/
+		else if (cmd == EC_DISCONNECT) {
+			GO_STATE(EC3_LEAVE) ;
+			break ;
+		}
+		break;
+	case ACTIONS(EC2_TRACE) :
+		start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),
+			EC_TIMEOUT_TMAX) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC2_TRACE :
+		/*EC22*/
+		if (cmd == EC_TRACE_PROP) {
+			prop_actions(smc) ;
+			GO_STATE(EC2_TRACE) ;
+			break ;
+		}
+		/*EC23a*/
+		else if (cmd == EC_DISCONNECT) {
+			smc->e.path_test = PT_EXITING ;
+			GO_STATE(EC3_LEAVE) ;
+			break ;
+		}
+		/*EC23b*/
+		else if (smc->e.path_test == PT_PENDING) {
+			GO_STATE(EC3_LEAVE) ;
+			break ;
+		}
+		/*EC23c*/
+		else if (cmd == EC_TIMEOUT_TMAX) {
+			/* Trace_Max is expired */
+			/* -> send AIX_EVENT */
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
+				(u_long) FDDI_SMT_ERROR, (u_long)
+				FDDI_TRACE_MAX, smt_get_error_word(smc));
+			smc->e.path_test = PT_PENDING ;
+			GO_STATE(EC3_LEAVE) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(EC3_LEAVE) :
+		start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;
+		for (p = 0 ; p < NUMPHYS ; p++)
+			queue_event(smc,EVENT_PCMA+p,PC_STOP) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC3_LEAVE:
+		/*EC30*/
+		if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&
+			(smc->e.path_test != PT_PENDING)) {
+			GO_STATE(EC0_OUT) ;
+			break ;
+		}
+		/*EC34*/
+		else if (cmd == EC_TIMEOUT_TD &&
+			(smc->e.path_test == PT_PENDING)) {
+			GO_STATE(EC4_PATH_TEST) ;
+			break ;
+		}
+		/*EC31*/
+		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
+			GO_STATE(EC1_IN) ;
+			break ;
+		}
+		/*EC33*/
+		else if (cmd == EC_DISCONNECT &&
+			smc->e.path_test == PT_PENDING) {
+			smc->e.path_test = PT_EXITING ;
+			/*
+			 * stay in state - state will be left via timeout
+			 */
+		}
+		/*EC37*/
+		else if (cmd == EC_TIMEOUT_TD &&
+			smc->mib.fddiSMTBypassPresent &&
+			smc->e.path_test != PT_PENDING) {
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(EC4_PATH_TEST) :
+		stop_ecm_timer(smc) ;
+		smc->e.path_test = PT_TESTING ;
+		start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;
+		/* now perform path test ... just a simulation */
+		ACTIONS_DONE() ;
+		break ;
+	case EC4_PATH_TEST :
+		/* path test done delay */
+		if (cmd == EC_TEST_DONE)
+			smc->e.path_test = PT_PASSED ;
+
+		if (smc->e.path_test == PT_FAILED)
+			RS_SET(smc,RS_PATHTEST) ;
+
+		/*EC40a*/
+		if (smc->e.path_test == PT_FAILED &&
+			!smc->mib.fddiSMTBypassPresent) {
+			GO_STATE(EC0_OUT) ;
+			break ;
+		}
+		/*EC40b*/
+		else if (cmd == EC_DISCONNECT &&
+			!smc->mib.fddiSMTBypassPresent) {
+			GO_STATE(EC0_OUT) ;
+			break ;
+		}
+		/*EC41*/
+		else if (smc->e.path_test == PT_PASSED) {
+			GO_STATE(EC1_IN) ;
+			break ;
+		}
+		/*EC47a*/
+		else if (smc->e.path_test == PT_FAILED &&
+			smc->mib.fddiSMTBypassPresent) {
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		/*EC47b*/
+		else if (cmd == EC_DISCONNECT &&
+			smc->mib.fddiSMTBypassPresent) {
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(EC5_INSERT) :
+		sm_pm_bypass_req(smc,BP_INSERT);
+		start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC5_INSERT :
+		/*EC56*/
+		if (cmd == EC_TIMEOUT_INMAX) {
+			GO_STATE(EC6_CHECK) ;
+			break ;
+		}
+		/*EC57*/
+		else if (cmd == EC_DISCONNECT) {
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(EC6_CHECK) :
+		/*
+		 * in EC6_CHECK, we *POLL* the line state !
+		 * check whether both bypass switches have switched.
+		 */
+		start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
+		smc->e.ecm_line_state = TRUE ;	/* flag to pcm: report Q/HLS */
+		(void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */
+		(void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */
+		ACTIONS_DONE() ;
+		break ;
+	case EC6_CHECK :
+		ls_a = sm_pm_get_ls(smc,PA) ;
+		ls_b = sm_pm_get_ls(smc,PB) ;
+
+		/*EC61*/
+		if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&
+		    ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {
+			smc->e.sb_flag = FALSE ;
+			smc->e.ecm_line_state = FALSE ;
+			GO_STATE(EC1_IN) ;
+			break ;
+		}
+		/*EC66*/
+		else if (!smc->e.sb_flag &&
+			 (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||
+			  ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){
+			smc->e.sb_flag = TRUE ;
+			DB_ECMN(1,"ECM : EC6_CHECK - stuck bypass\n",0,0) ;
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,
+				smt_get_error_word(smc));
+		}
+		/*EC67*/
+		else if (cmd == EC_DISCONNECT) {
+			smc->e.ecm_line_state = FALSE ;
+			GO_STATE(EC7_DEINSERT) ;
+			break ;
+		}
+		else {
+			/*
+			 * restart poll
+			 */
+			start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
+		}
+		break ;
+	case ACTIONS(EC7_DEINSERT) :
+		sm_pm_bypass_req(smc,BP_DEINSERT);
+		start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;
+		ACTIONS_DONE() ;
+		break ;
+	case EC7_DEINSERT:
+		/*EC70*/
+		if (cmd == EC_TIMEOUT_IMAX) {
+			GO_STATE(EC0_OUT) ;
+			break ;
+		}
+		/*EC75*/
+		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
+			GO_STATE(EC5_INSERT) ;
+			break ;
+		}
+		break;
+	default:
+		SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;
+		break;
+	}
+}
+
+#ifndef	CONCENTRATOR
+/*
+ * trace propagation actions for SAS & DAS
+ */
+static void prop_actions(smc)
+struct s_smc *smc ;
+{
+	int	port_in = 0 ;
+	int	port_out = 0 ;
+
+	RS_SET(smc,RS_EVENT) ;
+	switch (smc->s.sas) {
+	case SMT_SAS :
+		port_in = port_out = pcm_get_s_port(smc) ;
+		break ;
+	case SMT_DAS :
+		port_in = cfm_get_mac_input(smc) ;	/* PA or PB */
+		port_out = cfm_get_mac_output(smc) ;	/* PA or PB */
+		break ;
+	case SMT_NAC :
+		SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;
+		return ;
+	}
+
+	DB_ECM("ECM : prop_actions - trace_prop %d\n", smc->e.trace_prop,0) ;
+	DB_ECM("ECM : prop_actions - in %d out %d\n", port_in,port_out) ;
+
+	if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
+		/* trace initiatior */
+		DB_ECM("ECM : initiate TRACE on PHY %c\n",'A'+port_in-PA,0) ;
+		queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;
+	}
+	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&
+		port_out != PA) {
+		/* trace propagate upstream */
+		DB_ECM("ECM : propagate TRACE on PHY B\n",0,0) ;
+		queue_event(smc,EVENT_PCMB,PC_TRACE) ;
+	}
+	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&
+		port_out != PB) {
+		/* trace propagate upstream */
+		DB_ECM("ECM : propagate TRACE on PHY A\n",0,0) ;
+		queue_event(smc,EVENT_PCMA,PC_TRACE) ;
+	}
+	else {
+		/* signal trace termination */
+		DB_ECM("ECM : TRACE terminated\n",0,0) ;
+		smc->e.path_test = PT_PENDING ;
+	}
+	smc->e.trace_prop = 0 ;
+}
+#else
+/*
+ * trace propagation actions for Concentrator
+ */
+static void prop_actions(smc)
+struct s_smc *smc ;
+{
+	int	initiator ;
+	int	upstream ;
+	int	p ;
+
+	RS_SET(smc,RS_EVENT) ;
+	while (smc->e.trace_prop) {
+		DB_ECM("ECM : prop_actions - trace_prop %d\n",
+			smc->e.trace_prop,0) ;
+
+		if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
+			initiator = ENTITY_MAC ;
+			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;
+			DB_ECM("ECM: MAC initiates trace\n",0,0) ;
+		}
+		else {
+			for (p = NUMPHYS-1 ; p >= 0 ; p--) {
+				if (smc->e.trace_prop &
+					ENTITY_BIT(ENTITY_PHY(p)))
+					break ;
+			}
+			initiator = ENTITY_PHY(p) ;
+			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;
+		}
+		upstream = cem_get_upstream(smc,initiator) ;
+
+		if (upstream == ENTITY_MAC) {
+			/* signal trace termination */
+			DB_ECM("ECM : TRACE terminated\n",0,0) ;
+			smc->e.path_test = PT_PENDING ;
+		}
+		else {
+			/* trace propagate upstream */
+			DB_ECM("ECM : propagate TRACE on PHY %d\n",upstream,0) ;
+			queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;
+		}
+	}
+}
+#endif
+
+
+/*
+ * SMT timer interface
+ *	start ECM timer
+ */
+static void start_ecm_timer(smc,value,event)
+struct s_smc *smc ;
+u_long value;
+int event ;
+{
+	smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));
+}
+
+/*
+ * SMT timer interface
+ *	stop ECM timer
+ */
+static void stop_ecm_timer(smc)
+struct s_smc *smc ;
+{
+	if (smc->e.ecm_timer.tm_active)
+		smt_timer_stop(smc,&smc->e.ecm_timer) ;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/ess.c linux.18p8/drivers/net/skfp/ess.c
--- linux.vanilla/drivers/net/skfp/ess.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/ess.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,732 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * *******************************************************************
+ * This SBA code implements the Synchronous Bandwidth Allocation
+ * functions described in the "FDDI Synchronous Forum Implementer's
+ * Agreement" dated December 1th, 1993.
+ * *******************************************************************
+ *
+ *	PURPOSE: The purpose of this function is to control
+ *		 synchronous allocations on a single FDDI segment.
+ *		 Allocations are limited to the primary FDDI ring.
+ *		 The SBM provides recovery mechanisms to recover
+ *		 unused bandwidth also resolves T_Neg and
+ *		 reconfiguration changes. Many of the SBM state
+ *		 machine inputs are sourced by the underlying
+ *		 FDDI sub-system supporting the SBA application.
+ *
+ * *******************************************************************
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+
+#ifndef	SLIM_SMT
+
+#ifdef ESS
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)ess.c	1.10 96/02/23 (C) SK" ;
+#define LINT_USE(x)
+#else
+#define LINT_USE(x)	(x)=(x)
+#endif
+#define MS2BCLK(x)	((x)*12500L)
+
+/*
+	-------------------------------------------------------------
+	LOCAL VARIABLES:
+	-------------------------------------------------------------
+*/
+
+static const u_short plist_raf_alc_res[] = { SMT_P0012, SMT_P320B, SMT_P320F,
+					SMT_P3210, SMT_P0019, SMT_P001A,
+					SMT_P001D, 0 } ;
+
+static const u_short plist_raf_chg_req[] = { SMT_P320B, SMT_P320F, SMT_P3210,
+					SMT_P001A, 0 } ;
+
+static const struct fddi_addr smt_sba_da = {{0x80,0x01,0x43,0x00,0x80,0x0C}} ;
+static const struct fddi_addr null_addr = {{0,0,0,0,0,0}} ;
+
+/*
+	-------------------------------------------------------------
+	GLOBAL VARIABLES:
+	-------------------------------------------------------------
+*/
+
+
+/*
+	-------------------------------------------------------------
+	LOCAL FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+static	void	ess_send_response(),		ess_config_fifo(),
+		ess_send_alc_req(),		ess_send_frame() ;
+
+/*
+	-------------------------------------------------------------
+	EXTERNAL FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+extern	void	*sm_to_para() ;
+
+extern	void	smt_send_frame(),	smt_free_mbuf(),
+		set_formac_tsync(),	formac_reinit_tx() ;
+
+extern	int	smt_check_para() ;
+
+extern	SMbuf	*smt_get_mbuf(),	*smt_build_frame() ;
+
+extern	u_long	smt_get_tid() ;
+
+/*
+	-------------------------------------------------------------
+	PUBLIC FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+	void	ess_timer_poll(),		ess_para_change() ;
+
+	int	ess_raf_received_pack(),	process_bw_alloc() ;
+
+
+/*
+ * --------------------------------------------------------------------------
+ *	End Station Support	(ESS)
+ * --------------------------------------------------------------------------
+ */
+
+/*
+ * evaluate the RAF frame
+ */
+int ess_raf_received_pack(smc,mb,sm,fs)
+struct s_smc *smc ;
+SMbuf *mb ;
+struct smt_header *sm ;
+int fs ;
+{
+	void			*p ;		/* universal pointer */
+	struct smt_p_0016	*cmd ;		/* para: command for the ESS */
+	SMbuf			*db ;
+	u_long			msg_res_type ;	/* recource type */
+	u_long			payload, overhead ;
+	int			local ;
+	int			i ;
+
+	/*
+	 * Message Processing Code
+	 */
+	 local = ((fs & L_INDICATOR) != 0) ;
+
+	/*
+	 * get the resource type
+	 */
+	if (!(p = (void *) sm_to_para(smc,sm,SMT_P0015))) {
+		DB_ESS("ESS: RAF frame error, parameter type not found\n",0,0) ;
+		return(fs) ;
+	}
+	msg_res_type = ((struct smt_p_0015 *)p)->res_type ;
+
+	/*
+	 * get the pointer to the ESS command
+	 */
+	if (!(cmd = (struct smt_p_0016 *) sm_to_para(smc,sm,SMT_P0016))) {
+		/*
+		 * error in frame: para ESS command was not found
+		 */
+		 DB_ESS("ESS: RAF frame error, parameter command not found\n",0,0);
+		 return(fs) ;
+	}
+
+	DB_ESSN(2,"fc %x	ft %x\n",sm->smt_class,sm->smt_type) ;
+	DB_ESSN(2,"ver %x	tran %lx\n",sm->smt_version,sm->smt_tid) ;
+	DB_ESSN(2,"stn_id %s\n",addr_to_string(&sm->smt_source),0) ;
+
+	DB_ESSN(2,"infolen %x	res %x\n",sm->smt_len, msg_res_type) ;
+	DB_ESSN(2,"sbacmd %x\n",cmd->sba_cmd,0) ;
+
+	/*
+	 * evaluate the ESS command
+	 */
+	switch (cmd->sba_cmd) {
+
+	/*
+	 * Process an ESS Allocation Request
+	 */
+	case REQUEST_ALLOCATION :
+		/*
+		 * check for an RAF Request (Allocation Request)
+		 */
+		if (sm->smt_type == SMT_REQUEST) {
+			/*
+			 * process the Allocation request only if the frame is
+			 * local and no static allocation is used
+			 */
+			if (!local || smc->mib.fddiESSPayload)
+				return(fs) ;
+			
+			p = (void *) sm_to_para(smc,sm,SMT_P0019)  ;
+			for (i = 0; i < 5; i++) {
+				if (((struct smt_p_0019 *)p)->alloc_addr.a[i]) {
+					return(fs) ;
+				}
+			}
+
+			/*
+			 * Note: The Application should send a LAN_LOC_FRAME.
+			 *	 The ESS do not send the Frame to the network!
+			 */
+			smc->ess.alloc_trans_id = sm->smt_tid ;
+			DB_ESS("ESS: save Alloc Req Trans ID %lx\n",sm->smt_tid,0);
+			p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+			((struct smt_p_320f *)p)->mib_payload =
+				smc->mib.a[PATH0].fddiPATHSbaPayload ;
+			p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+			((struct smt_p_3210 *)p)->mib_overhead =
+				smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+			sm->smt_dest = smt_sba_da ;
+
+			if (smc->ess.local_sba_active)
+				return(fs | I_INDICATOR) ;
+
+			if (!(db = smt_get_mbuf(smc)))
+				return(fs) ;
+
+			db->sm_len = mb->sm_len ;
+			db->sm_off = mb->sm_off ;
+			memcpy(((char *)(db->sm_data+db->sm_off)),(char *)sm,
+				(int)db->sm_len) ;
+			dump_smt(smc,
+				(struct smt_header *)(db->sm_data+db->sm_off),
+				"RAF") ;
+			smt_send_frame(smc,db,FC_SMT_INFO,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * The RAF frame is an Allocation Response !
+		 * check the parameters
+		 */
+		if (smt_check_para(smc,sm,plist_raf_alc_res)) {
+			DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * VERIFY THE FRAME IS WELL BUILT:
+		 *
+		 *	1. path index = primary ring only
+		 *	2. resource type = sync bw only
+		 *	3. trans action id = alloc_trans_id
+		 *	4. reason code = success
+		 *
+		 * If any are violated, discard the RAF frame
+		 */
+		if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index
+			!= PRIMARY_RING) ||
+			(msg_res_type != SYNC_BW) ||
+		(((struct smt_p_reason *)sm_to_para(smc,sm,SMT_P0012))->rdf_reason
+			!= SMT_RDF_SUCCESS) ||
+			(sm->smt_tid != smc->ess.alloc_trans_id)) {
+
+			DB_ESS("ESS: Allocation Responce not accepted\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * Extract message parameters
+		 */
+		p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+		payload = ((struct smt_p_320f *)p)->mib_payload ;
+		p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+		overhead = ((struct smt_p_3210 *)p)->mib_overhead ;
+
+		DB_ESSN(2,"payload= %lx	overhead= %lx\n",payload,overhead) ;
+
+		/*
+		 * process the bandwidth allocation
+		 */
+		(void)process_bw_alloc(smc,(long)payload,(long)overhead) ;
+
+		return(fs) ;
+		/* end of Process Allocation Request */
+
+	/*
+	 * Process an ESS Change Request
+	 */
+	case CHANGE_ALLOCATION :
+		/*
+		 * except only replies
+		 */
+		if (sm->smt_type != SMT_REQUEST) {
+			DB_ESS("ESS: Do not process Change Responses\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * check the para for the Change Request
+		 */
+		if (smt_check_para(smc,sm,plist_raf_chg_req)) {
+			DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * Verify the path index and resource
+		 * type are correct. If any of
+		 * these are false, don't process this
+		 * change request frame.
+		 */
+		if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index
+			!= PRIMARY_RING) || (msg_res_type != SYNC_BW)) {
+			DB_ESS("ESS: RAF frame with para problem, ignoring\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * Extract message queue parameters
+		 */
+		p = (void *) sm_to_para(smc,sm,SMT_P320F) ;
+		payload = ((struct smt_p_320f *)p)->mib_payload ;
+		p = (void *) sm_to_para(smc,sm,SMT_P3210) ;
+		overhead = ((struct smt_p_3210 *)p)->mib_overhead ;
+
+		DB_ESSN(2,"ESS: Change Request from %s\n",
+			addr_to_string(&sm->smt_source),0) ;
+		DB_ESSN(2,"payload= %lx	overhead= %lx\n",payload,overhead) ;
+
+		/*
+		 * process the bandwidth allocation
+		 */
+		if(!process_bw_alloc(smc,(long)payload,(long)overhead))
+			return(fs) ;
+
+		/*
+		 * send an RAF Change Reply
+		 */
+		ess_send_response(smc,sm,CHANGE_ALLOCATION) ;
+
+		return(fs) ;
+		/* end of Process Change Request */
+
+	/*
+	 * Process Report Response
+	 */
+	case REPORT_ALLOCATION :
+		/*
+		 * except only requests
+		 */
+		if (sm->smt_type != SMT_REQUEST) {
+			DB_ESS("ESS: Do not process a Report Reply\n",0,0) ;
+			return(fs) ;
+		}
+
+		DB_ESSN(2,"ESS: Report Request from %s\n",
+			addr_to_string(&(sm->smt_source)),0) ;
+
+		/*
+		 * verify that the resource type is sync bw only
+		 */
+		if (msg_res_type != SYNC_BW) {
+			DB_ESS("ESS: ignoring RAF with para problem\n",0,0) ;
+			return(fs) ;
+		}
+
+		/*
+		 * send an RAF Change Reply
+		 */
+		ess_send_response(smc,sm,REPORT_ALLOCATION) ;
+
+		return(fs) ;
+		/* end of Process Report Request */
+
+	default:
+		/*
+		 * error in frame
+		 */
+		DB_ESS("ESS: ignoring RAF with bad sba_cmd\n",0,0) ;
+		break ;
+	}
+
+	return(fs) ;
+}
+
+/*
+ * determines the synchronous bandwidth, set the TSYNC register and the
+ * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG.
+ */
+int process_bw_alloc(smc,payload,overhead)
+struct s_smc *smc ;
+long payload ;
+long overhead ;
+{
+	/*
+	 * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG,
+	 * if the payload is greater than zero.
+	 * For the SBAPayload and the SBAOverhead we have the following
+	 * unite quations
+ 	 *		      _		  _
+	 *		     |	     bytes |
+	 *	SBAPayload = | 8000 ------ |
+	 *		     |		s  |
+	 *		      -		  -
+ 	 *		       _       _
+	 *		      |	 bytes	|
+	 *	SBAOverhead = | ------	|
+	 *		      |	 T-NEG	|
+	 *		       -       -
+ 	 *
+	 * T-NEG is discribed by the equation:
+	 *
+	 *		     (-) fddiMACT-NEG
+	 *	T-NEG =	    -------------------
+	 *			12500000 1/s
+	 *
+	 * The number of bytes we are able to send is the payload
+	 * plus the overhead.
+	 *
+	 *			  bytes    T-NEG SBAPayload 8000 bytes/s
+	 * sync_bw =  SBAOverhead ------ + -----------------------------
+	 *	   		  T-NEG		T-NEG
+	 *
+	 *
+	 *	      		     1
+	 * sync_bw =  SBAOverhead + ---- (-)fddiMACT-NEG * SBAPayload
+	 *	       		    1562
+	 *
+	 */
+
+	/*
+	 * set the mib attributes fddiPATHSbaOverhead, fddiPATHSbaPayload
+	 */
+/*	if (smt_set_obj(smc,SMT_P320F,payload,S_SET)) {
+		DB_ESS("ESS: SMT does not accept the payload value\n",0,0) ;
+		return(FALSE) ;
+	}
+	if (smt_set_obj(smc,SMT_P3210,overhead,S_SET)) {
+		DB_ESS("ESS: SMT does not accept the overhead value\n",0,0) ;
+		return(FALSE) ;
+	} */
+
+	/* premliminary */
+	if (payload > MAX_PAYLOAD || overhead > 5000) {
+		DB_ESS("ESS: payload / overhead not accepted\n",0,0) ;
+		return(FALSE) ;
+	}
+
+	/*
+	 * start the iterative allocation process if the payload or the overhead
+	 * are smaller than the parsed values
+	 */
+	if (smc->mib.fddiESSPayload &&
+		((u_long)payload != smc->mib.fddiESSPayload ||
+		(u_long)overhead != smc->mib.fddiESSOverhead)) {
+		smc->ess.raf_act_timer_poll = TRUE ;
+		smc->ess.timer_count = 0 ;
+	}
+
+	/*
+	 * evulate the Payload
+	 */
+	if (payload) {
+		DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit on\n",0,0) ;
+		smc->ess.sync_bw_available = TRUE ;
+
+		smc->ess.sync_bw = overhead -
+			(long)smc->mib.m[MAC0].fddiMACT_Neg *
+			payload / 1562 ;
+	}
+	else {
+		DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit off\n",0,0) ;
+		smc->ess.sync_bw_available = FALSE ;
+		smc->ess.sync_bw = 0 ;
+		overhead = 0 ;
+	}
+
+	smc->mib.a[PATH0].fddiPATHSbaPayload = payload ;
+	smc->mib.a[PATH0].fddiPATHSbaOverhead = overhead ;
+
+
+	DB_ESSN(2,"tsync = %lx\n",smc->ess.sync_bw,0) ;
+
+	ess_config_fifo(smc) ;
+	set_formac_tsync(smc,smc->ess.sync_bw) ;
+	return(TRUE) ;
+}
+
+static void ess_send_response(smc,sm,sba_cmd)
+struct s_smc *smc ;
+struct smt_header *sm ;
+int sba_cmd ;
+{
+	struct smt_sba_chg	*chg ;
+	SMbuf			*mb ;
+	void			*p ;
+
+	/*
+	 * get and initialize the responce frame
+	 */
+	if (sba_cmd == CHANGE_ALLOCATION) {
+		if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY,
+				sizeof(struct smt_sba_chg))))
+				return ;
+	}
+	else {
+		if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY,
+				sizeof(struct smt_sba_rep_res))))
+				return ;
+	}
+
+	chg = smtod(mb,struct smt_sba_chg *) ;
+	chg->smt.smt_tid = sm->smt_tid ;
+	chg->smt.smt_dest = sm->smt_source ;
+
+	/* set P15 */
+	chg->s_type.para.p_type = SMT_P0015 ;
+	chg->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ;
+	chg->s_type.res_type = SYNC_BW ;
+
+	/* set P16 */
+	chg->cmd.para.p_type = SMT_P0016 ;
+	chg->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ;
+	chg->cmd.sba_cmd = sba_cmd ;
+
+	/* set P320B */
+	chg->path.para.p_type = SMT_P320B ;
+	chg->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ;
+	chg->path.mib_index = SBAPATHINDEX ;
+	chg->path.path_pad = (u_short)NULL ;
+	chg->path.path_index = PRIMARY_RING ;
+
+	/* set P320F */
+	chg->payload.para.p_type = SMT_P320F ;
+	chg->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ;
+	chg->payload.mib_index = SBAPATHINDEX ;
+	chg->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ;
+
+	/* set P3210 */
+	chg->overhead.para.p_type = SMT_P3210 ;
+	chg->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ;
+	chg->overhead.mib_index = SBAPATHINDEX ;
+	chg->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+
+	if (sba_cmd == CHANGE_ALLOCATION) {
+		/* set P1A */
+		chg->cat.para.p_type = SMT_P001A ;
+		chg->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ;
+		p = (void *) sm_to_para(smc,sm,SMT_P001A) ;
+		chg->cat.category = ((struct smt_p_001a *)p)->category ;
+	}
+	dump_smt(smc,(struct smt_header *)chg,"RAF") ;
+	ess_send_frame(smc,mb) ;
+}
+
+
+void ess_timer_poll(smc)
+struct s_smc *smc ;
+{
+	if (!smc->ess.raf_act_timer_poll)
+		return ;
+
+	DB_ESSN(2,"ESS: timer_poll\n",0,0) ;
+
+	smc->ess.timer_count++ ;
+	if (smc->ess.timer_count == 10) {
+		smc->ess.timer_count = 0 ;
+		ess_send_alc_req(smc) ;
+	}
+}
+
+static void ess_send_alc_req(smc)
+struct s_smc *smc ;
+{
+	struct smt_sba_alc_req *req ;
+	SMbuf	*mb ;
+
+	/*
+	 * send never allocation request where the requested payload and
+	 * overhead is zero or deallocate bandwidht when no bandwidth is
+	 * parsed
+	 */
+	if (!smc->mib.fddiESSPayload) {
+		smc->mib.fddiESSOverhead = 0 ;
+	}
+	else {
+		if (!smc->mib.fddiESSOverhead)
+			smc->mib.fddiESSOverhead = DEFAULT_OV ;
+	}
+
+	if (smc->mib.fddiESSOverhead ==
+		smc->mib.a[PATH0].fddiPATHSbaOverhead &&
+		smc->mib.fddiESSPayload ==
+		smc->mib.a[PATH0].fddiPATHSbaPayload){
+		smc->ess.raf_act_timer_poll = FALSE ;
+		smc->ess.timer_count = 7 ;	/* next RAF alc req after 3 s */
+		return ;
+	}
+	
+	/*
+	 * get and initialize the responce frame
+	 */
+	if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REQUEST,
+			sizeof(struct smt_sba_alc_req))))
+			return ;
+	req = smtod(mb,struct smt_sba_alc_req *) ;
+	req->smt.smt_tid = smc->ess.alloc_trans_id = smt_get_tid(smc) ;
+	req->smt.smt_dest = smt_sba_da ;
+
+	/* set P15 */
+	req->s_type.para.p_type = SMT_P0015 ;
+	req->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ;
+	req->s_type.res_type = SYNC_BW ;
+
+	/* set P16 */
+	req->cmd.para.p_type = SMT_P0016 ;
+	req->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ;
+	req->cmd.sba_cmd = REQUEST_ALLOCATION ;
+
+	/*
+	 * set the parameter type and parameter lenght of all used
+	 * parameters
+	 */
+
+	/* set P320B */
+	req->path.para.p_type = SMT_P320B ;
+	req->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ;
+	req->path.mib_index = SBAPATHINDEX ;
+	req->path.path_pad = (u_short)NULL ;
+	req->path.path_index = PRIMARY_RING ;
+
+	/* set P0017 */
+	req->pl_req.para.p_type = SMT_P0017 ;
+	req->pl_req.para.p_len = sizeof(struct smt_p_0017) - PARA_LEN ;
+	req->pl_req.sba_pl_req = smc->mib.fddiESSPayload -
+		smc->mib.a[PATH0].fddiPATHSbaPayload ;
+
+	/* set P0018 */
+	req->ov_req.para.p_type = SMT_P0018 ;
+	req->ov_req.para.p_len = sizeof(struct smt_p_0018) - PARA_LEN ;
+	req->ov_req.sba_ov_req = smc->mib.fddiESSOverhead -
+		smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+
+	/* set P320F */
+	req->payload.para.p_type = SMT_P320F ;
+	req->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ;
+	req->payload.mib_index = SBAPATHINDEX ;
+	req->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ;
+
+	/* set P3210 */
+	req->overhead.para.p_type = SMT_P3210 ;
+	req->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ;
+	req->overhead.mib_index = SBAPATHINDEX ;
+	req->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ;
+
+	/* set P19 */
+	req->a_addr.para.p_type = SMT_P0019 ;
+	req->a_addr.para.p_len = sizeof(struct smt_p_0019) - PARA_LEN ;
+	req->a_addr.sba_pad = (u_short)NULL ;
+	req->a_addr.alloc_addr = null_addr ;
+
+	/* set P1A */
+	req->cat.para.p_type = SMT_P001A ;
+	req->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ;
+	req->cat.category = smc->mib.fddiESSCategory ;
+
+	/* set P1B */
+	req->tneg.para.p_type = SMT_P001B ;
+	req->tneg.para.p_len = sizeof(struct smt_p_001b) - PARA_LEN ;
+	req->tneg.max_t_neg = smc->mib.fddiESSMaxTNeg ;
+
+	/* set P1C */
+	req->segm.para.p_type = SMT_P001C ;
+	req->segm.para.p_len = sizeof(struct smt_p_001c) - PARA_LEN ;
+	req->segm.min_seg_siz = smc->mib.fddiESSMinSegmentSize ;
+
+	dump_smt(smc,(struct smt_header *)req,"RAF") ;
+	ess_send_frame(smc,mb) ;
+}
+
+static void ess_send_frame(smc,mb)
+struct s_smc *smc ;
+SMbuf *mb ;
+{
+	/*
+	 * check if the frame must be send to the own ESS
+	 */
+	if (smc->ess.local_sba_active) {
+		/*
+		 * Send the Change Reply to the local SBA
+		 */
+		DB_ESS("ESS:Send to the local SBA\n",0,0) ;
+		if (!smc->ess.sba_reply_pend)
+			smc->ess.sba_reply_pend = mb ;
+		else {
+			DB_ESS("Frame is lost - another frame was pending\n",0,0);
+			smt_free_mbuf(smc,mb) ;
+		}
+	}
+	else {
+		/*
+		 * Send the SBA RAF Change Reply to the network
+		 */
+		DB_ESS("ESS:Send to the network\n",0,0) ;
+		smt_send_frame(smc,mb,FC_SMT_INFO,0) ;
+	}
+}
+
+void ess_para_change(smc)
+struct s_smc *smc ;
+{
+	(void)process_bw_alloc(smc,(long)smc->mib.a[PATH0].fddiPATHSbaPayload,
+		(long)smc->mib.a[PATH0].fddiPATHSbaOverhead) ;
+}
+
+static void ess_config_fifo(smc)
+struct s_smc *smc ;
+{
+	/*
+	 * if nothing to do exit 
+	 */
+	if (smc->mib.a[PATH0].fddiPATHSbaPayload) {
+		if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON &&
+			(smc->hw.fp.fifo.fifo_config_mode&SEND_ASYNC_AS_SYNC) ==
+			smc->mib.fddiESSSynchTxMode) {
+			return ;
+		}
+	}
+	else {
+		if (!(smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON)) {
+			return ;
+		}
+	}
+
+	/*
+	 * split up the FIFO and reinitialize the queues
+	 */
+	formac_reinit_tx(smc) ;
+}
+
+#endif /* ESS */
+
+#endif	/* no SLIM_SMT */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/fplustm.c linux.18p8/drivers/net/skfp/fplustm.c
--- linux.vanilla/drivers/net/skfp/fplustm.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/fplustm.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,1645 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * FORMAC+ Driver for tag mode
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#include "can.c"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)fplustm.c	1.32 99/02/23 (C) SK " ;
+#endif
+
+#ifndef UNUSED
+#ifdef  lint
+#define UNUSED(x)	(x) = (x)
+#else
+#define UNUSED(x)
+#endif
+#endif
+
+#define FM_ADDRX	 (FM_ADDET|FM_EXGPA0|FM_EXGPA1)
+#define MS2BCLK(x)	((x)*12500L)
+#define US2BCLK(x)	((x)*1250L)
+
+/*
+ * prototypes for static function
+ */
+static void build_claim_beacon() ;
+static int init_mac() ;
+static void rtm_init() ;
+static void smt_split_up_fifo() ;
+
+#if (!defined(NO_SMT_PANIC) || defined(DEBUG))
+static	char write_mdr_warning [] = "E350 write_mdr() FM_SNPPND is set\n";
+static	char cam_warning [] = "E_SMT_004: CAM still busy\n";
+#endif
+
+#define	DUMMY_READ()	smc->hw.mc_dummy = (u_short) inp(ADDR(B0_RAP))
+
+#define	CHECK_NPP() {	unsigned k = 10000 ;\
+			while ((inpw(FM_A(FM_STMCHN)) & FM_SNPPND) && k) k--;\
+			if (!k) { \
+				SMT_PANIC(smc,SMT_E0130, SMT_E0130_MSG) ; \
+			}	\
+		}
+
+#define	CHECK_CAM() {	unsigned k = 10 ;\
+			while (!(inpw(FM_A(FM_AFSTAT)) & FM_DONE) && k) k--;\
+			if (!k) { \
+				SMT_PANIC(smc,SMT_E0131, SMT_E0131_MSG) ; \
+			}	\
+		}
+
+const struct fddi_addr fddi_broadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
+static const struct fddi_addr null_addr = {{0,0,0,0,0,0}};
+static const struct fddi_addr dbeacon_multi = {{0x01,0x80,0xc2,0x00,0x01,0x00}};
+
+static const u_short my_said = 0xffff ;	/* short address (n.u.) */
+static const u_short my_sagp = 0xffff ;	/* short group address (n.u.) */
+
+/*
+ * define my address
+ */
+#ifdef	USE_CAN_ADDR
+#define MA	smc->hw.fddi_canon_addr
+#else
+#define MA	smc->hw.fddi_home_addr
+#endif
+
+
+/*
+ * usefull interrupt bits
+ */
+static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ;
+static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0|
+			FM_STBURS | FM_STBURA0 ;
+
+	/* delete FM_SRBFL after tests */
+static int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL |
+			FM_SMYCLM ;
+static int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR |
+			FM_SERRCTR | FM_SLSTCTR |
+			FM_STRTEXP | FM_SMULTDA | FM_SRNGOP ;
+
+static int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ;
+static int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ;
+
+static int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC |
+			FM_SLOCLM | FM_SHICLM | FM_SMYCLM | FM_SCLM ;
+
+
+static u_long mac_get_tneg(smc)
+struct s_smc *smc ;
+{
+	u_long	tneg ;
+
+	tneg = (u_long)((long)inpw(FM_A(FM_TNEG))<<5) ;
+	return((u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) |
+		0xffe00000L)) ;
+}
+
+void mac_update_counter(smc)
+struct s_smc *smc ;
+{
+	smc->mib.m[MAC0].fddiMACFrame_Ct =
+		(smc->mib.m[MAC0].fddiMACFrame_Ct & 0xffff0000L)
+		+ (u_short) inpw(FM_A(FM_FCNTR)) ;
+	smc->mib.m[MAC0].fddiMACLost_Ct =
+		(smc->mib.m[MAC0].fddiMACLost_Ct & 0xffff0000L)
+		+ (u_short) inpw(FM_A(FM_LCNTR)) ;
+	smc->mib.m[MAC0].fddiMACError_Ct =
+		(smc->mib.m[MAC0].fddiMACError_Ct & 0xffff0000L)
+		+ (u_short) inpw(FM_A(FM_ECNTR)) ;
+	smc->mib.m[MAC0].fddiMACT_Neg = mac_get_tneg(smc) ;
+#ifdef SMT_REAL_TOKEN_CT
+	/*
+	 * If the token counter is emulated it is updated in smt_event.
+	 */
+	TBD
+#else
+	smt_emulate_token_ct( smc, MAC0 );
+#endif
+}
+
+/*
+ * write long value into buffer memory over memory data register (MDR),
+ */
+void	write_mdr(smc,val)
+struct s_smc *smc ;
+u_long val;
+{
+	CHECK_NPP() ;
+	MDRW(val) ;
+}
+
+/*
+ * read long value from buffer memory over memory data register (MDR),
+ */
+u_long read_mdr(smc,addr)
+struct s_smc *smc ;
+unsigned int addr;
+{
+	long p ;
+	CHECK_NPP() ;
+	MARR(addr) ;
+	outpw(FM_A(FM_CMDREG1),FM_IRMEMWO) ;
+	CHECK_NPP() ;	/* needed for PCI to prevent from timeing violations */
+/*	p = MDRR() ; */	/* bad read values if the workaround */
+			/* smc->hw.mc_dummy = *((short volatile far *)(addr)))*/
+			/* is used */
+	p = (u_long)inpw(FM_A(FM_MDRU))<<16 ;
+	p += (u_long)inpw(FM_A(FM_MDRL)) ;
+	return(p) ;
+}
+/*
+ * clear buffer memory
+ */
+static void init_ram(smc)
+struct s_smc *smc ;
+{
+	u_short i ;
+
+	smc->hw.fp.fifo.rbc_ram_start = 0 ;
+	smc->hw.fp.fifo.rbc_ram_end =
+		smc->hw.fp.fifo.rbc_ram_start + RBC_MEM_SIZE ;
+	CHECK_NPP() ;
+	MARW(smc->hw.fp.fifo.rbc_ram_start) ;
+	for (i = smc->hw.fp.fifo.rbc_ram_start;
+		i < (u_short) (smc->hw.fp.fifo.rbc_ram_end-1); i++)
+		write_mdr(smc,0L) ;
+	/* Erase the last byte too */
+	write_mdr(smc,0L) ;
+}
+
+/*
+ * set receive FIFO pointer
+ */
+static void set_recvptr(smc)
+struct s_smc *smc ;
+{
+	/*
+	 * initialize the pointer for receive queue 1
+	 */
+	outpw(FM_A(FM_RPR1),smc->hw.fp.fifo.rx1_fifo_start) ;	/* RPR1 */
+	outpw(FM_A(FM_SWPR1),smc->hw.fp.fifo.rx1_fifo_start) ;	/* SWPR1 */
+	outpw(FM_A(FM_WPR1),smc->hw.fp.fifo.rx1_fifo_start) ;	/* WPR1 */
+	outpw(FM_A(FM_EARV1),smc->hw.fp.fifo.tx_s_start-1) ;	/* EARV1 */
+
+	/*
+	 * initialize the pointer for receive queue 2
+	 */
+	if (smc->hw.fp.fifo.rx2_fifo_size) {
+		outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rx2_fifo_start) ;
+		outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rx2_fifo_start) ;
+		outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rx2_fifo_start) ;
+		outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+	}
+	else {
+		outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+		outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+		outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+		outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ;
+	}
+}
+
+/*
+ * set transmit FIFO pointer
+ */
+static void set_txptr(smc)
+struct s_smc *smc ;
+{
+	outpw(FM_A(FM_CMDREG2),FM_IRSTQ) ;	/* reset transmit queues */
+
+	/*
+	 * initialize the pointer for asynchronous transmit queue
+	 */
+	outpw(FM_A(FM_RPXA0),smc->hw.fp.fifo.tx_a0_start) ;	/* RPXA0 */
+	outpw(FM_A(FM_SWPXA0),smc->hw.fp.fifo.tx_a0_start) ;	/* SWPXA0 */
+	outpw(FM_A(FM_WPXA0),smc->hw.fp.fifo.tx_a0_start) ;	/* WPXA0 */
+	outpw(FM_A(FM_EAA0),smc->hw.fp.fifo.rx2_fifo_start-1) ;	/* EAA0 */
+
+	/*
+	 * initialize the pointer for synchronous transmit queue
+	 */
+	if (smc->hw.fp.fifo.tx_s_size) {
+		outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_s_start) ;
+		outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_s_start) ;
+		outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_s_start) ;
+		outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ;
+	}
+	else {
+		outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_a0_start-1) ;
+		outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_a0_start-1) ;
+		outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_a0_start-1) ;
+		outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ;
+	}
+}
+
+/*
+ * init memory buffer management registers
+ */
+static void init_rbc(smc)
+struct s_smc *smc ;
+{
+	u_short	rbc_ram_addr ;
+
+	/*
+	 * set unused pointers or permanent pointers
+	 */
+	rbc_ram_addr = smc->hw.fp.fifo.rx2_fifo_start - 1 ;
+
+	outpw(FM_A(FM_RPXA1),rbc_ram_addr) ;	/* a1-send pointer */
+	outpw(FM_A(FM_WPXA1),rbc_ram_addr) ;
+	outpw(FM_A(FM_SWPXA1),rbc_ram_addr) ;
+	outpw(FM_A(FM_EAA1),rbc_ram_addr) ;
+
+	set_recvptr(smc) ;
+	set_txptr(smc) ;
+}
+
+/*
+ * init rx pointer
+ */
+static void init_rx(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_rx_queue	*queue ;
+
+	/*
+	 * init all tx data structures for receive queue 1
+	 */
+	smc->hw.fp.rx[QUEUE_R1] = queue = &smc->hw.fp.rx_q[QUEUE_R1] ;
+	queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R1_CSR) ;
+	queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R1_DA) ;
+
+	/*
+	 * init all tx data structures for receive queue 2
+	 */
+	smc->hw.fp.rx[QUEUE_R2] = queue = &smc->hw.fp.rx_q[QUEUE_R2] ;
+	queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R2_CSR) ;
+	queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R2_DA) ;
+}
+
+/*
+ * set the TSYNC register of the FORMAC to regulate synchronous transmission
+ */
+void set_formac_tsync(smc,sync_bw)
+struct s_smc *smc ;
+long sync_bw ;
+{
+	outpw(FM_A(FM_TSYNC),(unsigned int) (((-sync_bw) >> 5) & 0xffff) ) ;
+}
+
+/*
+ * init all tx data structures
+ */
+static void init_tx(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_tx_queue	*queue ;
+
+	/*
+	 * init all tx data structures for the synchronous queue
+	 */
+	smc->hw.fp.tx[QUEUE_S] = queue = &smc->hw.fp.tx_q[QUEUE_S] ;
+	queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XS_CSR) ;
+	queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XS_DA) ;
+
+#ifdef ESS
+	set_formac_tsync(smc,smc->ess.sync_bw) ;
+#endif
+
+	/*
+	 * init all tx data structures for the asynchronous queue 0
+	 */
+	smc->hw.fp.tx[QUEUE_A0] = queue = &smc->hw.fp.tx_q[QUEUE_A0] ;
+	queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XA_CSR) ;
+	queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XA_DA) ;
+
+
+	llc_recover_tx(smc) ;
+}
+
+static void mac_counter_init(smc)
+struct s_smc *smc ;
+{
+	int i ;
+	u_long *ec ;
+
+	/*
+	 * clear FORMAC+ frame-, lost- and error counter
+	 */
+	outpw(FM_A(FM_FCNTR),0) ;
+	outpw(FM_A(FM_LCNTR),0) ;
+	outpw(FM_A(FM_ECNTR),0) ;
+	/*
+	 * clear internal error counter stucture
+	 */
+	ec = (u_long *)&smc->hw.fp.err_stats ;
+	for (i = (sizeof(struct err_st)/sizeof(long)) ; i ; i--)
+		*ec++ = 0L ;
+	smc->mib.m[MAC0].fddiMACRingOp_Ct = 0 ;
+}
+
+/*
+ * set FORMAC address, and t_request
+ */
+static	void set_formac_addr(smc)
+struct s_smc *smc ;
+{
+	long	t_requ = smc->mib.m[MAC0].fddiMACT_Req ;
+
+	outpw(FM_A(FM_SAID),my_said) ;	/* set short address */
+	outpw(FM_A(FM_LAIL),(unsigned)((smc->hw.fddi_home_addr.a[4]<<8) +
+					smc->hw.fddi_home_addr.a[5])) ;
+	outpw(FM_A(FM_LAIC),(unsigned)((smc->hw.fddi_home_addr.a[2]<<8) +
+					smc->hw.fddi_home_addr.a[3])) ;
+	outpw(FM_A(FM_LAIM),(unsigned)((smc->hw.fddi_home_addr.a[0]<<8) +
+					smc->hw.fddi_home_addr.a[1])) ;
+
+	outpw(FM_A(FM_SAGP),my_sagp) ;	/* set short group address */
+
+	outpw(FM_A(FM_LAGL),(unsigned)((smc->hw.fp.group_addr.a[4]<<8) +
+					smc->hw.fp.group_addr.a[5])) ;
+	outpw(FM_A(FM_LAGC),(unsigned)((smc->hw.fp.group_addr.a[2]<<8) +
+					smc->hw.fp.group_addr.a[3])) ;
+	outpw(FM_A(FM_LAGM),(unsigned)((smc->hw.fp.group_addr.a[0]<<8) +
+					smc->hw.fp.group_addr.a[1])) ;
+
+	/* set r_request regs. (MSW & LSW of TRT ) */
+	outpw(FM_A(FM_TREQ1),(unsigned)(t_requ>>16)) ;
+	outpw(FM_A(FM_TREQ0),(unsigned)t_requ) ;
+}
+
+void set_int(p,l)
+char *p;
+int l;
+{
+	p[0] = (char)(l >> 24) ;
+	p[1] = (char)(l >> 16) ;
+	p[2] = (char)(l >> 8) ;
+	p[3] = (char)(l >> 0) ;
+}
+
+/*
+ * copy TX descriptor to buffer mem
+ * append FC field and MAC frame
+ * if more bit is set in descr
+ *	append pointer to descriptor (endless loop)
+ * else
+ *	append 'end of chain' pointer
+ */
+static void copy_tx_mac(smc,td,mac,off,len)
+struct s_smc *smc ;
+u_long td;		/* transmit descriptor */
+struct fddi_mac *mac;	/* mac frame pointer */
+unsigned off;		/* start address within buffer memory */
+int len ;		/* lenght of the frame including the FC */
+{
+	int	i ;
+	u_int	*p ;
+
+	CHECK_NPP() ;
+	MARW(off) ;		/* set memory address reg for writes */
+
+	p = (u_int *) mac ;
+	for (i = (len + 3)/4 ; i ; i--) {
+		if (i == 1) {
+			/* last word, set the tag bit */
+			outpw(FM_A(FM_CMDREG2),FM_ISTTB) ;
+		}
+		write_mdr(smc,MDR_REVERSE(*p)) ;
+		p++ ;
+	}
+
+	outpw(FM_A(FM_CMDREG2),FM_ISTTB) ;	/* set the tag bit */
+	write_mdr(smc,td) ;	/* write over memory data reg to buffer */
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(module;tests;3)
+	How to test directed beacon frames
+	----------------------------------------------------------------
+
+	o Insert a break point in the function build_claim_beacon()
+	  before calling copy_tx_mac() for building the claim frame.
+	o Modify the RM3_DETECT case so that the RM6_DETECT state
+	  will always entered from the RM3_DETECT state (function rmt_fsm(),
+	  rmt.c)
+	o Compile the driver.
+	o Set the parameter TREQ in the protocol.ini or net.cfg to a
+	  small value to make sure your station will win the claim
+	  process.
+	o Start the driver.
+	o When you reach the break point, modify the SA and DA address
+	  of the claim frame (e.g. SA = DA = 10005affffff).
+	o When you see RM3_DETECT and RM6_DETECT, observe the direct
+	  beacon frames on the UPPSLANA.
+
+	END_MANUAL_ENTRY
+ */
+static void directed_beacon(smc)
+struct s_smc *smc ;
+{
+	SK_LOC_DECL(u_int,a[2]) ;
+
+	/*
+	 * set UNA in frame
+	 * enable FORMAC to send endless queue of directed beacon
+	 * important: the UNA starts at byte 1 (not at byte 0)
+	 */
+	* (char *) a = (char) ((long)DBEACON_INFO<<24L) ;
+	a[1] = 0 ;
+	memcpy((char *)a+1,(char *) &smc->mib.m[MAC0].fddiMACUpstreamNbr,6) ;
+
+	CHECK_NPP() ;
+	 /* set memory address reg for writes */
+	MARW(smc->hw.fp.fifo.rbc_ram_start+DBEACON_FRAME_OFF+4) ;
+	write_mdr(smc,MDR_REVERSE(a[0])) ;
+	outpw(FM_A(FM_CMDREG2),FM_ISTTB) ;	/* set the tag bit */
+	write_mdr(smc,MDR_REVERSE(a[1])) ;
+
+	outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF) ;
+}
+
+/*
+	setup claim & beacon pointer
+	NOTE :
+		special frame packets end with a pointer to their own
+		descriptor, and the MORE bit is set in the descriptor
+*/
+static void build_claim_beacon(smc,t_request)
+struct s_smc *smc ;
+u_long t_request;
+{
+	u_int	td ;
+	int	len ;
+	struct fddi_mac_sf *mac ;
+
+	/*
+	 * build claim packet
+	 */
+	len = 17 ;
+	td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ;
+	mac = &smc->hw.fp.mac_sfb ;
+	mac->mac_fc = FC_CLAIM ;
+	/* DA == SA in claim frame */
+	mac->mac_source = mac->mac_dest = MA ;
+	/* 2's complement */
+	set_int((char *)mac->mac_info,(int)t_request) ;
+
+	copy_tx_mac(smc,td,(struct fddi_mac *)mac,
+		smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF,len) ;
+	/* set CLAIM start pointer */
+	outpw(FM_A(FM_SACL),smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF) ;
+
+	/*
+	 * build beacon packet
+	 */
+	len = 17 ;
+	td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ;
+	mac->mac_fc = FC_BEACON ;
+	mac->mac_source = MA ;
+	mac->mac_dest = null_addr ;		/* DA == 0 in beacon frame */
+	set_int((char *) mac->mac_info,((int)BEACON_INFO<<24) + 0 ) ;
+
+	copy_tx_mac(smc,td,(struct fddi_mac *)mac,
+		smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF,len) ;
+	/* set beacon start pointer */
+	outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF) ;
+
+	/*
+	 * build directed beacon packet
+	 * contains optional UNA
+	 */
+	len = 23 ;
+	td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ;
+	mac->mac_fc = FC_BEACON ;
+	mac->mac_source = MA ;
+	mac->mac_dest = dbeacon_multi ;		/* multicast */
+	set_int((char *) mac->mac_info,((int)DBEACON_INFO<<24) + 0 ) ;
+	set_int((char *) mac->mac_info+4,0) ;
+	set_int((char *) mac->mac_info+8,0) ;
+
+	copy_tx_mac(smc,td,(struct fddi_mac *)mac,
+		smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF,len) ;
+
+	/* end of claim/beacon queue */
+	outpw(FM_A(FM_EACB),smc->hw.fp.fifo.rx1_fifo_start-1) ;
+
+	outpw(FM_A(FM_WPXSF),0) ;
+	outpw(FM_A(FM_RPXSF),0) ;
+}
+
+void formac_rcv_restart(smc)
+struct s_smc *smc ;
+{
+	/* enable receive function */
+	SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ;
+
+	outpw(FM_A(FM_CMDREG1),FM_ICLLR) ;	/* clear receive lock */
+}
+
+void formac_tx_restart(smc)
+struct s_smc *smc ;
+{
+	outpw(FM_A(FM_CMDREG1),FM_ICLLS) ;	/* clear s-frame lock */
+	outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ;	/* clear a-frame lock */
+}
+
+static void enable_formac(smc)
+struct s_smc *smc ;
+{
+	/* set formac IMSK : 0 enables irq */
+	outpw(FM_A(FM_IMSK1U),~mac_imsk1u) ;
+	outpw(FM_A(FM_IMSK1L),~mac_imsk1l) ;
+	outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ;
+	outpw(FM_A(FM_IMSK2L),~mac_imsk2l) ;
+	outpw(FM_A(FM_IMSK3U),~mac_imsk3u) ;
+	outpw(FM_A(FM_IMSK3L),~mac_imsk3l) ;
+}
+
+#if 0	/* Removed because the driver should use the ASICs TX complete IRQ. */
+	/* The FORMACs tx complete IRQ should be used any longer */
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;4)
+
+	void enable_tx_irq(smc, queue)
+	struct s_smc *smc ;
+	u_short	queue ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		enable_tx_irq() enables the FORMACs transmit complete
+		interrupt of the queue.
+
+Para	queue	= QUEUE_S:	synchronous queue
+		= QUEUE_A0:	asynchronous queue
+
+Note	After any ring operational change the transmit complete
+	interrupts are disabled.
+	The operating system dependent module must enable
+	the transmit complete interrupt of a queue,
+		- when it queues the first frame,
+		  because of no transmit resources are beeing
+		  available and
+		- when it escapes from the function llc_restart_tx
+		  while some frames are still queued.
+
+	END_MANUAL_ENTRY
+ */
+void enable_tx_irq(smc, queue)
+struct s_smc *smc ;
+u_short	queue ;		/* 0 = synchronous queue, 1 = asynchronous queue 0 */
+{
+	u_short	imask ;
+
+	imask = ~(inpw(FM_A(FM_IMSK1U))) ;
+
+	if (queue == 0) {
+		outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMS)) ;
+	}
+	if (queue == 1) {
+		outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMA0)) ;
+	}
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;4)
+
+	void disable_tx_irq(smc, queue)
+	struct s_smc *smc ;
+	u_short	queue ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		disable_tx_irq disables the FORMACs transmit complete
+		interrupt of the queue
+
+Para	queue	= QUEUE_S:	synchronous queue
+		= QUEUE_A0:	asynchronous queue
+
+Note	The operating system dependent module should disable
+	the transmit complete interrupts if it escapes from the
+	function llc_restart_tx and no frames are queued.
+
+	END_MANUAL_ENTRY
+ */
+void disable_tx_irq(smc, queue)
+struct s_smc *smc ;
+u_short	queue ;		/* 0 = synchronous queue, 1 = asynchronous queue 0 */
+{
+	u_short	imask ;
+
+	imask = ~(inpw(FM_A(FM_IMSK1U))) ;
+
+	if (queue == 0) {
+		outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMS)) ;
+	}
+	if (queue == 1) {
+		outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMA0)) ;
+	}
+}
+#endif
+
+static void disable_formac(smc)
+struct s_smc *smc ;
+{
+	/* clear formac IMSK : 1 disables irq */
+	outpw(FM_A(FM_IMSK1U),MW) ;
+	outpw(FM_A(FM_IMSK1L),MW) ;
+	outpw(FM_A(FM_IMSK2U),MW) ;
+	outpw(FM_A(FM_IMSK2L),MW) ;
+	outpw(FM_A(FM_IMSK3U),MW) ;
+	outpw(FM_A(FM_IMSK3L),MW) ;
+}
+
+
+static void mac_ring_up(smc,up)
+struct s_smc *smc ;
+int up;
+{
+	if (up) {
+		formac_rcv_restart(smc) ;	/* enable receive function */
+		smc->hw.mac_ring_is_up = TRUE ;
+		llc_restart_tx(smc) ;		/* TX queue */
+	}
+	else {
+		/* disable receive function */
+		SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ;
+
+		/* abort current transmit activity */
+		outpw(FM_A(FM_CMDREG2),FM_IACTR) ;
+
+		smc->hw.mac_ring_is_up = FALSE ;
+	}
+}
+
+/*--------------------------- ISR handling ----------------------------------*/
+/*
+ * mac1_irq is in drvfbi.c
+ */
+
+/*
+ * mac2_irq:	status bits for the receive queue 1, and ring status
+ * 		ring status indication bits
+ */
+void mac2_irq(smc,code_s2u,code_s2l)
+struct s_smc *smc ;
+u_short code_s2u ;
+u_short code_s2l ;
+{
+	u_short	change_s2l ;
+	u_short	change_s2u ;
+
+	/* (jd) 22-Feb-1999
+	 * Restart 2_DMax Timer after end of claiming or beaconing
+	 */
+	if (code_s2u & (FM_SCLM|FM_SHICLM|FM_SBEC|FM_SOTRBEC)) {
+		queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ;
+	}
+	else if (code_s2l & (FM_STKISS)) {
+		queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ;
+	}
+
+	/*
+	 * XOR current st bits with the last to avoid useless RMT event queuing
+	 */
+	change_s2l = smc->hw.fp.s2l ^ code_s2l ;
+	change_s2u = smc->hw.fp.s2u ^ code_s2u ;
+
+	if ((change_s2l & FM_SRNGOP) ||
+		(!smc->hw.mac_ring_is_up && ((code_s2l & FM_SRNGOP)))) {
+		if (code_s2l & FM_SRNGOP) {
+			mac_ring_up(smc,1) ;
+			queue_event(smc,EVENT_RMT,RM_RING_OP) ;
+			smc->mib.m[MAC0].fddiMACRingOp_Ct++ ;
+		}
+		else {
+			mac_ring_up(smc,0) ;
+			queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ;
+		}
+		goto mac2_end ;
+	}
+	if (code_s2l & FM_SMISFRM) {	/* missed frame */
+		smc->mib.m[MAC0].fddiMACNotCopied_Ct++ ;
+	}
+	if (code_s2u & (FM_SRCVOVR |	/* recv. FIFO overflow */
+			FM_SRBFL)) {	/* recv. buffer full */
+		smc->hw.mac_ct.mac_r_restart_counter++ ;
+/*		formac_rcv_restart(smc) ;	*/
+		smt_stat_counter(smc,1) ;
+/*		goto mac2_end ;			*/
+	}
+	if (code_s2u & FM_SOTRBEC)
+		queue_event(smc,EVENT_RMT,RM_OTHER_BEACON) ;
+	if (code_s2u & FM_SMYBEC)
+		queue_event(smc,EVENT_RMT,RM_MY_BEACON) ;
+	if (change_s2u & code_s2u & FM_SLOCLM) {
+		DB_RMTN(2,"RMT : lower claim received\n",0,0) ;
+	}
+	if ((code_s2u & FM_SMYCLM) && !(code_s2l & FM_SDUPCLM)) {
+		/*
+		 * This is my claim and that claim is not detected as a
+		 * duplicate one.
+		 */
+		queue_event(smc,EVENT_RMT,RM_MY_CLAIM) ;
+	}
+	if (code_s2l & FM_SDUPCLM) {
+		/*
+		 * If a duplicate claim frame (same SA but T_Bid != T_Req)
+		 * this flag will be set.
+		 * In the RMT state machine we need a RM_VALID_CLAIM event
+		 * to do the appropriate state change.
+		 * RM(34c)
+		 */
+		queue_event(smc,EVENT_RMT,RM_VALID_CLAIM) ;
+	}
+	if (change_s2u & code_s2u & FM_SHICLM) {
+		DB_RMTN(2,"RMT : higher claim received\n",0,0) ;
+	}
+	if ( (code_s2l & FM_STRTEXP) ||
+	     (code_s2l & FM_STRTEXR) )
+		queue_event(smc,EVENT_RMT,RM_TRT_EXP) ;
+	if (code_s2l & FM_SMULTDA) {
+		/*
+		 * The MAC has found a 2. MAC with the same address.
+		 * Signal dup_addr_test = failed to RMT state machine.
+		 * RM(25)
+		 */
+		smc->r.dup_addr_test = DA_FAILED ;
+		queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
+	}
+	if (code_s2u & FM_SBEC)
+		smc->hw.fp.err_stats.err_bec_stat++ ;
+	if (code_s2u & FM_SCLM)
+		smc->hw.fp.err_stats.err_clm_stat++ ;
+	if (code_s2l & FM_STVXEXP)
+		smc->mib.m[MAC0].fddiMACTvxExpired_Ct++ ;
+	if ((code_s2u & (FM_SBEC|FM_SCLM))) {
+		if (!(change_s2l & FM_SRNGOP) && (smc->hw.fp.s2l & FM_SRNGOP)) {
+			mac_ring_up(smc,0) ;
+			queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ;
+
+			mac_ring_up(smc,1) ;
+			queue_event(smc,EVENT_RMT,RM_RING_OP) ;
+			smc->mib.m[MAC0].fddiMACRingOp_Ct++ ;
+		}
+	}
+	if (code_s2l & FM_SPHINV)
+		smc->hw.fp.err_stats.err_phinv++ ;
+	if (code_s2l & FM_SSIFG)
+		smc->hw.fp.err_stats.err_sifg_det++ ;
+	if (code_s2l & FM_STKISS)
+		smc->hw.fp.err_stats.err_tkiss++ ;
+	if (code_s2l & FM_STKERR)
+		smc->hw.fp.err_stats.err_tkerr++ ;
+	if (code_s2l & FM_SFRMCTR)
+		smc->mib.m[MAC0].fddiMACFrame_Ct += 0x10000L ;
+	if (code_s2l & FM_SERRCTR)
+		smc->mib.m[MAC0].fddiMACError_Ct += 0x10000L ;
+	if (code_s2l & FM_SLSTCTR)
+		smc->mib.m[MAC0].fddiMACLost_Ct  += 0x10000L ;
+	if (code_s2u & FM_SERRSF) {
+		SMT_PANIC(smc,SMT_E0114, SMT_E0114_MSG) ;
+	}
+mac2_end:
+	/* notice old status */
+	smc->hw.fp.s2l = code_s2l ;
+	smc->hw.fp.s2u = code_s2u ;
+	outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ;
+}
+
+/*
+ * mac3_irq:	receive queue 2 bits and address detection bits
+ */
+void mac3_irq(smc,code_s3u,code_s3l)
+struct s_smc *smc ;
+u_short code_s3u ;
+u_short code_s3l ;
+{
+	UNUSED(code_s3l) ;
+
+	if (code_s3u & (FM_SRCVOVR2 |	/* recv. FIFO overflow */
+			FM_SRBFL2)) {	/* recv. buffer full */
+		smc->hw.mac_ct.mac_r_restart_counter++ ;
+		smt_stat_counter(smc,1);
+	}
+
+
+	if (code_s3u & FM_SRPERRQ2) {	/* parity error receive queue 2 */
+		SMT_PANIC(smc,SMT_E0115, SMT_E0115_MSG) ;
+	}
+	if (code_s3u & FM_SRPERRQ1) {	/* parity error receive queue 2 */
+		SMT_PANIC(smc,SMT_E0116, SMT_E0116_MSG) ;
+	}
+}
+
+
+/*
+ * take formac offline
+ */
+static void formac_offline(smc)
+struct s_smc *smc ;
+{
+	outpw(FM_A(FM_CMDREG2),FM_IACTR) ;/* abort current transmit activity */
+
+	/* disable receive function */
+	SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ;
+
+	/* FORMAC+ 'Initialize Mode' */
+	SETMASK(FM_A(FM_MDREG1),FM_MINIT,FM_MMODE) ;
+
+	disable_formac(smc) ;
+	smc->hw.mac_ring_is_up = FALSE ;
+	smc->hw.hw_state = STOPPED ;
+}
+
+/*
+ * bring formac online
+ */
+static void formac_online(smc)
+struct s_smc *smc ;
+{
+	enable_formac(smc) ;
+	SETMASK(FM_A(FM_MDREG1),FM_MONLINE | FM_SELRA | MDR1INIT |
+		smc->hw.fp.rx_mode, FM_MMODE | FM_SELRA | FM_ADDRX) ;
+}
+
+/*
+ * FORMAC+ full init. (tx, rx, timer, counter, claim & beacon)
+ */
+int init_fplus(smc)
+struct s_smc *smc ;
+{
+	smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ;
+	smc->hw.fp.rx_mode = FM_MDAMA ;
+	smc->hw.fp.group_addr = fddi_broadcast ;
+	smc->hw.fp.func_addr = 0 ;
+	smc->hw.fp.frselreg_init = 0 ;
+
+	init_driver_fplus(smc) ;
+	if (smc->s.sas == SMT_DAS)
+		smc->hw.fp.mdr3init |= FM_MENDAS ;
+
+	smc->hw.mac_ct.mac_nobuf_counter = 0 ;
+	smc->hw.mac_ct.mac_r_restart_counter = 0 ;
+
+	smc->hw.fp.fm_st1u = (HW_PTR) ADDR(B0_ST1U) ;
+	smc->hw.fp.fm_st1l = (HW_PTR) ADDR(B0_ST1L) ;
+	smc->hw.fp.fm_st2u = (HW_PTR) ADDR(B0_ST2U) ;
+	smc->hw.fp.fm_st2l = (HW_PTR) ADDR(B0_ST2L) ;
+	smc->hw.fp.fm_st3u = (HW_PTR) ADDR(B0_ST3U) ;
+	smc->hw.fp.fm_st3l = (HW_PTR) ADDR(B0_ST3L) ;
+
+	smc->hw.fp.s2l = smc->hw.fp.s2u = 0 ;
+	smc->hw.mac_ring_is_up = 0 ;
+
+	mac_counter_init(smc) ;
+
+	/* convert BCKL units to symbol time */
+	smc->hw.mac_pa.t_neg = (u_long)0 ;
+	smc->hw.mac_pa.t_pri = (u_long)0 ;
+
+	/* make sure all PCI settings are correct */
+	mac_do_pci_fix(smc) ;
+
+	return(init_mac(smc,1)) ;
+	/* enable_formac(smc) ; */
+}
+
+static int init_mac(smc,all)
+struct s_smc *smc ;
+int all ;
+{
+	u_short	t_max,x ;
+	u_long	time=0 ;
+
+	/*
+	 * clear memory
+	 */
+	outpw(FM_A(FM_MDREG1),FM_MINIT) ;	/* FORMAC+ init mode */
+	set_formac_addr(smc) ;
+	outpw(FM_A(FM_MDREG1),FM_MMEMACT) ;	/* FORMAC+ memory activ mode */
+	/* Note: Mode register 2 is set here, incase parity is enabled. */
+	outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ;
+
+	if (all) {
+		init_ram(smc) ;
+	}
+	else {
+		/*
+		 * reset the HPI, the Master and the BMUs
+		 */
+		outp(ADDR(B0_CTRL), CTRL_HPI_SET) ;
+		time = hwt_quick_read(smc) ;
+	}
+
+	/*
+	 * set all pointers, frames etc
+	 */
+	smt_split_up_fifo(smc) ;
+
+	init_tx(smc) ;
+	init_rx(smc) ;
+	init_rbc(smc) ;
+
+	build_claim_beacon(smc,smc->mib.m[MAC0].fddiMACT_Req) ;
+
+	/* set RX threshold */
+	/* see Errata #SN2 Phantom receive overflow */
+	outpw(FM_A(FM_FRMTHR),14<<12) ;		/* switch on */
+
+	/* set formac work mode */
+	outpw(FM_A(FM_MDREG1),MDR1INIT | FM_SELRA | smc->hw.fp.rx_mode) ;
+	outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ;
+	outpw(FM_A(FM_MDREG3),smc->hw.fp.mdr3init) ;
+	outpw(FM_A(FM_FRSELREG),smc->hw.fp.frselreg_init) ;
+
+	/* set timer */
+	/*
+	 * errata #22 fplus:
+	 * T_MAX must not be FFFE
+	 * or one of FFDF, FFB8, FF91 (-0x27 etc..)
+	 */
+	t_max = (u_short)(smc->mib.m[MAC0].fddiMACT_Max/32) ;
+	x = t_max/0x27 ;
+	x *= 0x27 ;
+	if ((t_max == 0xfffe) || (t_max - x == 0x16))
+		t_max-- ;
+	outpw(FM_A(FM_TMAX),(u_short)t_max) ;
+
+	/* BugFix for report #10204 */
+	if (smc->mib.m[MAC0].fddiMACTvxValue < (u_long) (- US2BCLK(52))) {
+		outpw(FM_A(FM_TVX), (u_short) (- US2BCLK(52))/255 & MB) ;
+	} else {
+		outpw(FM_A(FM_TVX),
+			(u_short)((smc->mib.m[MAC0].fddiMACTvxValue/255) & MB)) ;
+	}
+
+	outpw(FM_A(FM_CMDREG1),FM_ICLLS) ;	/* clear s-frame lock */
+	outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ;	/* clear a-frame lock */
+	outpw(FM_A(FM_CMDREG1),FM_ICLLR);	/* clear receive lock */
+
+	/* Auto unlock receice threshold for receive queue 1 and 2 */
+	outpw(FM_A(FM_UNLCKDLY),(0xff|(0xff<<8))) ;
+
+	rtm_init(smc) ;				/* RT-Monitor */
+
+	if (!all) {
+		/*
+		 * after 10ms, reset the BMUs and repair the rings
+		 */
+		hwt_wait_time(smc,time,MS2BCLK(10)) ;
+		outpd(ADDR(B0_R1_CSR),CSR_SET_RESET) ;
+		outpd(ADDR(B0_XA_CSR),CSR_SET_RESET) ;
+		outpd(ADDR(B0_XS_CSR),CSR_SET_RESET) ;
+		outp(ADDR(B0_CTRL), CTRL_HPI_CLR) ;
+		outpd(ADDR(B0_R1_CSR),CSR_CLR_RESET) ;
+		outpd(ADDR(B0_XA_CSR),CSR_CLR_RESET) ;
+		outpd(ADDR(B0_XS_CSR),CSR_CLR_RESET) ;
+		if (!smc->hw.hw_is_64bit) {
+			outpd(ADDR(B4_R1_F), RX_WATERMARK) ;
+			outpd(ADDR(B5_XA_F), TX_WATERMARK) ;
+			outpd(ADDR(B5_XS_F), TX_WATERMARK) ;
+		}
+		smc->hw.hw_state = STOPPED ;
+		mac_drv_repair_descr(smc) ;
+	}
+	smc->hw.hw_state = STARTED ;
+
+	return(0) ;
+}
+
+
+/*
+ * called by CFM
+ */
+void config_mux(smc,mux)
+struct s_smc *smc ;
+int mux;
+{
+	plc_config_mux(smc,mux) ;
+
+	SETMASK(FM_A(FM_MDREG1),FM_SELRA,FM_SELRA) ;
+}
+
+/*
+ * called by RMT
+ * enable CLAIM/BEACON interrupts
+ * (only called if these events are of interest, e.g. in DETECT state
+ * the interrupt must not be permanently enabled
+ * RMT calls this function periodically (timer driven polling)
+ */
+void sm_mac_check_beacon_claim(smc)
+struct s_smc *smc ;
+{
+	/* set formac IMSK : 0 enables irq */
+	outpw(FM_A(FM_IMSK2U),~(mac_imsk2u | mac_beacon_imsk2u)) ;
+	/* the driver must receive the directed beacons */
+	formac_rcv_restart(smc) ;
+	process_receive(smc) ;
+}
+
+/*-------------------------- interface functions ----------------------------*/
+/*
+ * control ODL output
+ */
+void sm_pm_control(smc,mode)
+struct s_smc *smc ;
+int mode;
+{
+	SK_UNUSED(smc) ;
+
+	/*
+	 * if PCM logic has set LS_REQUEST = Transmit QUIET Line State
+	 *	/FOTOFF signal turn activ -> ODL disable
+	 */
+	switch(mode) {
+	case PM_TRANSMIT_DISABLE :
+		break ;
+	case PM_TRANSMIT_ENABLE :
+		break ;
+	}
+}
+
+/*
+ * control MAC layer	(called by RMT)
+ */
+void sm_ma_control(smc,mode)
+struct s_smc *smc ;
+int mode;
+{
+	switch(mode) {
+	case MA_OFFLINE :
+		/* Add to make the MAC offline in RM0_ISOLATED state */
+		formac_offline(smc) ;
+		break ;
+	case MA_RESET :
+		(void)init_mac(smc,0) ;
+		break ;
+	case MA_BEACON :
+		formac_online(smc) ;
+		break ;
+	case MA_DIRECTED :
+		directed_beacon(smc) ;
+		break ;
+	case MA_TREQ :
+		/*
+		 * no actions necessary, TREQ is already set
+		 */
+		break ;
+	}
+}
+
+int sm_mac_get_tx_state(smc)
+struct s_smc *smc ;
+{
+	return((inpw(FM_A(FM_STMCHN))>>4)&7) ;
+}
+
+/*
+ * multicast functions
+ */
+
+static struct s_fpmc	*mac_get_mc_table(smc,user,own,del,can)
+struct s_smc *smc ;
+struct fddi_addr *user ;
+struct fddi_addr *own ;
+int del ;
+int can ;
+{
+	struct s_fpmc	*tb ;
+	struct s_fpmc	*slot ;
+	u_char	*p ;
+	int i ;
+
+	/*
+	 * set own = can(user)
+	 */
+	*own = *user ;
+	if (can) {
+		p = own->a ;
+		for (i = 0 ; i < 6 ; i++, p++)
+			*p = canonical[*p] ;
+	}
+	slot = 0 ;
+	for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
+		if (!tb->n) {		/* not used */
+			if (!del && !slot)	/* if !del save first free */
+				slot = tb ;
+			continue ;
+		}
+		if (memcmp((char *)&tb->a,(char *)own,6))
+			continue ;
+		return(tb) ;
+	}
+	return(slot) ;			/* return first free or NULL */
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	void mac_clear_multicast(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		Clear all multicast entries
+
+	END_MANUAL_ENTRY()
+ */
+void mac_clear_multicast(smc)
+struct s_smc *smc ;
+{
+	struct s_fpmc	*tb ;
+	int i ;
+
+	smc->hw.fp.os_slots_used = 0 ;	/* note the SMT addresses */
+					/* will not be deleted */
+	for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
+		if (!tb->perm) {
+			tb->n = 0 ;
+		}
+	}
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	int mac_set_func_addr(smc,f_addr)
+	struct s_smc *smc ;
+	u_long f_addr ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		Set a Token-Ring functional address, the address will
+		be activated after calling mac_update_multicast()
+
+Para	f_addr	functional bits in non-canonical format
+
+Returns	0: always success
+
+	END_MANUAL_ENTRY()
+ */
+int mac_set_func_addr(smc,f_addr)
+struct s_smc *smc ;
+u_long f_addr ;
+{
+	smc->hw.fp.func_addr = f_addr ;
+	return(0) ;
+}
+
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	int mac_add_multicast(smc,addr,can)
+	struct s_smc *smc ;
+	struct fddi_addr *addr ;
+	int can ;
+
+Function	DOWNCALL	(SMC, fplustm.c)
+		Add an entry to the multicast table
+
+Para	addr	pointer to a multicast address
+	can	= 0:	the multicast address has the physical format
+		= 1:	the multicast address has the canonical format
+		| 0x80	permanent
+
+Returns	0: success
+	1: address table full
+
+Note	After a 'driver reset' or a 'station set address' all
+	entries of the multicast table are cleared.
+	In this case the driver has to fill the multicast table again.
+	After the operating system dependent module filled
+	the multicast table it must call mac_update_multicast
+	to activate the new multicast addresses!
+
+	END_MANUAL_ENTRY()
+ */
+int mac_add_multicast(smc,addr,can)
+struct s_smc *smc ;
+struct fddi_addr *addr ;
+int can ;
+{
+	SK_LOC_DECL(struct fddi_addr,own) ;
+	struct s_fpmc	*tb ;
+
+	/*
+	 * check if there are free table entries
+	 */
+	if (can & 0x80) {
+		if (smc->hw.fp.smt_slots_used >= SMT_MAX_MULTI) {
+			return(1) ;
+		}
+	}
+	else {
+		if (smc->hw.fp.os_slots_used >= FPMAX_MULTICAST-SMT_MAX_MULTI) {
+			return(1) ;
+		}
+	}
+
+	/*
+	 * find empty slot
+	 */
+	if (!(tb = mac_get_mc_table(smc,addr,&own,0,can & ~0x80)))
+		return(1) ;
+	tb->n++ ;
+	tb->a = own ;
+	tb->perm = (can & 0x80) ? 1 : 0 ;
+
+	if (can & 0x80)
+		smc->hw.fp.smt_slots_used++ ;
+	else
+		smc->hw.fp.os_slots_used++ ;
+
+	return(0) ;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	void mac_del_multicast(smc,addr,can)
+	struct s_smc *smc ;
+	struct fddi_addr *addr ;
+	int can ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		Delete an entry from the multicast table
+
+Para	addr	pointer to a multicast address
+	can	= 0:	the multicast address has the physical format
+		= 1:	the multicast address has the canonical format
+		| 0x80	permanent
+
+	END_MANUAL_ENTRY()
+ */
+void mac_del_multicast(smc,addr,can)
+struct s_smc *smc ;
+struct fddi_addr *addr ;
+int can ;
+{
+	SK_LOC_DECL(struct fddi_addr,own) ;
+	struct s_fpmc	*tb ;
+
+	if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80)))
+		return ;
+	/*
+	 * permanent addresses must be deleted with perm bit
+	 * and vice versa
+	 */
+	if (( tb->perm &&  (can & 0x80)) ||
+	    (!tb->perm && !(can & 0x80))) {
+		/*
+		 * delete it
+		 */
+		if (tb->n) {
+			tb->n-- ;
+			if (tb->perm) {
+				smc->hw.fp.smt_slots_used-- ;
+			}
+			else {
+				smc->hw.fp.os_slots_used-- ;
+			}
+		}
+	}
+}
+
+/*
+ * mode
+ */
+
+#define RX_MODE_PROM		0x1
+#define RX_MODE_ALL_MULTI	0x2
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;2)
+
+	void mac_update_multicast(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, fplustm.c)
+		Update FORMAC multicast registers
+
+	END_MANUAL_ENTRY()
+ */
+void mac_update_multicast(smc)
+struct s_smc *smc ;
+{
+	struct s_fpmc	*tb ;
+	u_char	*fu ;
+	int	i ;
+
+	/*
+	 * invalidate the CAM
+	 */
+	outpw(FM_A(FM_AFCMD),FM_IINV_CAM) ;
+
+	/*
+	 * set the functional address
+	 */
+	if (smc->hw.fp.func_addr) {
+		fu = (u_char *) &smc->hw.fp.func_addr ;
+		outpw(FM_A(FM_AFMASK2),0xffff) ;
+		outpw(FM_A(FM_AFMASK1),(u_short) ~((fu[0] << 8) + fu[1])) ;
+		outpw(FM_A(FM_AFMASK0),(u_short) ~((fu[2] << 8) + fu[3])) ;
+		outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ;
+		outpw(FM_A(FM_AFCOMP2), 0xc000) ;
+		outpw(FM_A(FM_AFCOMP1), 0x0000) ;
+		outpw(FM_A(FM_AFCOMP0), 0x0000) ;
+		outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ;
+	}
+
+	/*
+	 * set the mask and the personality register(s)
+	 */
+	outpw(FM_A(FM_AFMASK0),0xffff) ;
+	outpw(FM_A(FM_AFMASK1),0xffff) ;
+	outpw(FM_A(FM_AFMASK2),0xffff) ;
+	outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ;
+
+	for (i = 0, tb = smc->hw.fp.mc.table; i < FPMAX_MULTICAST; i++, tb++) {
+		if (tb->n) {
+			CHECK_CAM() ;
+
+			/*
+			 * wirte the multicast addres into the CAM
+			 */
+			outpw(FM_A(FM_AFCOMP2),
+				(u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ;
+			outpw(FM_A(FM_AFCOMP1),
+				(u_short)((tb->a.a[2]<<8)+tb->a.a[3])) ;
+			outpw(FM_A(FM_AFCOMP0),
+				(u_short)((tb->a.a[4]<<8)+tb->a.a[5])) ;
+			outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ;
+		}
+	}
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;3)
+
+	void mac_set_rx_mode(smc,mode)
+	struct s_smc *smc ;
+	int mode ;
+
+Function	DOWNCALL/INTERN	(SMT, fplustm.c)
+		This function enables / disables the selected receive.
+		Don't call this function if the hardware module is
+		used -- use mac_drv_rx_mode() instead of.
+
+Para	mode =	1	RX_ENABLE_ALLMULTI	enable all multicasts
+		2	RX_DISABLE_ALLMULTI	disable "enable all multicasts"
+		3	RX_ENABLE_PROMISC	enable promiscous
+		4	RX_DISABLE_PROMISC	disable promiscous
+		5	RX_ENABLE_NSA		enable reception of NSA frames
+		6	RX_DISABLE_NSA		disable reception of NSA frames
+
+Note	The selected receive modes will be lost after 'driver reset'
+	or 'set station address'
+
+	END_MANUAL_ENTRY
+ */
+void mac_set_rx_mode(smc,mode)
+struct s_smc *smc ;
+int mode ;
+{
+	switch (mode) {
+	case RX_ENABLE_ALLMULTI :
+		smc->hw.fp.rx_prom |= RX_MODE_ALL_MULTI ;
+		break ;
+	case RX_DISABLE_ALLMULTI :
+		smc->hw.fp.rx_prom &= ~RX_MODE_ALL_MULTI ;
+		break ;
+	case RX_ENABLE_PROMISC :
+		smc->hw.fp.rx_prom |= RX_MODE_PROM ;
+		break ;
+	case RX_DISABLE_PROMISC :
+		smc->hw.fp.rx_prom &= ~RX_MODE_PROM ;
+		break ;
+	case RX_ENABLE_NSA :
+		smc->hw.fp.nsa_mode = FM_MDAMA ;
+		smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) |
+			smc->hw.fp.nsa_mode ;
+		break ;
+	case RX_DISABLE_NSA :
+		smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ;
+		smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) |
+			smc->hw.fp.nsa_mode ;
+		break ;
+	}
+	if (smc->hw.fp.rx_prom & RX_MODE_PROM) {
+		smc->hw.fp.rx_mode = FM_MLIMPROM ;
+	}
+	else if (smc->hw.fp.rx_prom & RX_MODE_ALL_MULTI) {
+		smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode | FM_EXGPA0 ;
+	}
+	else
+		smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode ;
+	SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ;
+	mac_update_multicast(smc) ;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(module;tests;3)
+	How to test the Restricted Token Monitor
+	----------------------------------------------------------------
+
+	o Insert a break point in the function rtm_irq()
+	o Remove all stations with a restricted token monitor from the
+	  network.
+	o Connect a UPPS ISA or EISA station to the network.
+	o Give the FORMAC of UPPS station the command to send
+	  restricted tokens until the ring becomes instable.
+	o Now connect your test test client.
+	o The restricted token monitor should detect the restricted token,
+	  and your break point will be reached.
+	o You can ovserve how the station will clean the ring.
+
+	END_MANUAL_ENTRY
+ */
+void rtm_irq(smc)
+struct s_smc *smc ;
+{
+	outpw(ADDR(B2_RTM_CRTL),TIM_CL_IRQ) ;		/* clear IRQ */
+	if (inpw(ADDR(B2_RTM_CRTL)) & TIM_RES_TOK) {
+		outpw(FM_A(FM_CMDREG1),FM_ICL) ;	/* force claim */
+		DB_RMT("RMT: fddiPATHT_Rmode expired\n",0,0) ;
+		AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
+				(u_long) FDDI_SMT_EVENT,
+				(u_long) FDDI_RTT, smt_get_event_word(smc));
+	}
+	outpw(ADDR(B2_RTM_CRTL),TIM_START) ;	/* enable RTM monitoring */
+}
+
+static void rtm_init(smc)
+struct s_smc *smc ;
+{
+	outpd(ADDR(B2_RTM_INI),0) ;		/* timer = 0 */
+	outpw(ADDR(B2_RTM_CRTL),TIM_START) ;	/* enable IRQ */
+}
+
+void rtm_set_timer(smc)
+struct s_smc *smc ;
+{
+	/*
+	 * MIB timer and hardware timer have the same resolution of 80nS
+	 */
+	DB_RMT("RMT: setting new fddiPATHT_Rmode, t = %d ns \n",
+		(int) smc->mib.a[PATH0].fddiPATHT_Rmode,0) ;
+	outpd(ADDR(B2_RTM_INI),smc->mib.a[PATH0].fddiPATHT_Rmode) ;
+}
+
+static void smt_split_up_fifo(smc)
+struct s_smc *smc ;
+{
+
+/*
+	BEGIN_MANUAL_ENTRY(module;mem;1)
+	-------------------------------------------------------------
+	RECEIVE BUFFER MEMORY DIVERSION
+	-------------------------------------------------------------
+
+	R1_RxD == SMT_R1_RXD_COUNT
+	R2_RxD == SMT_R2_RXD_COUNT
+
+	SMT_R1_RXD_COUNT must be unequal zero
+
+		   | R1_RxD R2_RxD |R1_RxD R2_RxD | R1_RxD R2_RxD
+		   |   x      0	   |  x	    1-3	  |   x     < 3
+	----------------------------------------------------------------------
+		   |   63,75 kB	   |    54,75	  |	R1_RxD
+	rx queue 1 | RX_FIFO_SPACE | RX_LARGE_FIFO| ------------- * 63,75 kB
+		   |		   |		  | R1_RxD+R2_RxD
+	----------------------------------------------------------------------
+		   |		   |    9 kB	  |     R2_RxD
+	rx queue 2 |	0 kB	   | RX_SMALL_FIFO| ------------- * 63,75 kB
+		   |  (not used)   |		  | R1_RxD+R2_RxD
+
+	END_MANUAL_ENTRY
+*/
+
+	if (SMT_R1_RXD_COUNT == 0) {
+		SMT_PANIC(smc,SMT_E0117, SMT_E0117_MSG) ;
+	}
+
+	switch(SMT_R2_RXD_COUNT) {
+	case 0:
+		smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE ;
+		smc->hw.fp.fifo.rx2_fifo_size = 0 ;
+		break ;
+	case 1:
+	case 2:
+	case 3:
+		smc->hw.fp.fifo.rx1_fifo_size = RX_LARGE_FIFO ;
+		smc->hw.fp.fifo.rx2_fifo_size = RX_SMALL_FIFO ;
+		break ;
+	default:	/* this is not the real defaule */
+		smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE *
+		SMT_R1_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ;
+		smc->hw.fp.fifo.rx2_fifo_size = RX_FIFO_SPACE *
+		SMT_R2_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ;
+		break ;
+	}
+
+/*
+	BEGIN_MANUAL_ENTRY(module;mem;1)
+	-------------------------------------------------------------
+	TRANSMIT BUFFER MEMORY DIVERSION
+	-------------------------------------------------------------
+
+
+		 | no sync bw	| sync bw available and | sync bw available and
+		 | available	| SynchTxMode = SPLIT	| SynchTxMode = ALL
+	-----------------------------------------------------------------------
+	sync tx	 |     0 kB	|	32 kB		|	55 kB
+	queue	 |		|   TX_MEDIUM_FIFO	|   TX_LARGE_FIFO
+	-----------------------------------------------------------------------
+	async tx |    64 kB	|	32 kB		|	 9 k
+	queue	 | TX_FIFO_SPACE|   TX_MEDIUM_FIFO	|   TX_SMALL_FIFO
+
+	END_MANUAL_ENTRY
+*/
+
+	/*
+	 * set the tx mode bits
+	 */
+	if (smc->mib.a[PATH0].fddiPATHSbaPayload) {
+#ifdef ESS
+		smc->hw.fp.fifo.fifo_config_mode |=
+			smc->mib.fddiESSSynchTxMode | SYNC_TRAFFIC_ON ;
+#endif
+	}
+	else {
+		smc->hw.fp.fifo.fifo_config_mode &=
+			~(SEND_ASYNC_AS_SYNC|SYNC_TRAFFIC_ON) ;
+	}
+
+	/*
+	 * split up the FIFO
+	 */
+	if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON) {
+		if (smc->hw.fp.fifo.fifo_config_mode & SEND_ASYNC_AS_SYNC) {
+			smc->hw.fp.fifo.tx_s_size = TX_LARGE_FIFO ;
+			smc->hw.fp.fifo.tx_a0_size = TX_SMALL_FIFO ;
+		}
+		else {
+			smc->hw.fp.fifo.tx_s_size = TX_MEDIUM_FIFO ;
+			smc->hw.fp.fifo.tx_a0_size = TX_MEDIUM_FIFO ;
+		}
+	}
+	else {
+			smc->hw.fp.fifo.tx_s_size = 0 ;
+			smc->hw.fp.fifo.tx_a0_size = TX_FIFO_SPACE ;
+	}
+
+	smc->hw.fp.fifo.rx1_fifo_start = smc->hw.fp.fifo.rbc_ram_start +
+		RX_FIFO_OFF ;
+	smc->hw.fp.fifo.tx_s_start = smc->hw.fp.fifo.rx1_fifo_start +
+		smc->hw.fp.fifo.rx1_fifo_size ;
+	smc->hw.fp.fifo.tx_a0_start = smc->hw.fp.fifo.tx_s_start +
+		smc->hw.fp.fifo.tx_s_size ;
+	smc->hw.fp.fifo.rx2_fifo_start = smc->hw.fp.fifo.tx_a0_start +
+		smc->hw.fp.fifo.tx_a0_size ;
+
+	DB_SMT("FIFO split: mode = %x\n",smc->hw.fp.fifo.fifo_config_mode,0) ;
+	DB_SMT("rbc_ram_start =	%x	 rbc_ram_end = 	%x\n",
+		smc->hw.fp.fifo.rbc_ram_start, smc->hw.fp.fifo.rbc_ram_end) ;
+	DB_SMT("rx1_fifo_start = %x	 tx_s_start = 	%x\n",
+		smc->hw.fp.fifo.rx1_fifo_start, smc->hw.fp.fifo.tx_s_start) ;
+	DB_SMT("tx_a0_start =	%x	 rx2_fifo_start = 	%x\n",
+		smc->hw.fp.fifo.tx_a0_start, smc->hw.fp.fifo.rx2_fifo_start) ;
+}
+
+void formac_reinit_tx(smc)
+struct s_smc *smc ;
+{
+	/*
+	 * Split up the FIFO and reinitialize the MAC if synchronous
+	 * bandwidth becomes available but no synchronous queue is
+	 * configured.
+	 */
+	if (!smc->hw.fp.fifo.tx_s_size && smc->mib.a[PATH0].fddiPATHSbaPayload){
+		(void)init_mac(smc,0) ;
+	}
+}
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/cmtdef.h linux.18p8/drivers/net/skfp/h/cmtdef.h
--- linux.vanilla/drivers/net/skfp/h/cmtdef.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/cmtdef.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,801 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_CMTDEF_
+#define _CMTDEF_
+
+/* **************************************************************** */
+
+/*
+ * implementation specific constants
+ * MODIIFY THE FOLLWOING THREE DEFINES
+ */
+#define AMDPLC			/* if Amd PLC chip used */
+#ifdef	CONC
+#define NUMPHYS		12	/* 2 for SAS or DAS, more for Concentrator */
+#else
+#ifdef	CONC_II
+#define NUMPHYS		24	/* 2 for SAS or DAS, more for Concentrator */
+#else
+#define NUMPHYS		2	/* 2 for SAS or DAS, more for Concentrator */
+#endif
+#endif
+#define NUMMACS		1	/* only 1 supported at the moment */
+#define NUMPATHS	2	/* primary and secondary path supported */
+
+/*
+ * DO NOT MODIFY BEYOND THIS POINT
+ */
+
+/* **************************************************************** */
+
+#if	NUMPHYS > 2
+#define CONCENTRATOR
+#endif
+
+/*
+ * Definitions for comfortable LINT usage
+ */
+#ifdef	lint
+#define LINT_USE(x)	(x)=(x)
+#else
+#define LINT_USE(x)
+#endif
+
+#ifdef	DEBUG
+#define	DB_PR(flag,a,b,c)	{ if (flag) printf(a,b,c) ; }
+#else
+#define	DB_PR(flag,a,b,c)
+#endif
+
+#ifdef DEBUG_BRD
+#define DB_ECM(a,b,c)		DB_PR((smc->debug.d_smt&1),a,b,c)
+#define DB_ECMN(n,a,b,c)	DB_PR((smc->debug.d_ecm >=(n)),a,b,c)
+#define DB_RMT(a,b,c)		DB_PR((smc->debug.d_smt&2),a,b,c)
+#define DB_RMTN(n,a,b,c)	DB_PR((smc->debug.d_rmt >=(n)),a,b,c)
+#define DB_CFM(a,b,c)		DB_PR((smc->debug.d_smt&4),a,b,c)
+#define DB_CFMN(n,a,b,c)	DB_PR((smc->debug.d_cfm >=(n)),a,b,c)
+#define DB_PCM(a,b,c)		DB_PR((smc->debug.d_smt&8),a,b,c)
+#define DB_PCMN(n,a,b,c)	DB_PR((smc->debug.d_pcm >=(n)),a,b,c)
+#define DB_SMT(a,b,c)		DB_PR((smc->debug.d_smtf),a,b,c)
+#define DB_SMTN(n,a,b,c)	DB_PR((smc->debug.d_smtf >=(n)),a,b,c)
+#define DB_SBA(a,b,c)		DB_PR((smc->debug.d_sba),a,b,c)
+#define DB_SBAN(n,a,b,c)	DB_PR((smc->debug.d_sba >=(n)),a,b,c)
+#define DB_ESS(a,b,c)		DB_PR((smc->debug.d_ess),a,b,c)
+#define DB_ESSN(n,a,b,c)	DB_PR((smc->debug.d_ess >=(n)),a,b,c)
+#else
+#define DB_ECM(a,b,c)		DB_PR((debug.d_smt&1),a,b,c)
+#define DB_ECMN(n,a,b,c)	DB_PR((debug.d_ecm >=(n)),a,b,c)
+#define DB_RMT(a,b,c)		DB_PR((debug.d_smt&2),a,b,c)
+#define DB_RMTN(n,a,b,c)	DB_PR((debug.d_rmt >=(n)),a,b,c)
+#define DB_CFM(a,b,c)		DB_PR((debug.d_smt&4),a,b,c)
+#define DB_CFMN(n,a,b,c)	DB_PR((debug.d_cfm >=(n)),a,b,c)
+#define DB_PCM(a,b,c)		DB_PR((debug.d_smt&8),a,b,c)
+#define DB_PCMN(n,a,b,c)	DB_PR((debug.d_pcm >=(n)),a,b,c)
+#define DB_SMT(a,b,c)		DB_PR((debug.d_smtf),a,b,c)
+#define DB_SMTN(n,a,b,c)	DB_PR((debug.d_smtf >=(n)),a,b,c)
+#define DB_SBA(a,b,c)		DB_PR((debug.d_sba),a,b,c)
+#define DB_SBAN(n,a,b,c)	DB_PR((debug.d_sba >=(n)),a,b,c)
+#define DB_ESS(a,b,c)		DB_PR((debug.d_ess),a,b,c)
+#define DB_ESSN(n,a,b,c)	DB_PR((debug.d_ess >=(n)),a,b,c)
+#endif
+
+#ifndef	SS_NOT_DS
+#define	SK_LOC_DECL(type,var)	type var
+#else
+#define	SK_LOC_DECL(type,var)	static type var
+#endif
+/*
+ * PHYs and PORTS
+ * Note: Don't touch the definition of PA and PB. Those might be used
+ *	by some "for" loops.
+ */
+#define PA		0
+#define PB		1
+#if	defined(SUPERNET_3) || defined(CONC_II)
+/*
+ * The port indices have to be different,
+ * because the MAC output goes through the 2. PLC
+ * Conc II: It has to be the first port in the row.
+ */
+#define PS		0	/* Internal PLC which is the same as PA */
+#else
+#define PS		1
+#endif
+#define PM		2		/* PM .. PA+NUM_PHYS-1 */
+
+/*
+ * PHY types - as in path descriptor 'fddiPHYType'
+ */
+#define TA			0	/* A port */
+#define TB			1	/* B port */
+#define TS			2	/* S port */
+#define TM			3	/* M port */
+#define TNONE			4
+
+
+/*
+ * indexes in MIB
+ */
+#define INDEX_MAC	1
+#define INDEX_PATH	1
+#define INDEX_PORT	1
+
+
+/*
+ * policies
+ */
+#define POLICY_AA	(1<<0)		/* reject AA */
+#define POLICY_AB	(1<<1)		/* reject AB */
+#define POLICY_AS	(1<<2)		/* reject AS */
+#define POLICY_AM	(1<<3)		/* reject AM */
+#define POLICY_BA	(1<<4)		/* reject BA */
+#define POLICY_BB	(1<<5)		/* reject BB */
+#define POLICY_BS	(1<<6)		/* reject BS */
+#define POLICY_BM	(1<<7)		/* reject BM */
+#define POLICY_SA	(1<<8)		/* reject SA */
+#define POLICY_SB	(1<<9)		/* reject SB */
+#define POLICY_SS	(1<<10)		/* reject SS */
+#define POLICY_SM	(1<<11)		/* reject SM */
+#define POLICY_MA	(1<<12)		/* reject MA */
+#define POLICY_MB	(1<<13)		/* reject MB */
+#define POLICY_MS	(1<<14)		/* reject MS */
+#define POLICY_MM	(1<<15)		/* reject MM */
+
+/*
+ * commands
+ */
+
+/*
+ * EVENTS
+ * event classes
+ */
+#define EVENT_ECM	1		/* event class ECM */
+#define EVENT_CFM	2		/* event class CFM */
+#define EVENT_RMT	3		/* event class RMT */
+#define EVENT_SMT	4		/* event class SMT */
+#define EVENT_PCM	5		/* event class PCM */
+#define EVENT_PCMA	5		/* event class PCMA */
+#define EVENT_PCMB	6		/* event class PCMB */
+
+/* WARNING :
+ * EVENT_PCM* must be last in the above list
+ * if more then two ports are used, EVENT_PCM .. EVENT_PCMA+NUM_PHYS-1
+ * are used !
+ */
+
+#define EV_TOKEN(class,event)	(((u_long)(class)<<16L)|((u_long)(event)))
+#define EV_T_CLASS(token)	((int)((token)>>16)&0xffff)
+#define EV_T_EVENT(token)	((int)(token)&0xffff)
+
+/*
+ * ECM events
+ */
+#define EC_CONNECT	1		/* connect request */
+#define EC_DISCONNECT	2		/* disconnect request */
+#define EC_TRACE_PROP	3		/* trace propagation */
+#define EC_PATH_TEST	4		/* path test */
+#define EC_TIMEOUT_TD	5		/* timer TD_min */
+#define EC_TIMEOUT_TMAX	6		/* timer trace_max */
+#define EC_TIMEOUT_IMAX	7		/* timer I_max */
+#define EC_TIMEOUT_INMAX 8		/* timer IN_max */
+#define EC_TEST_DONE	9		/* path test done */
+
+/*
+ * CFM events
+ */
+#define CF_LOOP		1		/* cf_loop flag from PCM */
+#define CF_LOOP_A	1		/* cf_loop flag from PCM */
+#define CF_LOOP_B	2		/* cf_loop flag from PCM */
+#define CF_JOIN		3		/* cf_join flag from PCM */
+#define CF_JOIN_A	3		/* cf_join flag from PCM */
+#define CF_JOIN_B	4		/* cf_join flag from PCM */
+
+/*
+ * PCM events
+ */
+#define PC_START		1
+#define PC_STOP			2
+#define PC_LOOP			3
+#define PC_JOIN			4
+#define PC_SIGNAL		5
+#define PC_REJECT		6
+#define PC_MAINT    		7
+#define PC_TRACE		8
+#define PC_PDR			9
+#define PC_ENABLE		10
+#define PC_DISABLE		11
+
+/*
+ * must be ordered as in LineStateType
+ */
+#define PC_QLS			12
+#define PC_ILS			13
+#define PC_MLS			14
+#define PC_HLS			15
+#define PC_LS_PDR		16
+#define PC_LS_NONE		17
+#define LS2MIB(x)	((x)-PC_QLS)
+#define MIB2LS(x)	((x)+PC_QLS)
+
+#define PC_TIMEOUT_TB_MAX	18	/* timer TB_max */
+#define PC_TIMEOUT_TB_MIN	19	/* timer TB_min */
+#define PC_TIMEOUT_C_MIN	20	/* timer C_Min */
+#define PC_TIMEOUT_T_OUT	21	/* timer T_Out */
+#define PC_TIMEOUT_TL_MIN	22	/* timer TL_Min */
+#define PC_TIMEOUT_T_NEXT	23	/* timer t_next[] */
+#define PC_TIMEOUT_LCT		24
+#define PC_NSE			25	/* NOISE hardware timer */
+#define PC_LEM			26	/* LEM done */
+
+/*
+ * RMT events				  meaning		from
+ */
+#define RM_RING_OP	1		/* ring operational	MAC	*/
+#define RM_RING_NON_OP	2		/* ring not operational	MAC	*/
+#define RM_MY_BEACON	3		/* recvd my beacon	MAC	*/
+#define RM_OTHER_BEACON	4		/* recvd other beacon	MAC	*/
+#define RM_MY_CLAIM	5		/* recvd my claim	MAC	*/
+#define RM_TRT_EXP	6		/* TRT exp		MAC	*/
+#define RM_VALID_CLAIM	7		/* claim from dup addr	MAC	*/
+#define RM_JOIN		8		/* signal rm_join	CFM	*/
+#define RM_LOOP		9		/* signal rm_loop	CFM	*/
+#define RM_DUP_ADDR	10		/* dup_addr_test hange	SMT-NIF	*/
+#define RM_ENABLE_FLAG	11		/* enable flag */
+
+#define RM_TIMEOUT_NON_OP	12	/* timeout T_Non_OP	*/
+#define RM_TIMEOUT_T_STUCK	13	/* timeout T_Stuck	*/
+#define RM_TIMEOUT_ANNOUNCE	14	/* timeout T_Announce	*/
+#define RM_TIMEOUT_T_DIRECT	15	/* timeout T_Direct	*/
+#define RM_TIMEOUT_D_MAX	16	/* timeout D_Max	*/
+#define RM_TIMEOUT_POLL		17	/* claim/beacon poller	*/
+#define RM_TX_STATE_CHANGE	18	/* To restart timer for D_Max */
+
+/*
+ * SMT events
+ */
+#define SM_TIMER	1		/* timer */
+#define SM_FAST		2		/* smt_force_irq */
+
+/* PC modes */
+#define PM_NONE		0
+#define PM_PEER		1
+#define PM_TREE		2
+
+/*
+ * PCM withhold codes
+ * MIB PC-WithholdType ENUM
+ */
+#define PC_WH_NONE	0		/* ok */
+#define PC_WH_M_M	1		/* M to M */
+#define PC_WH_OTHER	2		/* other incompatible phys */
+#define PC_WH_PATH	3		/* path not available */
+/*
+ * LCT duration
+ */
+#define LC_SHORT	1		/* short LCT */
+#define LC_MEDIUM	2		/* medium LCT */
+#define LC_LONG		3		/* long LCT */
+#define LC_EXTENDED	4		/* extended LCT */
+
+/*
+ * path_test values
+ */
+#define PT_NONE		0
+#define PT_TESTING	1		/* test is running */
+#define PT_PASSED	2		/* test passed */
+#define PT_FAILED	3		/* test failed */
+#define PT_PENDING	4		/* path test follows */
+#define PT_EXITING	5		/* disconnected while in trace/leave */
+
+/*
+ * duplicate address test
+ * MIB DupAddressTest ENUM
+ */
+#define DA_NONE		0		/* 		*/
+#define DA_PASSED	1		/* test passed */
+#define DA_FAILED	2		/* test failed */
+
+
+/*
+ * optical bypass
+ */
+#define BP_DEINSERT	0		/* disable bypass */
+#define BP_INSERT	1		/* enable bypass */
+
+/*
+ * ODL enable/disable
+ */
+#define PM_TRANSMIT_DISABLE	0	/* disable xmit */
+#define PM_TRANSMIT_ENABLE	1	/* enable xmit */
+
+/*
+ * parameter for config_mux
+ * note : number is index in config_endec table !
+ */
+#define MUX_THRUA	0		/* through A */
+#define MUX_THRUB	1		/* through B */
+#define MUX_WRAPA	2		/* wrap A */
+#define MUX_WRAPB	3		/* wrap B */
+#define MUX_ISOLATE	4		/* isolated */
+#define MUX_WRAPS	5		/* SAS */
+
+/*
+ * MAC control
+ */
+#define MA_RESET	0
+#define MA_BEACON	1
+#define MA_CLAIM	2
+#define MA_DIRECTED	3		/* directed beacon */
+#define MA_TREQ		4		/* change T_Req */
+#define MA_OFFLINE	5		/* switch MAC to offline */
+
+
+/*
+ * trace prop
+ * bit map for trace propagation
+ */
+#define ENTITY_MAC	(NUMPHYS)
+#define ENTITY_PHY(p)	(p)
+#define ENTITY_BIT(m)	(1<<(m))
+
+/*
+ * Resource Tag Types
+ */
+#define PATH_ISO	0	/* isolated */
+#define PATH_PRIM	3	/* primary path */
+#define PATH_THRU	5	/* through path */
+
+#define RES_MAC		2	/* resource type MAC */
+#define RES_PORT	4	/* resource type PORT */
+
+
+/*
+ * CFM state
+ * oops: MUST MATCH CF-StateType in SMT7.2 !
+ */
+#define SC0_ISOLATED	0		/* isolated */
+#define SC1_WRAP_A	5		/* wrap A (not used) */
+#define SC2_WRAP_B	6		/* wrap B (not used) */
+#define SC4_THRU_A	12		/* through A */
+#define SC5_THRU_B	7		/* through B (used in SMT 6.2) */
+#define SC7_WRAP_S	8		/* SAS (not used) */
+#define SC9_C_WRAP_A	9		/* c wrap A */
+#define SC10_C_WRAP_B	10		/* c wrap B */
+#define SC11_C_WRAP_S	11		/* c wrap S */
+
+/*
+ * convert MIB time in units of 80nS to uS
+ */
+#define MIB2US(t)		((t)/12)
+#define SEC2MIB(s)	((s)*12500000L)
+/*
+ * SMT timer
+ */
+struct smt_timer {
+	struct smt_timer	*tm_next ;	/* linked list */
+	struct s_smc		*tm_smc ;	/* pointer to context */
+	u_long			tm_delta ;	/* delta time */
+	u_long			tm_token ;	/* token value */
+	u_short			tm_active ;	/* flag : active/inactive */
+	u_short			tm_pad ;	/* pad field */
+} ;
+
+/*
+ * communication structures
+ */
+struct mac_parameter {
+	u_long	t_neg ;		/* T_Neg parameter */
+	u_long	t_pri ;		/* T_Pri register in MAC */
+} ;
+
+/*
+ * MAC counters
+ */
+struct mac_counter {
+	u_long	mac_nobuf_counter ;	/* MAC SW counter: no buffer */
+	u_long	mac_r_restart_counter ;	/* MAC SW counter: rx restarted */
+} ;
+
+/*
+ * para struct context for SMT parameters
+ */
+struct s_pcon {
+	int	pc_len ;
+	int	pc_err ;
+	int	pc_badset ;
+	void	*pc_p ;
+} ;
+
+
+/*
+ * link error monitor
+ */
+#define LEM_AVG	5
+struct lem_counter {
+#ifdef	AM29K
+	int	lem_on	;
+	u_long	lem_errors ;
+	u_long	lem_symbols ;
+	u_long	lem_tsymbols ;
+	int	lem_s_count ;
+	int	lem_n_s ;
+	int	lem_values ;
+	int	lem_index ;
+	int	lem_avg_ber[LEM_AVG] ;
+	int	lem_sum ;
+#else
+	u_short	lem_float_ber ;		/* 10E-nn bit error rate */
+	u_long	lem_errors ;		/* accumulated error count */
+	u_short	lem_on	;
+#endif
+} ;
+
+#define NUMBITS	10
+
+
+#ifdef	AMDPLC
+
+/*
+ * PLC state table
+ */
+struct s_plc {
+	u_short	p_state ;		/* current state */
+	u_short	p_bits ;		/* number of bits to send */
+	u_short	p_start ;		/* first bit pos */
+	u_short	p_pad ;			/* padding for alignment */
+	u_long soft_err ;		/* error counter */
+	u_long parity_err ;		/* error counter */
+	u_long ebuf_err ;		/* error counter */
+	u_long ebuf_cont ;		/* continous error counter */
+	u_long phyinv ;			/* error counter */
+	u_long vsym_ctr ;		/* error counter */
+	u_long mini_ctr ;		/* error counter */
+	u_long tpc_exp ;		/* error counter */
+	u_long np_err ;			/* error counter */
+	u_long b_pcs ;			/* error counter */
+	u_long b_tpc ;			/* error counter */
+	u_long b_tne ;			/* error counter */
+	u_long b_qls ;			/* error counter */
+	u_long b_ils ;			/* error counter */
+	u_long b_hls ;			/* error counter */
+} ;
+#endif
+
+#ifdef	PROTOTYP_INC
+#include "fddi/driver.pro"
+#else	/* PROTOTYP_INC */
+/*
+ * function prototypes
+ */
+#include "h/mbuf.h"	/* Type definitions for MBUFs */
+void hwt_restart(                       /* hwt.c */
+#ifdef ANSIC
+        struct s_smc *smc
+#endif
+	) ;
+
+SMbuf *smt_build_frame(                 /* smt.c */
+#ifdef ANSIC
+        struct s_smc *smc,
+        int class,
+        int type,
+        int length
+#endif
+	) ;
+
+SMbuf *smt_get_mbuf(                     /* drvsr.c */
+#ifdef ANSIC
+        struct s_smc *smc
+#endif
+	) ;
+
+void *sm_to_para(                       /* smt.c */
+#ifdef ANSIC
+	struct s_smc *smc,
+        struct smt_header *sm,
+        int para
+#endif
+	) ;
+
+#ifndef SK_UNUSED
+#define SK_UNUSED(var)		(void)(var)
+#endif
+
+void queue_event() ;
+void ecm() ;
+void ecm_init() ;
+void rmt() ;
+void rmt_init() ;
+void pcm() ;
+void pcm_init() ;
+void cfm() ;
+void cfm_init() ;
+void smt_timer_start() ;
+void smt_timer_stop() ;
+void pcm_status_state() ;
+void plc_config_mux() ;
+void sm_lem_evaluate() ;
+void smt_clear_una_dna() ;
+void mac_status_para() ;
+void mac_update_counter() ;
+void sm_pm_ls_latch() ;
+void sm_ma_control() ;
+void sm_mac_check_beacon_claim() ;
+void config_mux() ;
+void smt_agent_init() ;
+void smt_timer_init() ;
+void smt_received_pack() ;
+void smt_add_para() ;
+void smt_swap_para() ;
+void ev_init() ;
+void hwt_init() ;
+u_long hwt_read() ;
+void hwt_stop() ;
+void hwt_start() ;
+void smt_send_mbuf() ;
+void smt_free_mbuf() ;
+void sm_pm_bypass_req() ;
+void rmt_indication() ;
+void cfm_state_change() ;
+void rx_indication() ;
+void tx_indication() ;
+#ifndef NO_SMT_PANIC
+void smt_panic() ;
+#else
+#ifdef	DEBUG
+void smt_panic() ;
+#else
+#define	smt_panic(smc,text)
+#endif	/* DEBUG */
+#endif	/* NO_SMT_PANIC */
+void smt_stat_counter() ;
+void smt_timer_poll() ;
+u_long smt_get_time() ;
+u_long smt_get_tid() ;
+void smt_timer_done() ;
+void smt_set_defaults() ;
+void smt_fixup_mib() ;
+void smt_reset_defaults() ;
+void smt_agent_task() ;
+void smt_please_reconnect() ;
+int smt_check_para() ;
+void driver_get_bia() ;
+#ifdef	SUPERNET_3
+void drv_reset_indication() ;
+#endif	/* SUPERNET_3 */
+void smt_start_watchdog() ;
+
+void smt_event() ;
+void pcm_event() ;
+void rmt_event() ;
+void cfm_event() ;
+void timer_event() ;
+void ev_dispatcher() ;
+
+void smt_get_state() ;
+void ecm_get_state() ;
+void pcm_get_state() ;
+void rmt_get_state() ;
+
+void ecm_state_change() ;
+int sm_pm_bypass_present() ;
+void pcm_state_change() ;
+void rmt_state_change() ;
+int sm_pm_get_ls() ;
+int pcm_get_s_port() ;
+int pcm_rooted_station() ;
+int cfm_get_mac_input() ;
+int cfm_get_mac_output() ;
+int port_to_mib() ;
+int cem_build_path() ;
+int sm_mac_get_tx_state() ;
+int is_individual() ;
+int is_my_addr() ;
+int is_broadcast() ;
+int is_equal() ;
+char *get_pcmstate() ;
+
+int smt_action() ;
+u_short smt_online() ;
+void smt_force_irq() ;
+void smt_pmf_received_pack() ;
+void smt_send_frame() ;
+void smt_set_timestamp() ;
+void mac_set_rx_mode() ;
+int mac_add_multicast() ;
+int mac_set_func_addr() ;
+void mac_del_multicast() ;
+void mac_update_multicast() ;
+void mac_clear_multicast() ;
+void mac_rx_directed_beacon() ;
+void set_formac_tsync() ;
+void formac_reinit_tx() ;
+void formac_tx_restart() ;
+void process_receive() ;
+void init_driver_fplus() ;
+
+void rtm_irq() ;
+void rtm_set_timer() ;
+void ring_status_indication() ;
+void llc_recover_tx() ;
+void llc_restart_tx() ;
+void plc_clear_irq() ;
+void plc_irq() ;
+int smt_set_mac_opvalues() ;
+#ifdef	TAG_MODE
+void mac_drv_pci_fix() ;
+void mac_do_pci_fix() ;
+void mac_drv_clear_tx_queue() ;
+void mac_drv_repair_descr() ;
+u_long hwt_quick_read() ;
+void hwt_wait_time() ;
+#endif
+
+#ifdef SMT_PNMI
+#ifdef ANSIC
+int pnmi_init (struct s_smc* smc);
+int pnmi_process_ndis_id (struct s_smc* smc, u_long ndis_oid, void* buf,
+		int len, int* BytesAccessed, int* BytesNeeded, u_char action);
+#else
+int pnmi_init ();
+int pnmi_process_ndis_id ();
+#endif
+#endif
+
+#ifdef	SBA
+#ifndef _H2INC
+void sba() ;
+#endif
+void sba_raf_received_pack() ;
+void sba_timer_poll() ;
+void smt_init_sba() ;
+#endif
+#ifdef	ESS
+int ess_raf_received_pack() ;
+void ess_timer_poll() ;
+void ess_para_change() ;
+#endif
+
+#ifdef	BOOT
+#define smt_srf_event(a,b,c,d)
+#define smt_init_evc(a)
+#else
+void smt_init_evc() ;
+void smt_srf_event() ;
+#endif
+
+#ifndef SMT_REAL_TOKEN_CT
+void smt_emulate_token_ct();
+#endif
+
+#if defined(DEBUG) && !defined(BOOT)
+void dump_smt() ;
+#else
+#define	dump_smt(smc,sm,text)
+#endif
+
+#ifdef	DEBUG
+char	*addr_to_string() ;
+void	dump_hex() ;
+#endif
+#endif	/* PROTOTYP_INC */
+
+/* PNMI default defines */
+#ifndef PNMI_INIT
+#define	PNMI_INIT(smc)	/* Nothing */
+#endif
+#ifndef PNMI_GET_ID
+#define PNMI_GET_ID( smc, ndis_oid, buf, len, BytesWritten, BytesNeeded ) \
+		( 1 ? (-1) : (-1) )
+#endif
+#ifndef PNMI_SET_ID
+#define PNMI_SET_ID( smc, ndis_oid, buf, len, BytesRead, BytesNeeded, \
+		set_type) ( 1 ? (-1) : (-1) )
+#endif
+
+/*
+ * SMT_PANIC defines
+ */
+#ifndef	SMT_PANIC
+#define	SMT_PANIC(smc,nr,msg)	smt_panic (smc, msg)
+#endif
+
+#ifndef	SMT_ERR_LOG
+#define	SMT_ERR_LOG(smc,nr,msg)	SMT_PANIC (smc, nr, msg)
+#endif
+
+#ifndef	SMT_EBASE
+#define	SMT_EBASE	100
+#endif
+
+#define	SMT_E0100	SMT_EBASE + 0
+#define	SMT_E0100_MSG	"cfm FSM: illegal ce_type"
+#define	SMT_E0101	SMT_EBASE + 1
+#define	SMT_E0101_MSG	"CEM: case ???"
+#define	SMT_E0102	SMT_EBASE + 2
+#define	SMT_E0102_MSG	"CEM A: illegal state"
+#define	SMT_E0103	SMT_EBASE + 3
+#define	SMT_E0103_MSG	"CEM B: illegal state"
+#define	SMT_E0104	SMT_EBASE + 4
+#define	SMT_E0104_MSG	"CEM M: illegal state"
+#define	SMT_E0105	SMT_EBASE + 5
+#define	SMT_E0105_MSG	"CEM S: illegal state"
+#define	SMT_E0106	SMT_EBASE + 6
+#define	SMT_E0106_MSG	"CFM : illegal state"
+#define	SMT_E0107	SMT_EBASE + 7
+#define	SMT_E0107_MSG	"ECM : illegal state"
+#define	SMT_E0108	SMT_EBASE + 8
+#define	SMT_E0108_MSG	"prop_actions : NAC in DAS CFM"
+#define	SMT_E0109	SMT_EBASE + 9
+#define	SMT_E0109_MSG	"ST2U.FM_SERRSF error in special frame"
+#define	SMT_E0110	SMT_EBASE + 10
+#define	SMT_E0110_MSG	"ST2U.FM_SRFRCTOV recv. count. overflow"
+#define	SMT_E0111	SMT_EBASE + 11
+#define	SMT_E0111_MSG	"ST2U.FM_SNFSLD NP & FORMAC simult. load"
+#define	SMT_E0112	SMT_EBASE + 12
+#define	SMT_E0112_MSG	"ST2U.FM_SRCVFRM single-frame recv.-mode"
+#define	SMT_E0113	SMT_EBASE + 13
+#define	SMT_E0113_MSG	"FPLUS: Buffer Memory Error"
+#define	SMT_E0114	SMT_EBASE + 14
+#define	SMT_E0114_MSG	"ST2U.FM_SERRSF error in special frame"
+#define	SMT_E0115	SMT_EBASE + 15
+#define	SMT_E0115_MSG	"ST3L: parity error in receive queue 2"
+#define	SMT_E0116	SMT_EBASE + 16
+#define	SMT_E0116_MSG	"ST3L: parity error in receive queue 1"
+#define	SMT_E0117	SMT_EBASE + 17
+#define	SMT_E0117_MSG	"E_SMT_001: RxD count for receive queue 1 = 0"
+#define	SMT_E0118	SMT_EBASE + 18
+#define	SMT_E0118_MSG	"PCM : illegal state"
+#define	SMT_E0119	SMT_EBASE + 19
+#define	SMT_E0119_MSG	"smt_add_para"
+#define	SMT_E0120	SMT_EBASE + 20
+#define	SMT_E0120_MSG	"smt_set_para"
+#define	SMT_E0121	SMT_EBASE + 21
+#define	SMT_E0121_MSG	"illegal event in dispatcher"
+#define	SMT_E0122	SMT_EBASE + 22
+#define	SMT_E0122_MSG	"RMT : illegal state"
+#define	SMT_E0123	SMT_EBASE + 23
+#define	SMT_E0123_MSG	"SBA: state machine has illegal state"
+#define	SMT_E0124	SMT_EBASE + 24
+#define	SMT_E0124_MSG	"sba_free_session() called with NULL pointer"
+#define	SMT_E0125	SMT_EBASE + 25
+#define	SMT_E0125_MSG	"SBA : illegal session pointer"
+#define	SMT_E0126	SMT_EBASE + 26
+#define	SMT_E0126_MSG	"smt_free_mbuf() called with NULL pointer\n"
+#define	SMT_E0127	SMT_EBASE + 27
+#define	SMT_E0127_MSG	"sizeof evcs"
+#define	SMT_E0128	SMT_EBASE + 28
+#define	SMT_E0128_MSG	"evc->evc_cond_state = 0"
+#define	SMT_E0129	SMT_EBASE + 29
+#define	SMT_E0129_MSG	"evc->evc_multiple = 0"
+#define	SMT_E0130	SMT_EBASE + 30
+#define	SMT_E0130_MSG	write_mdr_warning
+#define	SMT_E0131	SMT_EBASE + 31
+#define	SMT_E0131_MSG	cam_warning
+#define SMT_E0132	SMT_EBASE + 32
+#define SMT_E0132_MSG	"ST1L.FM_SPCEPDx parity/coding error"
+#define SMT_E0133	SMT_EBASE + 33
+#define SMT_E0133_MSG	"ST1L.FM_STBURx tx buffer underrun"
+#define SMT_E0134	SMT_EBASE + 34
+#define SMT_E0134_MSG	"ST1L.FM_SPCEPDx parity error"
+#define SMT_E0135	SMT_EBASE + 35
+#define SMT_E0135_MSG	"RMT: duplicate MAC address detected. Ring left!"
+#define SMT_E0136	SMT_EBASE + 36
+#define SMT_E0136_MSG	"Elasticity Buffer hang-up"
+#define SMT_E0137	SMT_EBASE + 37
+#define SMT_E0137_MSG	"SMT: queue overrun"
+#define SMT_E0138	SMT_EBASE + 38
+#define SMT_E0138_MSG	"RMT: duplicate MAC address detected. Ring NOT left!"
+#endif	/* _CMTDEF_ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/fddi.h linux.18p8/drivers/net/skfp/h/fddi.h
--- linux.vanilla/drivers/net/skfp/h/fddi.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/fddi.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_FDDI_
+#define _FDDI_
+
+struct fddi_addr {
+	u_char	a[6] ;
+} ;
+
+#define GROUP_ADDR	0x80		/* MSB in a[0] */
+
+struct fddi_mac {
+	struct fddi_addr	mac_dest ;
+	struct fddi_addr	mac_source ;
+	u_char			mac_info[4478] ;
+} ;
+
+#define FDDI_MAC_SIZE	(12)
+#define FDDI_RAW_MTU	(4500-5)	/* exl. Pr,SD, ED/FS */
+#define FDDI_RAW	(4500)
+
+/*
+ * FC values
+ */
+#define FC_VOID		0x40		/* void frame */
+#define FC_TOKEN	0x80		/* token */
+#define FC_RES_TOKEN	0xc0		/* restricted token */
+#define FC_SMT_INFO	0x41		/* SMT Info frame */
+/*
+ * FC_SMT_LAN_LOC && FC_SMT_LOC are SK specific !
+ */
+#define FC_SMT_LAN_LOC	0x42		/* local SMT Info frame */
+#define FC_SMT_LOC	0x43		/* local SMT Info frame */
+#define FC_SMT_NSA	0x4f		/* SMT NSA frame */
+#define FC_MAC		0xc0		/* MAC frame */
+#define FC_BEACON	0xc2		/* MAC beacon frame */
+#define FC_CLAIM	0xc3		/* MAC claim frame */
+#define FC_SYNC_LLC	0xd0		/* sync. LLC frame */
+#define FC_ASYNC_LLC	0x50		/* async. LLC frame */
+#define FC_SYNC_BIT	0x80		/* sync. bit in FC */
+
+#define FC_LLC_PRIOR	0x07		/* priority bits */
+
+#define BEACON_INFO	0		/* beacon type */
+#define DBEACON_INFO	1		/* beacon type DIRECTED */
+
+
+/*
+ * indicator bits
+ */
+#define C_INDICATOR	(1<<0)
+#define A_INDICATOR	(1<<1)
+#define E_INDICATOR	(1<<2)
+#define I_INDICATOR	(1<<6)		/* SK specific */ 
+#define L_INDICATOR	(1<<7)		/* SK specific */
+
+#endif	/* _FDDI_ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/fddimib.h linux.18p8/drivers/net/skfp/h/fddimib.h
--- linux.vanilla/drivers/net/skfp/h/fddimib.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/fddimib.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,349 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * FDDI MIB
+ */
+
+/*
+ * typedefs
+ */
+
+typedef	u_long	Counter ;
+typedef u_char	TimeStamp[8] ;
+typedef struct fddi_addr LongAddr ;
+typedef	u_long	Timer_2 ;
+typedef	u_long	Timer ;
+typedef	u_short	ResId ;
+typedef u_short	SMTEnum ;
+typedef	u_char	SMTFlag ;
+
+typedef struct {
+	Counter		count ;
+	TimeStamp	timestamp ;
+} SetCountType ;
+
+/*
+ * bits for bit string "available_path"
+ */
+#define MIB_PATH_P	(1<<0)
+#define MIB_PATH_S	(1<<1)
+#define MIB_PATH_L	(1<<2)
+
+/*
+ * bits for bit string PermittedPaths & RequestedPaths (SIZE(8))
+ */
+#define MIB_P_PATH_LOCAL	(1<<0)
+#define MIB_P_PATH_SEC_ALTER	(1<<1)
+#define MIB_P_PATH_PRIM_ALTER	(1<<2)
+#define MIB_P_PATH_CON_ALTER	(1<<3)
+#define MIB_P_PATH_SEC_PREFER	(1<<4)
+#define MIB_P_PATH_PRIM_PREFER	(1<<5)
+#define MIB_P_PATH_CON_PREFER	(1<<6)
+#define MIB_P_PATH_THRU		(1<<7)
+
+/*
+ * enum current path
+ */
+#define MIB_PATH_ISOLATED	0
+#define MIB_PATH_LOCAL		1
+#define MIB_PATH_SECONDARY	2
+#define MIB_PATH_PRIMARY	3
+#define MIB_PATH_CONCATENATED	4
+#define MIB_PATH_THRU		5
+
+/*
+ * enum PMDClass
+ */
+#define MIB_PMDCLASS_MULTI	0
+#define MIB_PMDCLASS_SINGLE1	1
+#define MIB_PMDCLASS_SINGLE2	2
+#define MIB_PMDCLASS_SONET	3
+#define MIB_PMDCLASS_LCF	4
+#define MIB_PMDCLASS_TP		5
+#define MIB_PMDCLASS_UNKNOWN	6
+#define MIB_PMDCLASS_UNSPEC	7
+
+/*
+ * enum SMTStationStatus
+ */
+#define MIB_SMT_STASTA_CON	0
+#define MIB_SMT_STASTA_SEPA	1
+#define MIB_SMT_STASTA_THRU	2
+
+
+struct fddi_mib {
+	/*
+	 * private
+	 */
+	u_char			fddiPRPMFPasswd[8] ;
+	struct smt_sid		fddiPRPMFStation ;
+
+#ifdef	ESS
+	/*
+	 * private variables for static allocation of the
+	 * End Station Support
+	 */
+	u_long	fddiESSPayload ;	/* payload for static alloc */
+	u_long	fddiESSOverhead ;	/* frame ov for static alloc */
+	u_long	fddiESSMaxTNeg ;	/* maximum of T-NEG */
+	u_long	fddiESSMinSegmentSize ;	/* min size of the sync frames */
+	u_long	fddiESSCategory ;	/* category for the Alloc req */
+	short	fddiESSSynchTxMode ;	/* send all LLC frames as sync */
+#endif	/* ESS */
+#ifdef	SBA
+	/*
+	 * private variables for the Synchronous Bandwidth Allocator
+	 */
+	char	fddiSBACommand ;	/* holds the parsed SBA cmd */
+	u_char	fddiSBAAvailable ;	/* SBA allocatable value */
+#endif	/* SBA */
+
+	/*
+	 * SMT standard mib
+	 */
+	struct smt_sid		fddiSMTStationId ;
+	u_short			fddiSMTOpVersionId ;
+	u_short			fddiSMTHiVersionId ;
+	u_short			fddiSMTLoVersionId ;
+	u_char			fddiSMTManufacturerData[32] ;
+	u_char			fddiSMTUserData[32] ;
+	u_short			fddiSMTMIBVersionId ;
+
+	/*
+	 * ConfigGrp
+	 */
+	u_char			fddiSMTMac_Ct ;
+	u_char			fddiSMTNonMaster_Ct ;
+	u_char			fddiSMTMaster_Ct ;
+	u_char			fddiSMTAvailablePaths ;
+	u_short			fddiSMTConfigCapabilities ;
+	u_short			fddiSMTConfigPolicy ;
+	u_short			fddiSMTConnectionPolicy ;
+	u_short			fddiSMTTT_Notify ;
+	u_char			fddiSMTStatRptPolicy ;
+	u_long			fddiSMTTrace_MaxExpiration ;
+	u_short			fddiSMTPORTIndexes[NUMPHYS] ;
+	u_short			fddiSMTMACIndexes ;
+	u_char			fddiSMTBypassPresent ;
+
+	/*
+	 * StatusGrp
+	 */
+	SMTEnum			fddiSMTECMState ;
+	SMTEnum			fddiSMTCF_State ;
+	SMTEnum			fddiSMTStationStatus ;
+	u_char			fddiSMTRemoteDisconnectFlag ;
+	u_char			fddiSMTPeerWrapFlag ;
+
+	/*
+	 * MIBOperationGrp
+	 */
+	TimeStamp		fddiSMTTimeStamp ;
+	TimeStamp		fddiSMTTransitionTimeStamp ;
+	SetCountType		fddiSMTSetCount ;
+	struct smt_sid		fddiSMTLastSetStationId ;
+
+	struct fddi_mib_m {
+		u_short		fddiMACFrameStatusFunctions ;
+		Timer_2		fddiMACT_MaxCapabilitiy ;
+		Timer_2		fddiMACTVXCapabilitiy ;
+
+		/* ConfigGrp */
+		u_char		fddiMACMultiple_N ;	/* private */
+		u_char		fddiMACMultiple_P ;	/* private */
+		u_char		fddiMACDuplicateAddressCond ;/* private */
+		u_char		fddiMACAvailablePaths ;
+		u_short		fddiMACCurrentPath ;
+		LongAddr	fddiMACUpstreamNbr ;
+		LongAddr	fddiMACDownstreamNbr ;
+		LongAddr	fddiMACOldUpstreamNbr ;
+		LongAddr	fddiMACOldDownstreamNbr ;
+		SMTEnum		fddiMACDupAddressTest ;
+		u_short		fddiMACRequestedPaths ;
+		SMTEnum		fddiMACDownstreamPORTType ;
+		ResId		fddiMACIndex ;
+
+		/* AddressGrp */
+		LongAddr	fddiMACSMTAddress ;
+
+		/* OperationGrp */
+		Timer_2		fddiMACT_Min ;	/* private */
+		Timer_2		fddiMACT_ReqMIB ;
+		Timer_2		fddiMACT_Req ;	/* private */
+		Timer_2		fddiMACT_Neg ;
+		Timer_2		fddiMACT_MaxMIB ;
+		Timer_2		fddiMACT_Max ;	/* private */
+		Timer_2		fddiMACTvxValueMIB ;
+		Timer_2		fddiMACTvxValue ; /* private */
+		Timer_2		fddiMACT_Pri0 ;
+		Timer_2		fddiMACT_Pri1 ;
+		Timer_2		fddiMACT_Pri2 ;
+		Timer_2		fddiMACT_Pri3 ;
+		Timer_2		fddiMACT_Pri4 ;
+		Timer_2		fddiMACT_Pri5 ;
+		Timer_2		fddiMACT_Pri6 ;
+
+		/* CountersGrp */
+		Counter		fddiMACFrame_Ct ;
+		Counter		fddiMACCopied_Ct ;
+		Counter		fddiMACTransmit_Ct ;
+		Counter		fddiMACToken_Ct ;
+		Counter		fddiMACError_Ct ;
+		Counter		fddiMACLost_Ct ;
+		Counter		fddiMACTvxExpired_Ct ;
+		Counter		fddiMACNotCopied_Ct ;
+		Counter		fddiMACRingOp_Ct ;
+
+		Counter		fddiMACSMTCopied_Ct ;		/* private */
+		Counter		fddiMACSMTTransmit_Ct ;		/* private */
+
+		/* private for delta ratio */
+		Counter		fddiMACOld_Frame_Ct ;
+		Counter		fddiMACOld_Copied_Ct ;
+		Counter		fddiMACOld_Error_Ct ;
+		Counter		fddiMACOld_Lost_Ct ;
+		Counter		fddiMACOld_NotCopied_Ct ;
+
+		/* FrameErrorConditionGrp */
+		u_short		fddiMACFrameErrorThreshold ;
+		u_short		fddiMACFrameErrorRatio ;
+
+		/* NotCopiedConditionGrp */
+		u_short		fddiMACNotCopiedThreshold ;
+		u_short		fddiMACNotCopiedRatio ;
+
+		/* StatusGrp */
+		SMTEnum		fddiMACRMTState ;
+		SMTFlag		fddiMACDA_Flag ;
+		SMTFlag		fddiMACUNDA_Flag ;
+		SMTFlag		fddiMACFrameErrorFlag ;
+		SMTFlag		fddiMACNotCopiedFlag ;
+		SMTFlag		fddiMACMA_UnitdataAvailable ;
+		SMTFlag		fddiMACHardwarePresent ;
+		SMTFlag		fddiMACMA_UnitdataEnable ;
+
+	} m[NUMMACS] ;
+#define MAC0	0
+
+	struct fddi_mib_a {
+		ResId		fddiPATHIndex ;
+		u_long		fddiPATHSbaPayload ;
+		u_long		fddiPATHSbaOverhead ;
+		/* fddiPATHConfiguration is built on demand */
+		/* u_long		fddiPATHConfiguration ; */
+		Timer		fddiPATHT_Rmode ;
+		u_long		fddiPATHSbaAvailable ;
+		Timer_2		fddiPATHTVXLowerBound ;
+		Timer_2		fddiPATHT_MaxLowerBound ;
+		Timer_2		fddiPATHMaxT_Req ;
+	} a[NUMPATHS] ;
+#define PATH0	0
+
+	struct fddi_mib_p {
+		/* ConfigGrp */
+		SMTEnum		fddiPORTMy_Type ;
+		SMTEnum		fddiPORTNeighborType ;
+		u_char		fddiPORTConnectionPolicies ;
+		struct {
+			u_char	T_val ;
+			u_char	R_val ;
+		} fddiPORTMacIndicated ;
+		SMTEnum		fddiPORTCurrentPath ;
+		/* must be 4: is 32 bit in SMT format
+		 * indices :
+		 *	1	none
+		 *	2	tree
+		 *	3	peer
+		 */
+		u_char		fddiPORTRequestedPaths[4] ;
+		u_short		fddiPORTMACPlacement ;
+		u_char		fddiPORTAvailablePaths ;
+		u_char		fddiPORTConnectionCapabilities ;
+		SMTEnum		fddiPORTPMDClass ;
+		ResId		fddiPORTIndex ;
+
+		/* OperationGrp */
+		SMTEnum		fddiPORTMaint_LS ;
+		SMTEnum		fddiPORTPC_LS ;
+		u_char		fddiPORTBS_Flag ;
+
+		/* ErrorCtrsGrp */
+		Counter		fddiPORTLCTFail_Ct ;
+		Counter		fddiPORTEBError_Ct ;
+		Counter		fddiPORTOldEBError_Ct ;
+
+		/* LerGrp */
+		Counter		fddiPORTLem_Reject_Ct ;
+		Counter		fddiPORTLem_Ct ;
+		u_char		fddiPORTLer_Estimate ;
+		u_char		fddiPORTLer_Cutoff ;
+		u_char		fddiPORTLer_Alarm ;
+
+		/* StatusGrp */
+		SMTEnum		fddiPORTConnectState ;
+		SMTEnum		fddiPORTPCMState ;	/* real value */
+		SMTEnum		fddiPORTPCMStateX ;	/* value for MIB */
+		SMTEnum		fddiPORTPC_Withhold ;
+		SMTFlag		fddiPORTHardwarePresent ;
+		u_char		fddiPORTLerFlag ;
+
+		u_char		fddiPORTMultiple_U ;	/* private */
+		u_char		fddiPORTMultiple_P ;	/* private */
+		u_char		fddiPORTEB_Condition ;	/* private */
+	} p[NUMPHYS] ;
+	struct {
+		Counter		fddiPRIVECF_Req_Rx ;	/* ECF req received */
+		Counter		fddiPRIVECF_Reply_Rx ;	/* ECF repl received */
+		Counter		fddiPRIVECF_Req_Tx ;	/* ECF req transm */
+		Counter		fddiPRIVECF_Reply_Tx ;	/* ECF repl transm */
+		Counter		fddiPRIVPMF_Get_Rx ;	/* PMF Get rec */
+		Counter		fddiPRIVPMF_Set_Rx ;	/* PMF Set rec */
+		Counter		fddiPRIVRDF_Rx ;	/* RDF received */
+		Counter		fddiPRIVRDF_Tx ;	/* RDF transmitted */
+	} priv ;
+} ;
+
+/*
+ * OIDs for statistics
+ */
+#define	SMT_OID_CF_STATE	1	/* fddiSMTCF_State */
+#define	SMT_OID_PCM_STATE_A	2	/* fddiPORTPCMState port A */
+#define	SMT_OID_PCM_STATE_B	17	/* fddiPORTPCMState port B */
+#define	SMT_OID_RMT_STATE	3	/* fddiMACRMTState */
+#define	SMT_OID_UNA		4	/* fddiMACUpstreamNbr */
+#define	SMT_OID_DNA		5	/* fddiMACOldDownstreamNbr */
+#define	SMT_OID_ERROR_CT	6	/* fddiMACError_Ct */
+#define	SMT_OID_LOST_CT		7	/* fddiMACLost_Ct */
+#define	SMT_OID_LEM_CT		8	/* fddiPORTLem_Ct */
+#define	SMT_OID_LEM_CT_A	11	/* fddiPORTLem_Ct port A */
+#define	SMT_OID_LEM_CT_B	12	/* fddiPORTLem_Ct port B */
+#define	SMT_OID_LCT_FAIL_CT	9	/* fddiPORTLCTFail_Ct */
+#define	SMT_OID_LCT_FAIL_CT_A	13	/* fddiPORTLCTFail_Ct port A */
+#define	SMT_OID_LCT_FAIL_CT_B	14	/* fddiPORTLCTFail_Ct port B */
+#define	SMT_OID_LEM_REJECT_CT	10	/* fddiPORTLem_Reject_Ct */
+#define	SMT_OID_LEM_REJECT_CT_A	15	/* fddiPORTLem_Reject_Ct port A */
+#define	SMT_OID_LEM_REJECT_CT_B	16	/* fddiPORTLem_Reject_Ct port B */
+
+/*
+ * SK MIB
+ */
+#define SMT_OID_ECF_REQ_RX	20	/* ECF requests received */
+#define SMT_OID_ECF_REPLY_RX	21	/* ECF replies received */
+#define SMT_OID_ECF_REQ_TX	22	/* ECF requests transmitted */
+#define SMT_OID_ECF_REPLY_TX	23	/* ECF replies transmitted */
+#define SMT_OID_PMF_GET_RX	24	/* PMF get requests received */
+#define SMT_OID_PMF_SET_RX	25	/* PMF set requests received */
+#define SMT_OID_RDF_RX		26	/* RDF received */
+#define SMT_OID_RDF_TX		27	/* RDF transmitted */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/fplustm.h linux.18p8/drivers/net/skfp/h/fplustm.h
--- linux.vanilla/drivers/net/skfp/h/fplustm.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/fplustm.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,278 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *	AMD Fplus in tag mode data structs
+ *	defs for fplustm.c
+ */
+
+#ifndef	_FPLUS_
+#define _FPLUS_
+
+#ifndef	HW_PTR
+#ifdef	MEM_MAPPED_IO
+#define	HW_PTR	u_long
+#else
+#define	HW_PTR	u_short
+#endif
+#endif
+
+/*
+ * fplus error statistic structure
+ */
+struct err_st {
+	u_long err_valid ;		/* memory status valid */
+	u_long err_abort ;		/* memory status receive abort */
+	u_long err_e_indicator ;	/* error indicator */
+	u_long err_crc ;		/* error detected (CRC or length) */
+	u_long err_llc_frame ;		/* LLC frame */
+	u_long err_mac_frame ;		/* MAC frame */
+	u_long err_smt_frame ;		/* SMT frame */
+	u_long err_imp_frame ;		/* implementer frame */
+	u_long err_no_buf ;		/* no buffer available */
+	u_long err_too_long ;		/* longer than max. buffer */
+	u_long err_bec_stat ;		/* beacon state entered */
+	u_long err_clm_stat ;		/* claim state entered */
+	u_long err_sifg_det ;		/* short interframe gap detect */
+	u_long err_phinv ;		/* PHY invalid */
+	u_long err_tkiss ;		/* token issued */
+	u_long err_tkerr ;		/* token error */
+} ;
+
+/*
+ *	Transmit Descriptor struct
+ */
+struct s_smt_fp_txd {
+	u_int txd_tbctrl ;		/* transmit buffer control */
+	u_int txd_txdscr ;		/* transmit frame status word */
+	u_int txd_tbadr ;		/* physical tx buffer address */
+	u_int txd_ntdadr ;		/* physical pointer to the next TxD */
+#ifdef	ENA_64BIT_SUP
+	u_int txd_tbadr_hi ;		/* physical tx buffer addr (high dword)*/
+#endif
+	char far *txd_virt ;		/* virtual pointer to the data frag */
+					/* virt pointer to the next TxD */
+	struct s_smt_fp_txd volatile far *txd_next ;
+	struct s_txd_os txd_os ;	/* OS - specific struct */
+} ;
+
+/*
+ *	Receive Descriptor struct
+ */
+struct s_smt_fp_rxd {
+	u_int rxd_rbctrl ;		/* receive buffer control */
+	u_int rxd_rfsw ;		/* receive frame status word */
+	u_int rxd_rbadr ;		/* physical rx buffer address */
+	u_int rxd_nrdadr ;		/* physical pointer to the next RxD */
+#ifdef	ENA_64BIT_SUP
+	u_int rxd_rbadr_hi ;		/* physical tx buffer addr (high dword)*/
+#endif
+	char far *rxd_virt ;		/* virtual pointer to the data frag */
+					/* virt pointer to the next RxD */
+	struct s_smt_fp_rxd volatile far *rxd_next ;
+	struct s_rxd_os rxd_os ;	/* OS - specific struct */
+} ;
+
+/*
+ *	Descriptor Union Definition
+ */
+union s_fp_descr {
+	struct	s_smt_fp_txd t ;		/* pointer to the TxD */
+	struct	s_smt_fp_rxd r ;		/* pointer to the RxD */
+} ;
+
+/*
+ *	TxD Ring Control struct
+ */
+struct s_smt_tx_queue {
+	struct s_smt_fp_txd volatile *tx_curr_put ; /* next free TxD */
+	struct s_smt_fp_txd volatile *tx_prev_put ; /* shadow put pointer */
+	struct s_smt_fp_txd volatile *tx_curr_get ; /* next TxD to release*/
+	u_short tx_free ;			/* count of free TxD's */
+	u_short tx_used ;			/* count of used TxD's */
+	HW_PTR tx_bmu_ctl ;			/* BMU addr for tx start */
+	HW_PTR tx_bmu_dsc ;			/* BMU addr for curr dsc. */
+} ;
+
+/*
+ *	RxD Ring Control struct
+ */
+struct s_smt_rx_queue {
+	struct s_smt_fp_rxd volatile *rx_curr_put ; /* next RxD to queue into */
+	struct s_smt_fp_rxd volatile *rx_prev_put ; /* shadow put pointer */
+	struct s_smt_fp_rxd volatile *rx_curr_get ; /* next RxD to fill */
+	u_short rx_free ;			/* count of free RxD's */
+	u_short rx_used ;			/* count of used RxD's */
+	HW_PTR rx_bmu_ctl ;			/* BMU addr for rx start */
+	HW_PTR rx_bmu_dsc ;			/* BMU addr for curr dsc. */
+} ;
+
+#define VOID_FRAME_OFF		0x00
+#define CLAIM_FRAME_OFF		0x08
+#define BEACON_FRAME_OFF	0x10
+#define DBEACON_FRAME_OFF	0x18
+#define RX_FIFO_OFF		0x21		/* to get a prime number for */
+						/* the RX_FIFO_SPACE */
+
+#define RBC_MEM_SIZE		0x8000
+#define SEND_ASYNC_AS_SYNC	0x1
+#define	SYNC_TRAFFIC_ON		0x2
+
+/* big FIFO memory */
+#define	RX_FIFO_SPACE		0x4000 - RX_FIFO_OFF
+#define	TX_FIFO_SPACE		0x4000
+
+#define	TX_SMALL_FIFO		0x0900
+#define	TX_MEDIUM_FIFO		TX_FIFO_SPACE / 2	
+#define	TX_LARGE_FIFO		TX_FIFO_SPACE - TX_SMALL_FIFO	
+
+#define	RX_SMALL_FIFO		0x0900
+#define	RX_LARGE_FIFO		RX_FIFO_SPACE - RX_SMALL_FIFO	
+
+struct s_smt_fifo_conf {
+	u_short	rbc_ram_start ;		/* FIFO start address */
+	u_short	rbc_ram_end ;		/* FIFO size */
+	u_short	rx1_fifo_start ;	/* rx queue start address */
+	u_short	rx1_fifo_size ;		/* rx queue size */
+	u_short	rx2_fifo_start ;	/* rx queue start address */
+	u_short	rx2_fifo_size ;		/* rx queue size */
+	u_short	tx_s_start ;		/* sync queue start address */
+	u_short	tx_s_size ;		/* sync queue size */
+	u_short	tx_a0_start ;		/* async queue A0 start address */
+	u_short	tx_a0_size ;		/* async queue A0 size */
+	u_short	fifo_config_mode ;	/* FIFO configuration mode */
+} ;
+
+#define FM_ADDRX	(FM_ADDET|FM_EXGPA0|FM_EXGPA1)
+
+struct s_smt_fp {
+	u_short	mdr2init ;		/* mode register 2 init value */
+	u_short	mdr3init ;		/* mode register 3 init value */
+	u_short frselreg_init ;		/* frame selection register init val */
+	u_short	rx_mode ;		/* address mode broad/multi/promisc */
+	u_short	nsa_mode ;
+	u_short rx_prom ;
+	u_short	exgpa ;
+
+	struct err_st err_stats ;	/* error statistics */
+
+	/*
+	 * MAC buffers
+	 */
+	struct fddi_mac_sf {		/* special frame build buffer */
+		u_char			mac_fc ;
+		struct fddi_addr	mac_dest ;
+		struct fddi_addr	mac_source ;
+		u_char			mac_info[0x20] ;
+	} mac_sfb ;
+
+
+	/*
+	 * queues
+	 */
+#define QUEUE_S			0
+#define QUEUE_A0		1
+#define QUEUE_R1		0
+#define QUEUE_R2		1
+#define USED_QUEUES		2
+
+	/*
+	 * queue pointers; points to the queue dependent variables
+	 */
+	struct s_smt_tx_queue *tx[USED_QUEUES] ;
+	struct s_smt_rx_queue *rx[USED_QUEUES] ;
+
+	/*
+	 * queue dependent variables
+	 */
+	struct s_smt_tx_queue tx_q[USED_QUEUES] ;
+	struct s_smt_rx_queue rx_q[USED_QUEUES] ;
+
+	/*
+	 * FIFO configuration struct
+	 */
+	struct	s_smt_fifo_conf	fifo ;
+
+	/* last formac status */
+	u_short	 s2u ;
+	u_short	 s2l ;
+
+	/* calculated FORMAC+ reg.addr. */
+	HW_PTR	fm_st1u ;
+	HW_PTR	fm_st1l ;
+	HW_PTR	fm_st2u ;
+	HW_PTR	fm_st2l ;
+	HW_PTR	fm_st3u ;
+	HW_PTR	fm_st3l ;
+
+
+	/*
+	 * multicast table
+	 */
+#define FPMAX_MULTICAST 32 
+#define	SMT_MAX_MULTI	4
+	struct {
+		struct s_fpmc {
+			struct fddi_addr	a ;	/* mc address */
+			u_char			n ;	/* usage counter */
+			u_char			perm ;	/* flag: permanent */
+		} table[FPMAX_MULTICAST] ;
+	} mc ;
+	struct fddi_addr	group_addr ;
+	u_long	func_addr ;		/* functional address */
+	int	smt_slots_used ;	/* count of table entries for the SMT */
+	int	os_slots_used ;		/* count of table entries */ 
+					/* used by the os-specific module */
+} ;
+
+/*
+ * modes for mac_set_rx_mode()
+ */
+#define RX_ENABLE_ALLMULTI	1	/* enable all multicasts */
+#define RX_DISABLE_ALLMULTI	2	/* disable "enable all multicasts" */
+#define RX_ENABLE_PROMISC	3	/* enable promiscous */
+#define RX_DISABLE_PROMISC	4	/* disable promiscous */
+#define RX_ENABLE_NSA		5	/* enable reception of NSA frames */
+#define RX_DISABLE_NSA		6	/* disable reception of NSA frames */
+
+
+/*
+ * support for byte reversal in AIX
+ * (descriptors and pointers must be byte reversed in memory
+ *  CPU is big endian; M-Channel is little endian)
+ */
+#ifdef	AIX
+#define MDR_REV
+#define	AIX_REVERSE(x)		((((x)<<24L)&0xff000000L)	+	\
+				 (((x)<< 8L)&0x00ff0000L)	+	\
+				 (((x)>> 8L)&0x0000ff00L)	+	\
+				 (((x)>>24L)&0x000000ffL))
+#else
+#ifndef AIX_REVERSE
+#define	AIX_REVERSE(x)	(x)
+#endif
+#endif
+
+#ifdef	MDR_REV	
+#define	MDR_REVERSE(x)		((((x)<<24L)&0xff000000L)	+	\
+				 (((x)<< 8L)&0x00ff0000L)	+	\
+				 (((x)>> 8L)&0x0000ff00L)	+	\
+				 (((x)>>24L)&0x000000ffL))
+#else
+#ifndef MDR_REVERSE
+#define	MDR_REVERSE(x)	(x)
+#endif
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/hwmtm.h linux.18p8/drivers/net/skfp/h/hwmtm.h
--- linux.vanilla/drivers/net/skfp/h/hwmtm.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/hwmtm.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,424 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_HWM_
+#define	_HWM_
+
+#include "h/mbuf.h"
+
+/*
+ * MACRO for DMA synchronization:
+ *	The descriptor 'desc' is flushed for the device 'flag'.
+ *	Devices are the CPU (DDI_DMA_SYNC_FORCPU) and the
+ *	adapter (DDI_DMA_SYNC_FORDEV).
+ *
+ *	'desc'	Pointer to a Rx or Tx descriptor.
+ *	'flag'	Flag for direction (view for CPU or DEVICE) that
+ *		should be synchronized.
+ *
+ *	Empty macros and defines are specified here. The real macro
+ *	is os-specific and should be defined in osdef1st.h.
+ */
+#ifndef DRV_BUF_FLUSH
+#define DRV_BUF_FLUSH(desc,flag)
+#define DDI_DMA_SYNC_FORCPU
+#define DDI_DMA_SYNC_FORDEV
+#endif
+
+	/*
+	 * hardware modul dependent receive modes
+	 */
+#define	RX_ENABLE_PASS_SMT	21
+#define	RX_DISABLE_PASS_SMT	22
+#define	RX_ENABLE_PASS_NSA	23
+#define	RX_DISABLE_PASS_NSA	24
+#define	RX_ENABLE_PASS_DB	25
+#define	RX_DISABLE_PASS_DB	26
+#define	RX_DISABLE_PASS_ALL	27
+#define	RX_DISABLE_LLC_PROMISC	28
+#define	RX_ENABLE_LLC_PROMISC	29
+
+
+#ifndef	DMA_RD
+#define DMA_RD		1	/* memory -> hw */
+#endif
+#ifndef DMA_WR
+#define DMA_WR		2	/* hw -> memory */
+#endif
+#define SMT_BUF		0x80
+
+	/*
+	 * bits of the frame status byte
+	 */
+#define EN_IRQ_EOF	0x02	/* get IRQ after end of frame transmission */
+#define	LOC_TX		0x04	/* send frame to the local SMT */
+#define LAST_FRAG	0x08	/* last TxD of the frame */
+#define	FIRST_FRAG	0x10	/* first TxD of the frame */
+#define	LAN_TX		0x20	/* send frame to network if set */
+#define RING_DOWN	0x40	/* error: unable to send, ring down */
+#define OUT_OF_TXD	0x80	/* error: not enough TxDs available */
+
+
+#ifndef NULL
+#define NULL 		0
+#endif
+
+#ifdef	LITTLE_ENDIAN
+#define HWM_REVERSE(x)	(x)
+#else
+#define	HWM_REVERSE(x)		((((x)<<24L)&0xff000000L)	+	\
+				 (((x)<< 8L)&0x00ff0000L)	+	\
+				 (((x)>> 8L)&0x0000ff00L)	+	\
+				 (((x)>>24L)&0x000000ffL))
+#endif
+
+#define C_INDIC		(1L<<25)
+#define A_INDIC		(1L<<26)
+#define	RD_FS_LOCAL	0x80
+
+	/*
+	 * DEBUG FLAGS
+	 */
+#define	DEBUG_SMTF	1
+#define	DEBUG_SMT	2
+#define	DEBUG_ECM	3
+#define	DEBUG_RMT	4
+#define	DEBUG_CFM	5
+#define	DEBUG_PCM	6
+#define	DEBUG_SBA	7
+#define	DEBUG_ESS	8
+
+#define	DB_HWM_RX	10
+#define	DB_HWM_TX	11
+#define DB_HWM_GEN	12
+
+struct s_mbuf_pool {
+#ifndef	MB_OUTSIDE_SMC
+	SMbuf		mb[MAX_MBUF] ;		/* mbuf pool */
+#endif
+	SMbuf		*mb_start ;		/* points to the first mb */
+	SMbuf		*mb_free ;		/* free queue */
+} ;
+
+struct hwm_r {
+	/*
+	 * hardware modul specific receive variables
+	 */
+	u_int			len ;		/* length of the whole frame */
+	char			*mb_pos ;	/* SMbuf receive position */
+} ;
+
+struct hw_modul {
+	/*
+	 * All hardware modul specific variables
+	 */
+	struct	s_mbuf_pool	mbuf_pool ;
+	struct	hwm_r	r ;
+
+	union s_fp_descr volatile *descr_p ; /* points to the desriptor area */
+
+	u_short pass_SMT ;		/* pass SMT frames */
+	u_short pass_NSA ;		/* pass all NSA frames */
+	u_short pass_DB ;		/* pass Direct Beacon Frames */
+	u_short pass_llc_promisc ;	/* pass all llc frames (default ON) */
+
+	SMbuf	*llc_rx_pipe ;		/* points to the first queued llc fr */
+	SMbuf	*llc_rx_tail ;		/* points to the last queued llc fr */
+	int	queued_rx_frames ;	/* number of queued frames */
+
+	SMbuf	*txd_tx_pipe ;		/* points to first mb in the txd ring */
+	SMbuf	*txd_tx_tail ;		/* points to last mb in the txd ring */
+	int	queued_txd_mb ;		/* number of SMT MBufs in txd ring */
+
+	int	rx_break ;		/* rev. was breaked because ind. off */
+	int	leave_isr ;		/* leave fddi_isr immedeately if set */
+	int	isr_flag ;		/* set, when HWM is entered from isr */
+	/*
+	 * varaibles for the current transmit frame
+	 */
+	struct s_smt_tx_queue *tx_p ;	/* pointer to the transmit queue */
+	u_long	tx_descr ;		/* tx descriptor for FORMAC+ */
+	int	tx_len ;		/* tx frame length */
+	SMbuf	*tx_mb ;		/* SMT tx MBuf pointer */
+	char	*tx_data ;		/* data pointer to the SMT tx Mbuf */
+
+	int	detec_count ;		/* counter for out of RxD condition */
+	u_long	rx_len_error ;		/* rx len FORMAC != sum of fragments */
+} ;
+
+
+/*
+ * DEBUG structs and macros
+ */
+
+#ifdef	DEBUG
+struct os_debug {
+	int	hwm_rx ;
+	int	hwm_tx ;
+	int	hwm_gen ;
+} ;
+#endif
+
+#ifdef	DEBUG
+#ifdef	DEBUG_BRD
+#define	DB_P	smc->debug
+#else
+#define DB_P	debug
+#endif
+
+#define DB_RX(a,b,c,lev) if (DB_P.d_os.hwm_rx >= (lev))	printf(a,b,c)
+#define DB_TX(a,b,c,lev) if (DB_P.d_os.hwm_tx >= (lev))	printf(a,b,c)
+#define DB_GEN(a,b,c,lev) if (DB_P.d_os.hwm_gen >= (lev)) printf(a,b,c)
+#else	/* DEBUG */
+#define DB_RX(a,b,c,lev)
+#define DB_TX(a,b,c,lev)
+#define DB_GEN(a,b,c,lev)
+#endif	/* DEBUG */
+
+#ifndef	SK_BREAK
+#define	SK_BREAK()
+#endif
+
+
+/*
+ * HWM Macros
+ */
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_TX_PHYS)
+ *	u_long HWM_GET_TX_PHYS(txd)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to read
+ *		the physical address of the specified TxD.
+ *
+ * para	txd	pointer to the TxD
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_TX_PHYS(txd)		(u_long)AIX_REVERSE((txd)->txd_tbadr)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_TX_LEN)
+ *	int HWM_GET_TX_LEN(txd)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to read
+ *		the fragment length of the specified TxD
+ *
+ * para	rxd	pointer to the TxD
+ *
+ * return	the length of the fragment in bytes
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_TX_LEN(txd)	((int)AIX_REVERSE((txd)->txd_tbctrl)& RD_LENGTH)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_TX_USED)
+ *	txd *HWM_GET_TX_USED(smc,queue)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get the
+ *		number of used TxDs for the queue, specified by the index.
+ *
+ * para	queue	the number of the send queue: Can be specified by
+ *		QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0)
+ *
+ * return	number of used TxDs for this send queue
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_TX_USED(smc,queue)	(int) (smc)->hw.fp.tx_q[queue].tx_used
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_CURR_TXD)
+ *	txd *HWM_GET_CURR_TXD(smc,queue)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get the
+ *		pointer to the TxD which points to the current queue put
+ *		position.
+ *
+ * para	queue	the number of the send queue: Can be specified by
+ *		QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0)
+ *
+ * return	pointer to the current TxD
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_CURR_TXD(smc,queue)	(struct s_smt_fp_txd volatile *)\
+					(smc)->hw.fp.tx_q[queue].tx_curr_put
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_TX_CHECK)
+ *	void HWM_TX_CHECK(smc,frame_status,low_water)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro is invoked by the OS-specific before it left it's
+ *		driver_send function. This macro calls mac_drv_clear_txd
+ *		if the free TxDs of the current transmit queue is equal or
+ *		lower than the given low water mark.
+ *
+ * para	frame_status	status of the frame, see design description
+ *	low_water	low water mark of free TxD's
+ *
+ *	END_MANUAL_ENTRY
+ */
+#ifndef HWM_NO_FLOW_CTL
+#define	HWM_TX_CHECK(smc,frame_status,low_water) {\
+	if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\
+		mac_drv_clear_txd(smc) ;\
+	}\
+}
+#else
+#define	HWM_TX_CHECK(smc,frame_status,low_water)	mac_drv_clear_txd(smc)
+#endif
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN)
+ *	int HWM_GET_RX_FRAG_LEN(rxd)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to read
+ *		the fragment length of the specified RxD
+ *
+ * para	rxd	pointer to the RxD
+ *
+ * return	the length of the fragment in bytes
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_RX_FRAG_LEN(rxd)	((int)AIX_REVERSE((rxd)->rxd_rbctrl)& \
+				RD_LENGTH)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_RX_PHYS)
+ *	u_long HWM_GET_RX_PHYS(rxd)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to read
+ *		the physical address of the specified RxD.
+ *
+ * para	rxd	pointer to the RxD
+ *
+ * return	the RxD's physical pointer to the data fragment
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_RX_PHYS(rxd)	(u_long)AIX_REVERSE((rxd)->rxd_rbadr)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_RX_USED)
+ *	int HWM_GET_RX_USED(smc)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get
+ *		the count of used RXDs in receive queue 1.
+ *
+ * return	the used RXD count of receive queue 1
+ *
+ * NOTE: Remember, because of an ASIC bug at least one RXD should be unused
+ *	 in the descriptor ring !
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_RX_USED(smc)	((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_used)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_RX_FREE)
+ *	int HWM_GET_RX_FREE(smc)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get
+ *		the rxd_free count of receive queue 1.
+ *
+ * return	the rxd_free count of receive queue 1
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_RX_FREE(smc)	((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_free-1)
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_GET_CURR_RXD)
+ *	rxd *HWM_GET_CURR_RXD(smc)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro may be invoked by the OS-specific module to get the
+ *		pointer to the RxD which points to the current queue put
+ *		position.
+ *
+ * return	pointer to the current RxD
+ *
+ *	END_MANUAL_ENTRY
+ */
+#define	HWM_GET_CURR_RXD(smc)	(struct s_smt_fp_rxd volatile *)\
+				(smc)->hw.fp.rx_q[QUEUE_R1].rx_curr_put
+
+/*
+ *	BEGIN_MANUAL_ENTRY(HWM_RX_CHECK)
+ *	void HWM_RX_CHECK(smc,low_water)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This macro is invoked by the OS-specific before it left the
+ *		function mac_drv_rx_complete. This macro calls mac_drv_fill_rxd
+ *		if the number of used RxDs is equal or lower than the
+ *		the given low water mark.
+ *
+ * para	low_water	low water mark of used RxD's
+ *
+ *	END_MANUAL_ENTRY
+ */
+#ifndef HWM_NO_FLOW_CTL
+#define	HWM_RX_CHECK(smc,low_water) {\
+	if ((low_water) >= (smc)->hw.fp.rx_q[QUEUE_R1].rx_used) {\
+		mac_drv_fill_rxd(smc) ;\
+	}\
+}
+#else
+#define	HWM_RX_CHECK(smc,low_water)		mac_drv_fill_rxd(smc)
+#endif
+
+#ifndef	HWM_EBASE
+#define	HWM_EBASE	500
+#endif
+
+#define	HWM_E0001	HWM_EBASE + 1
+#define	HWM_E0001_MSG	"HWM: Wrong size of s_rxd_os struct"
+#define	HWM_E0002	HWM_EBASE + 2
+#define	HWM_E0002_MSG	"HWM: Wrong size of s_txd_os struct"
+#define	HWM_E0003	HWM_EBASE + 3
+#define	HWM_E0003_MSG	"HWM: smt_free_mbuf() called with NULL pointer"
+#define	HWM_E0004	HWM_EBASE + 4
+#define	HWM_E0004_MSG	"HWM: Parity error rx queue 1"
+#define	HWM_E0005	HWM_EBASE + 5
+#define	HWM_E0005_MSG	"HWM: Encoding error rx queue 1"
+#define	HWM_E0006	HWM_EBASE + 6
+#define	HWM_E0006_MSG	"HWM: Encoding error async tx queue"
+#define	HWM_E0007	HWM_EBASE + 7
+#define	HWM_E0007_MSG	"HWM: Encoding error sync tx queue"
+#define	HWM_E0008	HWM_EBASE + 8
+#define	HWM_E0008_MSG	""
+#define	HWM_E0009	HWM_EBASE + 9
+#define	HWM_E0009_MSG	"HWM: Out of RxD condition detected"
+#define	HWM_E0010	HWM_EBASE + 10
+#define	HWM_E0010_MSG	"HWM: A protocol layer has tried to send a frame with an invalid frame control"
+#define HWM_E0011	HWM_EBASE + 11
+#define HWM_E0011_MSG	"HWM: mac_drv_clear_tx_queue was called although the hardware wasn't stopped"
+#define HWM_E0012	HWM_EBASE + 12
+#define HWM_E0012_MSG	"HWM: mac_drv_clear_rx_queue was called although the hardware wasn't stopped"
+#define HWM_E0013	HWM_EBASE + 13
+#define HWM_E0013_MSG	"HWM: mac_drv_repair_descr was called although the hardware wasn't stopped"
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/lnkstat.h linux.18p8/drivers/net/skfp/h/lnkstat.h
--- linux.vanilla/drivers/net/skfp/h/lnkstat.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/lnkstat.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Definition of the Error Log Structure
+ * This structure will be copied into the Error Log buffer
+ * during the NDIS General Request ReadErrorLog by the MAC Driver
+ */
+
+struct	s_error_log {
+
+	/*
+	 * place holder for token ring adapter error log (zeros)
+	 */
+	u_char	reserved_0 ;			/* byte 0 inside Error Log */
+	u_char	reserved_1 ;			/* byte 1 */
+	u_char	reserved_2 ;			/* byte 2 */	
+	u_char	reserved_3 ;			/* byte 3 */
+	u_char	reserved_4 ;			/* byte 4 */
+	u_char	reserved_5 ;			/* byte 5 */
+	u_char	reserved_6 ;			/* byte 6 */
+	u_char	reserved_7 ;			/* byte 7 */
+	u_char	reserved_8 ;			/* byte 8 */
+	u_char	reserved_9 ;			/* byte 9 */
+	u_char	reserved_10 ;			/* byte 10 */
+	u_char	reserved_11 ;			/* byte 11 */
+	u_char	reserved_12 ;			/* byte 12 */
+	u_char	reserved_13 ;			/* byte 13 */
+
+	/*
+	 * FDDI link statistics 
+	 */
+/*
+ * smt error low
+ */
+#define SMT_ERL_AEB	(1<<15)			/* A elast. buffer */
+#define SMT_ERL_BLC	(1<<14)			/* B link error condition */
+#define SMT_ERL_ALC	(1<<13)			/* A link error condition */
+#define SMT_ERL_NCC	(1<<12)			/* not copied condition */
+#define SMT_ERL_FEC	(1<<11)			/* frame error condition */
+
+/*
+ * smt event low
+ */
+#define SMT_EVL_NCE	(1<<5)
+
+	u_short	smt_error_low ;			/* byte 14/15 */
+	u_short	smt_error_high ;		/* byte 16/17 */
+	u_short	smt_event_low ;			/* byte 18/19 */
+	u_short	smt_event_high ;		/* byte 20/21 */
+	u_short	connection_policy_violation ;	/* byte 22/23 */
+	u_short port_event ;			/* byte 24/25 */
+	u_short set_count_low ;			/* byte 26/27 */
+	u_short set_count_high ;		/* byte 28/29 */
+	u_short	aci_id_code ;			/* byte 30/31 */
+	u_short	purge_frame_counter ;		/* byte 32/33 */
+
+	/*
+	 * CMT and RMT state machines
+	 */
+	u_short	ecm_state ;			/* byte 34/35 */
+	u_short	pcm_a_state ;			/* byte 36/37 */
+	u_short pcm_b_state ;			/* byte 38/39 */
+	u_short	cfm_state ;			/* byte 40/41 */
+	u_short	rmt_state ;			/* byte 42/43 */
+
+	u_short	not_used[30] ;			/* byte 44-103 */
+
+	u_short	ucode_version_level ;		/* byte 104/105 */
+
+	u_short	not_used_1 ;			/* byte 106/107 */
+	u_short not_used_2 ;			/* byte 108/109 */
+} ;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/mbuf.h linux.18p8/drivers/net/skfp/h/mbuf.h
--- linux.vanilla/drivers/net/skfp/h/mbuf.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/mbuf.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_MBUF_
+#define _MBUF_
+
+#ifndef PCI
+#define M_SIZE	4550
+#else
+#define M_SIZE	4504
+#endif
+
+#ifndef MAX_MBUF
+#define MAX_MBUF	4
+#endif
+
+#ifndef NO_STD_MBUF
+#define sm_next         m_next
+#define sm_off          m_off
+#define sm_len          m_len
+#define sm_data         m_data
+#define SMbuf           Mbuf
+#define mtod		smtod
+#define mtodoff		smtodoff
+#endif
+
+struct s_mbuf {
+	struct s_mbuf	*sm_next ;		/* low level linked list */
+	short		sm_off ;			/* offset in m_data */
+	u_int		sm_len ;			/* len of data */
+#ifdef	PCI
+	int		sm_use_count ;
+#endif
+	char		sm_data[M_SIZE] ;
+} ;
+
+typedef struct s_mbuf SMbuf ;
+
+/* mbuf head, to typed data */
+#define	smtod(x,t)	((t)((x)->sm_data + (x)->sm_off))
+#define	smtodoff(x,t,o)	((t)((x)->sm_data + (o)))
+
+#endif	/* _MBUF_ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/osdef1st.h linux.18p8/drivers/net/skfp/h/osdef1st.h
--- linux.vanilla/drivers/net/skfp/h/osdef1st.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/osdef1st.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,121 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/* 
+ * Operating system-dependant definitions that have to be defined
+ * before any other header files are included.
+ */
+
+// HWM (HardWare Module) Definitions
+// -----------------------
+
+#ifdef __LITTLE_ENDIAN
+#define LITTLE_ENDIAN
+#else
+#define BIG_ENDIAN
+#endif
+
+// this is set in the makefile
+// #define PCI			/* only PCI adapters supported by this driver */
+// #define MEM_MAPPED_IO	/* use memory mapped I/O */
+
+
+#define USE_CAN_ADDR		/* DA and SA in MAC header are canonical. */
+
+#define MB_OUTSIDE_SMC		/* SMT Mbufs outside of smc struct. */
+
+// -----------------------
+
+
+// SMT Definitions 
+// -----------------------
+#define SYNC	       		/* allow synchronous frames */
+
+// #define SBA			/* Synchronous Bandwidth Allocator support */
+				/* not available as free source */
+
+#define ESS			/* SBA End Station Support */
+
+#define	SMT_PANIC(smc, nr, msg)	printk(KERN_INFO "SMT PANIC: code: %d, msg: %s\n",nr,msg)
+
+
+#ifdef DEBUG
+#define printf(s,args...) printk(KERN_INFO s, ## args)
+#endif
+
+// #define HW_PTR	u_long
+// -----------------------
+
+
+
+// HWM and OS-specific buffer definitions
+// -----------------------
+
+// default number of receive buffers.
+#define NUM_RECEIVE_BUFFERS		10
+
+// default number of transmit buffers.
+#define NUM_TRANSMIT_BUFFERS		10
+
+// Number of SMT buffers (Mbufs).
+#define NUM_SMT_BUF	4
+
+// Number of TXDs for asynchronous transmit queue.
+#define HWM_ASYNC_TXD_COUNT	(NUM_TRANSMIT_BUFFERS + NUM_SMT_BUF)
+
+// Number of TXDs for synchronous transmit queue.
+#define HWM_SYNC_TXD_COUNT	HWM_ASYNC_TXD_COUNT
+
+
+// Number of RXDs for receive queue #1.
+// Note: Workaround for ASIC Errata #7: One extra RXD is required.
+#if (NUM_RECEIVE_BUFFERS > 100)
+#define SMT_R1_RXD_COUNT	(1 + 100)
+#else
+#define SMT_R1_RXD_COUNT	(1 + NUM_RECEIVE_BUFFERS)
+#endif
+
+// Number of RXDs for receive queue #2.
+#define SMT_R2_RXD_COUNT	0	// Not used.
+// -----------------------
+
+
+
+/*
+ * OS-specific part of the transmit/receive descriptor structure (TXD/RXD).
+ *
+ * Note: The size of these structures must follow this rule:
+ *
+ *	sizeof(struct) + 2*sizeof(void*) == n * 16, n >= 1
+ *
+ */
+
+struct s_txd_os {	// os-specific part of transmit descriptor
+	struct sk_buff *skb;
+	long		padding;
+} ;
+
+struct s_rxd_os {	// os-specific part of receive descriptor
+	struct sk_buff *skb;
+	long		padding;
+} ;
+
+
+/*
+ * So we do not need to make too many modifications to the generic driver
+ * parts, we take advantage of the AIX byte swapping macro interface.
+ */
+
+#define AIX_REVERSE(x)		((u32)le32_to_cpu((u32)(x)))
+#define MDR_REVERSE(x)		((u32)le32_to_cpu((u32)(x)))
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/sba.h linux.18p8/drivers/net/skfp/h/sba.h
--- linux.vanilla/drivers/net/skfp/h/sba.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/sba.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Synchronous Bandwith Allocation (SBA) structs
+ */
+ 
+#ifndef _SBA_
+#define _SBA_
+
+#include "h/mbuf.h"
+#include "h/sba_def.h"
+
+#ifdef	SBA
+
+/* Timer Cell Template */
+struct timer_cell {
+	struct timer_cell	*next_ptr ;
+	struct timer_cell	*prev_ptr ;
+	u_long			start_time ;
+	struct s_sba_node_vars	*node_var ;
+} ;
+
+/*
+ * Node variables
+ */
+struct s_sba_node_vars {
+	u_char			change_resp_flag ;
+	u_char			report_resp_flag ;
+	u_char			change_req_flag ;
+	u_char			report_req_flag ;
+	long			change_amount ;
+	long			node_overhead ;
+	long			node_payload ;
+	u_long			node_status ;
+	u_char			deallocate_status ;
+	u_char			timer_state ;
+	u_short			report_cnt ;
+	long			lastrep_req_tranid ;
+	struct fddi_addr	mac_address ;
+	struct s_sba_sessions 	*node_sessions ;
+	struct timer_cell	timer ;
+} ;
+
+/*
+ * Session variables
+ */
+struct s_sba_sessions {
+	u_long			deallocate_status ;
+	long			session_overhead ;
+	u_long			min_segment_size ;
+	long			session_payload ;
+	u_long			session_status ;
+	u_long			sba_category ;
+	long			lastchg_req_tranid ;
+	u_short			session_id ;
+	u_char			class ;
+	u_char			fddi2 ;
+	u_long			max_t_neg ;
+	struct s_sba_sessions	*next_session ;
+} ;
+
+struct s_sba {
+
+	struct s_sba_node_vars	node[MAX_NODES] ;
+	struct s_sba_sessions	session[MAX_SESSIONS] ;
+
+	struct s_sba_sessions	*free_session ;	/* points to the first */
+						/* free session */
+
+	struct timer_cell	*tail_timer ;	/* points to the last timer cell */
+
+	/*
+	 * variables for allocation actions
+	 */
+	long	total_payload ;		/* Total Payload */
+	long	total_overhead ;	/* Total Overhead */
+	long	sba_allocatable ;	/* allocatable sync bandwidth */
+
+	/*
+	 * RAF message receive parameters
+	 */
+	long		msg_path_index ;	/* Path Type */
+	long		msg_sba_pl_req ;	/* Payload Request */
+	long		msg_sba_ov_req ;	/* Overhead Request */
+	long		msg_mib_pl ;		/* Current Payload for this Path */
+	long		msg_mib_ov ;		/* Current Overhead for this Path*/
+	long		msg_category ;		/* Category of the Allocation */
+	u_long		msg_max_t_neg ;		/* longest T_Neg acceptable */
+	u_long		msg_min_seg_siz ;	/* minimum segement size */
+	struct smt_header	*sm ;		/* points to the rec message */
+	struct fddi_addr	*msg_alloc_addr ;	/* Allocation Address */
+
+	/*
+	 * SBA variables
+	 */
+	u_long	sba_t_neg ;		/* holds the last T_NEG */
+	long	sba_max_alloc ;		/* the parsed value of SBAAvailable */	
+
+	/*
+	 * SBA state machine variables
+	 */
+	short	sba_next_state ;	/* the next state of the SBA */
+	char	sba_command ;		/* holds the execuded SBA cmd */
+	u_char	sba_available ;		/* parsed value after possible check */
+} ;
+
+#endif	/* SBA */
+
+	/*
+	 * variables for the End Station Support
+	 */
+struct s_ess {
+
+	/*
+	 * flags and counters
+	 */
+	u_char	sync_bw_available ;	/* is set if sync bw is allocated */
+	u_char	local_sba_active ;	/* set when a local sba is available */
+	char	raf_act_timer_poll ;	/* activate the timer to send allc req */
+	char	timer_count ;		/* counts every timer function call */
+
+	SMbuf	*sba_reply_pend ;	/* local reply for the sba is pending */
+	
+	/*
+	 * variables for the ess bandwidth control
+	 */
+	long	sync_bw ;		/* holds the allocaed sync bw */
+	u_long	alloc_trans_id ;	/* trans id of the last alloc req */
+} ;
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/sba_def.h linux.18p8/drivers/net/skfp/h/sba_def.h
--- linux.vanilla/drivers/net/skfp/h/sba_def.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/sba_def.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#define PHYS			0		/* physical addr */
+#define PERM_ADDR		0x80		/* permanet address */
+#define SB_STATIC		0x00000001
+#define MAX_PAYLOAD		1562
+#define PRIMARY_RING		0x00000001
+#ifndef NULL
+#define NULL			0x00
+#endif
+
+/*********************** SB_Input Variable Values ***********************/
+/*	 may be needed when ever the SBA state machine is called	*/
+
+#define UNKNOWN_SYNC_SOURCE	0x0001
+#define REQ_ALLOCATION		0x0002
+#define REPORT_RESP		0x0003
+#define CHANGE_RESP		0x0004
+#define TNEG			0x0005
+#define NIF			0x0006
+#define SB_STOP			0x0007
+#define SB_START		0x0008
+#define REPORT_TIMER		0x0009
+#define CHANGE_REQUIRED		0x000A
+
+#define DEFAULT_OV		50
+
+#ifdef SBA
+/**************************** SBA STATES *****************************/
+
+#define SBA_STANDBY		0x00000000
+#define SBA_ACTIVE		0x00000001
+#define SBA_RECOVERY		0x00000002
+#define SBA_REPORT		0x00000003
+#define SBA_CHANGE		0x00000004
+
+/**************************** OTHERS *********************************/
+
+#define FIFTY_PERCENT		50		/* bytes per second */
+#define MAX_SESSIONS		150	
+#define TWO_MINUTES		13079		/* 9.175 ms/tick */
+#define FIFTY_BYTES		50
+#define SBA_DENIED		0x0000000D
+#define I_NEED_ONE		0x00000000
+#define MAX_NODES		50
+/*#define T_REPORT		0x59682F00L*/	/* 120s/80ns in Hex */
+#define	TWO_MIN			120		/* seconds */
+#define SBA_ST_UNKNOWN		0x00000002
+#define SBA_ST_ACTIVE		0x00000001
+#define S_CLEAR			0x00000000L
+#define ZERO			0x00000000
+#define FULL			0x00000000	/* old: 0xFFFFFFFFF */
+#define S_SET			0x00000001L
+#define LOW_PRIO		0x02		/* ??????? */
+#define OK			0x01		/* ??????? */
+#define NOT_OK			0x00		/* ??????? */
+
+/****************************************/
+/* deallocate_status[ni][si] values	*/
+/****************************************/
+#define TX_CHANGE		0X00000001L
+#define PENDING			0x00000002L
+#define NONE			0X00000000L
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/skfbi.h linux.18p8/drivers/net/skfp/h/skfbi.h
--- linux.vanilla/drivers/net/skfp/h/skfbi.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/skfbi.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,1920 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_SKFBI_H_
+#define	_SKFBI_H_
+
+#ifdef SYNC
+#define exist_board_far			exist_board
+#define get_board_para_far		get_board_para
+#endif
+
+/*
+ * physical address offset + IO-Port base address
+ */
+#ifndef	PCI
+#define	ADDR(a)	((a)+smc->hw.iop)
+#define	ADDRS(smc,a) ((a)+(smc)->hw.iop)
+#endif
+
+/*
+ * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)})
+ *	address calculation & function defines
+ */
+
+#ifdef	EISA
+
+/*
+ * Configuration PROM:	 !! all 8-Bit IO's !!
+ *					    |<-	  MAC-Address	 ->|
+ *	/-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
+ * val:	  |PROD_ID0..3|	   | free      |    |00|00|5A|40|    |nn|mm|00|00|
+ *	/-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
+ * IO-	  ^	      ^	   ^		    ^		     ^
+ * port	0C80	    0C83  0C88		   0C90		    0C98
+ *	  |	       \
+ *	  |		\
+ *	  |		 \______________________________________________
+ * EISA Expansion Board Product ID:					\
+ * BIT:	  |7 6 5 4 3 2 1 0|						 \
+ *	  | PROD_ID0	  | PROD_ID1	  | PROD_ID2	  | PROD_ID3	  |
+ *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *	  |0| MAN_C0  | MAN_C1	| MAN_C2  | PROD1 | PROD0 | REV1  | REV0  |
+ *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *	   ^=reserved			  | product numb. | revision numb |
+ * MAN_Cx = compressed manufacterer code (x:=0..2)
+ *	ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!)
+ */
+
+#ifndef	MULT_OEM
+#ifndef	OEM_CONCEPT
+#define	MAN_C0		('S'-0x40)
+#define	MAN_C1		('K'-0x40)
+#define	MAN_C2		('D'-0x40)
+#define	PROD_ID0	(u_char)((MAN_C0<<2) | (MAN_C1>>3))
+#define	PROD_ID1	(u_char)(((MAN_C1<<5) & 0xff) | MAN_C2)
+#define	PROD_ID2	(u_char)(1)	/* prod. nr. */
+#define	PROD_ID3	(u_char)(0)	/* rev. nr. */
+
+#ifndef	OEM_USER_DATA
+#define	OEM_USER_DATA	"SK-NET FDDI V2.0 Userdata"
+#endif
+#else	/*  OEM_CONCEPT */
+
+/* MAN_C(0|1|2) no longer present (ra). */
+#define	PROD_ID0	(u_char)OEM_PROD_ID0
+#define	PROD_ID1	(u_char)OEM_PROD_ID1
+#define	PROD_ID2	(u_char)OEM_PROD_ID2
+#define	PROD_ID3	(u_char)OEM_PROD_ID3
+#endif	/* OEM_CONCEPT */
+
+#define	SKLOGO		PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3
+#endif	/* MULT_OEM */
+
+#define	SADDRL	(0)		/* start address SKLOGO */
+#define	SA_MAC	(0x10)		/* start addr. MAC_AD within the PROM */
+#define	PRA_OFF	(4)
+#define SA_PMD_TYPE	(8)	/* start addr. PMD-Type */
+
+#define	SKFDDI_PSZ	32		/* address PROM size */
+
+/*
+ * address transmision from logical to physical offset address on board
+ */
+#define FMA(a)	(0x0400|((a)<<1))	/* FORMAC+ (r/w) */
+#define P1A(a)	(0x0800|((a)<<1))	/* PLC1 (r/w) */
+#define P2A(a)	(0x0840|((a)<<1))	/* PLC2 (r/w) */
+#define TIA(a)	(0x0880|((a)<<1))	/* Timer (r/w) */
+#define PRA(a)	(0x0c80| (a))		/* configuration PROM */
+#define	C0A(a)	(0x0c84| (a))		/* config. RAM */
+#define	C1A(a)	(0x0ca0| (a))		/* IRQ-, DMA-nr., EPROM type */
+#define	C2A(a)	(0x0ca4| (a))		/* EPROM and PAGE selector */
+
+#define	CONF	C0A(0)			/* config RAM (card enable bit port) */
+#define PGRA	C2A(0)			/* Flash page register */
+#define	CDID	PRA(0)			/* Card ID I/O port addr. offset */
+
+
+/*
+ * physical address offset + slot specific IO-Port base address
+ */
+#define FM_A(a)	(FMA(a)+smc->hw.iop)	/* FORMAC Plus physical addr */
+#define P1_A(a)	(P1A(a)+smc->hw.iop)	/* PLC1 (r/w) */
+#define P2_A(a)	(P2A(a)+smc->hw.iop)	/* PLC2 (r/w) */
+#define TI_A(a)	(TIA(a)+smc->hw.iop)	/* Timer (r/w) */
+#define PR_A(a)	(PRA(a)+smc->hw.iop)	/* config. PROM */
+#define C0_A(a)	(C0A(a)+smc->hw.iop)	/* config. RAM */
+#define C1_A(a)	(C1A(a)+smc->hw.iop)	/* config. RAM */
+#define C2_A(a)	(C2A(a)+smc->hw.iop)	/* config. RAM */
+
+
+#define	CSRA	0x0008		/* control/status register address (r/w) */
+#define	ISRA	0x0008		/* int. source register address (upper 8Bits) */
+#define PLC1I	0x001a		/* clear PLC1 interrupt (write only) */
+#define PLC2I	0x0020		/* clear PLC2 interrupt (write only) */
+#define CSFA	0x001c		/* control/status FIFO BUSY flags (read only) */
+#define RQAA	0x001c		/* Request reg. (write only) */
+#define WCTA	0x001e		/* word counter (r/w) */
+#define	FFLAG	0x005e		/* FLAG/V_FULL (FIFO almost full, write only)*/
+
+#define	CSR_A	(CSRA+smc->hw.iop)	/* control/status register address (r/w) */
+#ifdef UNIX
+#define	CSR_AS(smc)	(CSRA+(smc)->hw.iop)	/* control/status register address (r/w) */
+#endif
+#define	ISR_A	(ISRA+smc->hw.iop)	/* int. source register address (upper 8Bits) */
+#define PLC1_I	(PLC1I+smc->hw.iop)	/* clear PLC1 internupt (write only) */
+#define PLC2_I	(PLC2I+smc->hw.iop)	/* clear PLC2 interrupt (write only) */
+#define CSF_A	(CSFA+smc->hw.iop)	/* control/status FIFO BUSY flags (r/w) */
+#define RQA_A	(RQAA+smc->hw.iop)	/* Request reg. (write only) */
+#define WCT_A	(WCTA+smc->hw.iop)	/* word counter (r/w) */
+#define	FFLAG_A	(FFLAG+smc->hw.iop)	/* FLAG/V_FULL (FIFO almost full, write only)*/
+
+/*
+ * control/status register CSRA	bits
+ */
+/* write */
+#define CS_CRESET	0x01		/* Card reset (0=reset) */
+#define	CS_RESET_FIFO	0x02		/* FIFO reset (0=reset) */
+#define	CS_IMSK		0x04		/* enable IRQ (1=enable, 0=disable) */
+#define	CS_EN_IRQ_TC	0x08		/* enable IRQ from transfer counter */
+#define CS_BYPASS	0x20		/* bypass switch (0=remove, 1=insert)*/
+#define CS_LED_0	0x40		/* switch LED 0 */
+#define	CS_LED_1	0x80		/* switch LED 1 */
+/* read */
+#define	CS_BYSTAT	0x40		/* 0=Bypass exist, 1= ..not */
+#define	CS_SAS		0x80		/* single attachement station (=1) */
+
+/*
+ * control/status register CSFA bits (FIFO)
+ */
+#define	CSF_MUX0	0x01
+#define	CSF_MUX1	0x02
+#define	CSF_HSREQ0	0x04
+#define	CSF_HSREQ1	0x08
+#define	CSF_HSREQ2	0x10
+#define	CSF_BUSY_DMA	0x40
+#define	CSF_BUSY_FIFO	0x80
+
+/*
+ * Interrupt source register ISRA (upper 8 data bits) read only & low activ.
+ */
+#define IS_MINTR1	0x0100		/* FORMAC ST1U/L & ~IMSK1U/L*/
+#define IS_MINTR2	0x0200		/* FORMAC ST2U/L & ~IMSK2U/L*/
+#define IS_PLINT1	0x0400		/* PLC1 */
+#define IS_PLINT2	0x0800		/* PLC2 */
+#define IS_TIMINT	0x1000		/* Timer 82C54-2 */
+#define	IS_TC		0x2000		/* transf. counter */
+
+#define	ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC)
+
+/*
+ * CONFIG<0> RAM (C0_A())
+ */
+#define	CFG_CARD_EN	0x01		/* card enable */
+
+/*
+ * CONFIG<1> RAM (C1_A())
+ */
+#define	CFG_IRQ_SEL	0x03		/* IRQ select (4 nr.) */
+#define	CFG_IRQ_TT	0x04		/* IRQ trigger type (LEVEL/EDGE) */
+#define	CFG_DRQ_SEL	0x18		/* DMA requ. (4 nr.) */
+#define	CFG_BOOT_EN	0x20		/* 0=BOOT-, 1=Application Software */
+#define	CFG_PROG_EN	0x40		/* V_Prog for FLASH_PROM (1=on) */
+
+/*
+ * CONFIG<2> RAM (C2_A())
+ */
+#define	CFG_EPROM_SEL	0x0f		/* FPROM start address selection */
+#define	CFG_PAGE	0xf0		/* FPROM page selection */
+
+
+#define	READ_PROM(a)	((u_char)inp(a))
+#define	GET_PAGE(i)	outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE))
+#define	FPROM_SW()	(inp(C1_A(0)) & CFG_BOOT_EN)
+
+#define	MAX_PAGES	16		/* 16 pages */
+#define	MAX_FADDR	0x2000		/* 8K per page */
+#define	VPP_ON()	outp(C1_A(0),inp(C1_A(0)) |  CFG_PROG_EN)
+#define	VPP_OFF()	outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN)
+
+#define	DMA_BUSY()	(inpw(CSF_A) & CSF_BUSY_DMA)
+#define FIFO_BUSY()	(inpw(CSF_A) & CSF_BUSY_FIFO)
+#define	DMA_FIFO_BUSY()	(inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
+#define	BUS_CHECK()
+
+#ifdef UNISYS
+/* For UNISYS use another macro with drv_usecewait function */
+#define CHECK_DMA() {u_long k = 1000000; \
+		while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \
+		if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+#else
+#define CHECK_DMA() {u_long k = 1000000 ;\
+		while (k && (DMA_BUSY())) k-- ;\
+		if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+#endif
+
+#define CHECK_FIFO() {u_long k = 1000000 ;\
+		while (k && (FIFO_BUSY())) k-- ;\
+		if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
+
+#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\
+		while (k && (DMA_FIFO_BUSY())) k-- ;\
+		if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
+
+#define	GET_ISR()	~inpw(ISR_A)
+#define CHECK_ISR()	~inpw(ISR_A)
+
+#ifndef UNIX
+#ifndef	WINNT
+#define	CLI_FBI()	outpw(CSR_A,(inpw(CSR_A)&\
+			(CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
+#else	/* WINNT */
+#define CLI_FBI()	outpw(CSR_A,(l_inpw(CSR_A)&\
+			(CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
+#endif	/* WINNT */
+#else	/* UNIX */
+#define	CLI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
+			(CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led)
+#endif
+
+#ifndef UNIX
+#define	STI_FBI()	outpw(CSR_A,(inpw(CSR_A)&\
+		(CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led)
+#else
+#define	STI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
+		(CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led)
+#endif
+
+/* EISA DMA Controller */
+#define DMA_WRITE_SINGLE_MASK_BIT_M	0x0a	/* Master DMA Controller */
+#define DMA_WRITE_SINGLE_MASK_BIT_S	0xd4	/* Slave DMA Controller */
+#define DMA_CLEAR_BYTE_POINTER_M	0x0c
+#define DMA_CLEAR_BYTE_POINTER_S	0xd8
+
+#endif	/* EISA */
+
+#ifdef	MCA
+
+/*
+ * POS Register:	 !! all I/O's are 8-Bit !!
+ */
+#define	POS_SYS_SETUP	0x94	/* system setup register */
+#define	POS_SYSTEM	0xff	/* system mode */
+
+#define	POS_CHANNEL_POS	0x96	/* register slot ID */
+#define	POS_CHANNEL_BIT	0x08	/* mask for -"- */
+
+#define	POS_BASE	0x100	/* POS base address */
+#define	POS_ID_LOW	POS_BASE	/* card ID low */
+#define	POS_ID_HIGH	(POS_BASE+1)	/* card ID high */
+#define	POS_102		(POS_BASE+2)	/* card en., arbitration level .. */
+#define	POS_103		(POS_BASE+3)	/* FPROM addr, page */
+#define	POS_104		(POS_BASE+4)	/* I/O, IRQ */
+#define	POS_105		(POS_BASE+5)	/* POS_CHCK */
+#define	POS_106		(POS_BASE+6)	/* to read VPD */
+#define	POS_107		(POS_BASE+7)	/* added without function */
+
+/* FM1 card IDs */
+#define	FM1_CARD_ID0	0x83
+#define	FM1_CARD_ID1	0
+
+#define	FM1_IBM_ID0	0x9c
+#define	FM1_IBM_ID1	0x8f
+
+
+/* FM2 card IDs */
+#define	FM2_CARD_ID0	0xab
+#define	FM2_CARD_ID1	0
+
+#define	FM2_IBM_ID0	0x7e
+#define	FM2_IBM_ID1	0x8f
+
+/* Board revision. */
+#define FM1_REV		0
+#define FM2_REV		1
+
+#define	MAX_SLOT	8
+
+/*
+ * POS_102
+ */
+#define	POS_CARD_EN	0x01	/* card enable =1 */
+#define	POS_SDAT_EN	0x02	/* enable 32-bit streaming data mode */
+#define	POS_EN_CHKINT	0x04	/* enable int. from check line asserted */
+#define	POS_EN_BUS_ERR	0x08	/* enable int. on invalid busmaster transf. */
+#define	POS_FAIRNESS	0x10	/* fairnes on =1 */
+/* attention: arbitration level used with bit 0 POS 105 */
+#define	POS_LARBIT	0xe0	/* arbitration level	(0,0,0)->level = 0x8
+							(1,1,1)->level = 0xf */
+/*
+ * POS_103
+ */
+#define	POS_PAGE	0x07	/* FPROM page selection */
+#define	POS_BOOT_EN	0x08	/* boot PROM enable =1 */
+#define	POS_MSEL	0x70	/* memory start address for FPROM mapping */
+#define	PROG_EN		0x80	/* FM1: Vpp prog on/off */
+#define	POS_SDR		0x80	/* FM2: Streaming data bit */
+
+/*
+ * POS_104
+ */
+#define	POS_IOSEL	0x3f	/* selected I/O base address */
+#define	POS_IRQSEL	0xc0	/* selected interrupt */
+
+/*
+ * POS_105
+ */
+#define	POS_CHCK	0x80
+#define POS_SYNC_ERR	0x20	/* FM2: synchronous error reporting	*/
+#define POS_PAR_DATA	0x10	/* FM2: data parity enable bit	*/
+#define POS_PAR_ADDR	0x08	/* FM2: address parity enable bit	*/
+#define	POS_IRQHSEL	0x02	/* FM2: Highest bit for IRQ_selection	*/
+#define POS_HARBIT	0x01	/* Highest bit in Bus arbitration selection */
+
+#define	SA_MAC	(0)		/* start addr. MAC_AD within the PROM	*/
+#define	PRA_OFF	(0)
+#define SA_PMD_TYPE	(8)	/* start addr. PMD-Type	*/
+
+/*
+ * address transmision from logical to physical offset address on board
+ */
+#define	FMA(a)	(0x0100|((a)<<1))	/* FORMAC+ (r/w) */
+#define	P2(a)	(0x00c0|((a)<<1))	/* PLC2 (r/w) (DAS) */
+#define	P1(a)	(0x0080|((a)<<1))	/* PLC1 (r/w) */
+#define	TI(a)	(0x0060|((a)<<1))	/* Timer (r/w) */
+#define	PR(a)	(0x0040|((a)<<1))	/* configuration PROM */
+#define	CS(a)	(0x0020| (a))		/* control/status */
+#define	FF(a)	(0x0010|((a)<<1))	/* FIFO ASIC */
+#define	CT(a)	(0x0000|((a)<<1))	/* counter */
+
+/*
+ * counter
+ */
+#define	ACLA	CT(0)		/* address counter low */
+#define	ACHA	CT(1)		/* address counter high */
+#define	BCN	CT(2)		/* byte counter */
+#define	MUX	CT(3)		/* MUX-register */
+#define	WCN	CT(0x08)	/* word counter */
+#define	FFLG	CT(0x09)	/* FIFO Flags */
+
+/*
+ * test/control register (FM2 only)
+ */
+#define CNT_TST	0x018		/* Counter test control register */
+#define CNT_STP 0x01a		/* Counter test step reg. (8 Bit) */
+
+/*
+ * CS register (read only)
+ */
+#define	CSRA	CS(0)		/* control/status register address */
+#define	CSFA	CS(2)		/* control/status FIFO BUSY ...	 */
+#define	ISRA	CS(4)		/* first int. source register address */
+#define	ISR2	CS(6)		/* second int. source register address */
+#define	LEDR	CS(0x0c)	/* LED register r/w */
+#define	CSIL	CS(0x10)	/* I/O mapped POS_ID_low (100) */
+#define	CSIH	CS(0x12)	/*	- " - POS_ID_HIGH (101) */
+#define	CSA	CS(0x14)	/*	- " - POS_102 */
+#define	CSM	CS(0x0e)	/*	- " - POS_103 */
+#define	CSM_FM1	CS(0x16)	/*	- " - POS_103 (copy in FM1) */
+#define	CSI	CS(0x18)	/*	- " - POS_104 */
+#define	CSS	CS(0x1a)	/*	- " - POS_105 */
+#define	CSP_06	CS(0x1c)	/*	- " - POS_106 */
+#define	WDOG_ST		0x1c	/* Watchdog status (FM2 only)	*/
+#define	WDOG_EN		0x1c	/* Watchdog enabling (FM2 only, 8Bit)	*/
+#define	WDOG_DIS	0x1e	/* Watchdog disabling (FM2 only, 8Bit)	*/
+
+#define PGRA	CSM		/* Flash page register */
+
+
+#define	WCTA	FF(0)		/* word counter */
+#define	FFLAG	FF(1)		/* FLAG/V_FULL (FIFO almost full, write only)*/
+
+/*
+ * Timer register (FM2 only)
+ */
+#define RTM_CNT		0x28		/* RTM Counter */
+#define TI_DIV		0x60		/* Timer Prescaler */
+#define TI_CH1		0x62		/* Timer channel 1 counter */
+#define TI_STOP		0x64		/* Stop timer on channel 1 */
+#define TI_STRT		0x66		/* Start timer on channel 1 */
+#define TI_INI2		0x68		/* Timer: Bus master preemption */
+#define TI_CNT2		0x6a		/* Timer */
+#define TI_INI3		0x6c		/* Timer: Streaming data */
+#define TI_CNT3		0x6e		/* Timer */
+#define WDOG_LO		0x70		/* Watchdog counter low */
+#define WDOG_HI		0x72		/* Watchdog counter high */
+#define RTM_PRE		0x74		/* restr. token prescaler */
+#define RTM_TIM		0x76		/* restr. token timer */
+
+/*
+ * Recommended Timeout values (for FM2 timer only)
+ */
+#define TOUT_BM_PRE	188		/* 3.76 usec	*/
+#define TOUT_S_DAT	374		/* 7.48 usec	*/
+
+/*
+ * CS register (write only)
+ */
+#define	HSR(p)	CS(0x18|(p))	/* Host request register */
+
+#define	RTM_PUT		0x36		/* restr. token counter write */
+#define	RTM_GET		0x28		/*	- " -	clear */
+#define	RTM_CLEAR	0x34		/*	- " -	read */
+
+/*
+ * BCN	Bit definitions
+ */
+#define BCN_BUSY	0x8000		/* DMA Busy flag */
+#define BCN_AZERO	0x4000		/* Almost zero flag (BCN < 4) */
+#define BCN_STREAM	0x2000		/* Allow streaming data (BCN >= 8) */
+
+/*
+ * WCN	Bit definitions
+ */
+#define WCN_ZERO	0x2000		/* Zero flag (counted to zero) */
+#define WCN_AZERO	0x1000		/* Almost zero flag (BCN < 4) */
+
+/*
+ * CNT_TST	Bit definitions
+ */
+#define CNT_MODE	0x01		/* Go into test mode */
+#define	CNT_D32		0x02		/* 16/32 BIT test mode */
+
+/*
+ * FIFO Flag		FIFO Flags/Vfull register
+ */
+#define FF_VFULL	0x003f		/* V_full value mask */
+#define FFLG_FULL	0x2000		/* FULL flag */
+#define FFLG_A_FULL	0x1000		/* Almost full flag */
+#define FFLG_VFULL	0x0800		/* V_full Flag */
+#define FFLG_A_EMP	0x0400		/* almost empty flag */
+#define FFLG_EMP	0x0200		/* empty flag */
+#define FFLG_T_EMP	0x0100		/* totally empty flag */
+
+/*
+ * WDOG		Watchdog status register
+ */
+#define WDOG_ALM	0x01		/* Watchdog alarm Bit */
+#define WDOG_ACT	0x02		/* Watchdog active Bit */
+
+/*
+ * CS(0)	CONTROLS
+ */
+#define	CS_CRESET	0x0001
+#define	FIFO_RST	0x0002
+#define	CS_IMSK		0x0004
+#define	EN_IRQ_CHCK	0x0008
+#define	EN_IRQ_TOKEN	0x0010
+#define	EN_IRQ_TC	0x0020
+#define	TOKEN_STATUS	0x0040
+#define	RTM_CHANGE	0x0080
+
+#define	CS_SAS		0x0100
+#define	CS_BYSTAT	0x0200	/* bypass connected (0=conn.) */
+#define	CS_BYPASS	0x0400	/* bypass on/off indication */
+
+/*
+ * CS(2)	FIFOSTAT
+ */
+#define	HSREQ		0x0007
+#define	BIGDIR		0x0008
+#define	CSF_BUSY_FIFO	0x0010
+#define	CSF_BUSY_DMA	0x0020
+#define	SLOT_32		0x0040
+
+#define	LED_0		0x0001
+#define	LED_1		0x0002
+#define	LED_2		0x0100
+
+#define	MAX_PAGES	8		/* pages */
+#define	MAX_FADDR	0x4000		/* 16K per page */
+
+/*
+ *	IRQ = ISRA || ISR2 ;
+ *
+ *	ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ;
+ *	ISR2 = IRQ_TC_EN && IS_TC ;
+ *
+ *	IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) ||
+ *		 (IRQ_EN_TOKEN && IS_TOKEN) ;
+ *	IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ;
+ */
+/*
+ *	ISRA	!!! activ high !!!
+ */
+#define	IS_MINTR1	0x0001		/* FORMAC ST1U/L & ~IMSK1U/L*/
+#define	IS_MINTR2	0x0002		/* FORMAC ST2U/L & ~IMSK2U/L*/
+#define	IS_PLINT1	0x0004		/* PLC1 */
+#define	IS_PLINT2	0x0008		/* PLC2 */
+#define	IS_TIMINT	0x0010		/* Timer 82C54-2 */
+#define	IS_TOKEN	0x0020		/* restrictet token monitoring */
+#define	IS_CHCK_L	0x0040		/* check line asserted */
+#define	IS_BUSERR	0x0080		/* bus error */
+/*
+ *	ISR2
+ */
+#define	IS_TC		0x0001		/* terminal count irq */
+#define IS_SFDBKRTN	0x0002		/* selected feedback return */
+#define IS_D16		0x0004		/* DS16 */
+#define	IS_D32		0x0008		/* DS32 */
+#define IS_DPEI		0x0010		/* Data Parity Indication */
+
+#define	ALL_IRSR	0x00ff
+
+#define	FM_A(a)	ADDR(FMA(a))	/* FORMAC Plus physical addr */
+#define	P1_A(a)	ADDR(P1(a))	/* PLC1 (r/w) */
+#define	P2_A(a)	ADDR(P2(a))	/* PLC2 (r/w) (DAS) */
+#define	TI_A(a)	ADDR(TI(a))	/* Timer (r/w) FM1 only! */
+#define	PR_A(a)	ADDR(PR(a))	/* config. PROM */
+#define	CS_A(a)	ADDR(CS(a))	/* control/status */
+
+#define	ISR1_A	ADDR(ISRA)	/* first int. source register address */
+#define	ISR2_A	ADDR(ISR2)	/* second	-"-	 */
+#define	CSR_A	ADDR(CSRA)	/* control/status register address */
+#define	CSF_A	ADDR(CSFA)	/* control/status FIFO BUSY flags (r/w) */
+
+#define	CSIL_A	ADDR(CSIL)	/* I/O mapped POS_ID_low (102) */
+#define	CSIH_A	ADDR(CSIH)	/*	- " - POS_ID_HIGH (101) */
+#define	CSA_A	ADDR(CSA)	/*	- " - POS_102 */
+#define	CSI_A	ADDR(CSI)	/*	- " - POS_104 */
+#define	CSM_A	ADDR(CSM)	/*	- " - POS_103 */
+#define	CSM_FM1_A	ADDR(CSM_FM1)	/*	- " - POS_103 (2nd copy, FM1) */
+#define	CSP_06_A	ADDR(CSP_06)	/*	- " - POS_106 */
+
+#define	WCT_A	ADDR(WCTA)	/* word counter (r/w) */
+#define	FFLAG_A	ADDR(FFLAG)	/* FLAG/V_FULL (FIFO almost full, write only)*/
+
+#define	ACL_A	ADDR(ACLA)	/* address counter low */
+#define	ACH_A	ADDR(ACHA)	/* address counter high */
+#define	BCN_A	ADDR(BCN)	/* byte counter */
+#define	MUX_A	ADDR(MUX)	/* MUX-register */
+
+#define	ISR_A	ADDR(ISRA)	/* Interrupt Source Register */
+#define	FIFO_RESET_A	ADDR(FIFO_RESET)	/* reset the FIFO */
+#define	FIFO_EN_A	ADDR(FIFO_EN)		/* enable the FIFO */
+
+#define WDOG_EN_A	ADDR(WDOG_EN)		/* reset and start the WDOG */
+#define WDOG_DIS_A	ADDR(WDOG_DIS)		/* disable the WDOG */
+/*
+ * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A)
+ */
+#define	HSR_A(p)	ADDR(HSR(p))	/* Host request register */
+
+#define	STAT_BYP	0		/* bypass station */
+#define	STAT_INS	2		/* insert station */
+#define	BYPASS(o)	CS(0x10|(o))	/* o=STAT_BYP || STAT_INS */
+
+#define	IRQ_TC_EN	CS(0x0b)	/* enable/disable IRQ on TC */
+#define	IRQ_TC_DIS	CS(0x0a)
+#define	IRQ_TOKEN_EN	CS(9)		/* enable/disable IRQ on restr. Token */
+#define	IRQ_TOKEN_DIS	CS(8)
+#define	IRQ_CHCK_EN	CS(7)		/*	-"-	IRQ after CHCK line */
+#define	IRQ_CHCK_DIS	CS(6)
+#define	IRQ_OTH_EN	CS(5)		/*	-"-	other IRQ's */
+#define	IRQ_OTH_DIS	CS(4)
+#define	FIFO_EN		CS(3)		/* disable (reset), enable FIFO */
+#define	FIFO_RESET	CS(2)
+#define	CARD_EN		CS(1)		/* disable (reset), enable card */
+#define	CARD_DIS	CS(0)
+
+#define	LEDR_A		ADDR(LEDR)	/* D0=green, D1=yellow, D8=L2 */
+#define	PAGE_RG_A	ADDR(CSM)	/* D<2..0> */
+#define	IRQ_CHCK_EN_A	ADDR(IRQ_CHCK_EN)
+#define IRQ_CHCK_DIS_A	ADDR(IRQ_CHCK_DIS)
+
+#define	GET_PAGE(bank)	outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\
+				(~POS_PAGE)) |(int) (bank))
+#define	VPP_ON()	if (smc->hw.rev == FM1_REV) {	\
+				outpw(PAGE_RG_A,	\
+				(inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \
+			}
+#define	VPP_OFF()	if (smc->hw.rev == FM1_REV) {	\
+				outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \
+			}
+
+#define	SKFDDI_PSZ	16		/* address PROM size */
+
+#define	READ_PROM(a)	((u_char)inp(a))
+
+#define	GET_ISR()	~inpw(ISR1_A)
+#ifndef	TCI
+#define	CHECK_ISR()	~inpw(ISR1_A)
+#define	CHECK_ISR_SMP(iop)	~inpw((iop)+ISRA)
+#else
+#define	CHECK_ISR()		(~inpw(ISR1_A) | ~inpw(ISR2_A))
+#define	CHECK_ISR_SMP(iop)	(~inpw((iop)+ISRA) | ~inpw((iop)+ISR2))
+#endif
+
+#define	DMA_BUSY()	(inpw(CSF_A) & CSF_BUSY_DMA)
+#define	FIFO_BUSY()	(inpw(CSF_A) & CSF_BUSY_FIFO)
+#define	DMA_FIFO_BUSY()	(inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
+#define	BUS_CHECK() {	int i ; \
+			if ((i = GET_ISR()) & IS_BUSERR) \
+				SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \
+			if (i & IS_CHCK_L) \
+				SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \
+		}
+
+#define	CHECK_DMA() {	u_long k = 10000 ; \
+		 while (k && (DMA_BUSY())) { \
+			k-- ; \
+			BUS_CHECK() ; \
+		 } \
+		 if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+
+#define	CHECK_FIFO() {u_long k = 1000000 ;\
+		 while (k && (FIFO_BUSY())) k-- ;\
+		 if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
+
+#define	CHECK_DMA_FIFO() {u_long k = 1000000 ;\
+		 while (k && (DMA_FIFO_BUSY())) { \
+			k-- ;\
+			BUS_CHECK() ; \
+		 } \
+		 if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
+
+#ifndef UNIX
+#define	CLI_FBI()	outp(ADDR(IRQ_OTH_DIS),0)
+#else
+#define	CLI_FBI(smc)	outp(ADDRS((smc),IRQ_OTH_DIS),0)
+#endif
+
+#ifndef	TCI
+#define	CLI_FBI_SMP(iop)	outp((iop)+IRQ_OTH_DIS,0)
+#else
+#define	CLI_FBI_SMP(iop)	outp((iop)+IRQ_OTH_DIS,0) ;\
+				outp((iop)+IRQ_TC_DIS,0)
+#endif
+
+#ifndef UNIX
+#define	STI_FBI()	outp(ADDR(IRQ_OTH_EN),0)
+#else
+#define	STI_FBI(smc)	outp(ADDRS((smc),IRQ_OTH_EN),0)
+#endif
+
+/*
+ * Terminal count primitives
+ */
+#define CLI_TCI(smc)	outp(ADDRS((smc),IRQ_TC_DIS),0)
+#define STI_TCI(smc)	outp(ADDRS((smc),IRQ_TC_EN),0)
+#define CHECK_TC(smc,k)	{(k) = 10000 ;\
+	while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\
+	if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; }
+
+#endif	/* MCA */
+
+#ifdef	ISA
+
+/*
+ * address transmision from logic NPADDR6-0 to physical offset address on board
+ */
+#define FMA(a)	(0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7))  /* FORMAC+ (r/w) */
+#define PRA(a)	(0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7))  /* PROM (read only)*/
+#define P1A(a)	(0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7))  /* PLC1 (r/w) */
+#define P2A(a)	(0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7))  /* PLC2 (r/w) */
+#define TIA(a)	(0x6000|(((a)&0x03)<<1))		  /* Timer (r/w) */
+
+#define	ISRA	0x0000		/* int. source register address (read only) */
+#define	ACLA	0x0000		/* address counter low address (write only) */
+#define	ACHA	0x0002		/* address counter high address (write only) */
+#define	TRCA	0x0004		/* transfer counter address (write only) */
+#define	PGRA	0x0006		/* page register address (write only) */
+#define RQAA	0x2000		/* Request reg. (write only) */
+#define	CSRA	0x3000		/* control/status register address (r/w) */
+
+/*
+ * physical address offset + IO-Port base address
+ */
+#define FM_A(a)	(FMA(a)+smc->hw.iop)	/* FORMAC Plus physical addr */
+#define PR_A(a)	(PRA(a)+smc->hw.iop)	/* PROM (read only)*/
+#define P1_A(a)	(P1A(a)+smc->hw.iop)	/* PLC1 (r/w) */
+#define P2_A(a)	(P2A(a)+smc->hw.iop)	/* PLC2 (r/w) */
+#define TI_A(a)	(TIA(a)+smc->hw.iop)	/* Timer (r/w) */
+
+#define	ISR_A	(0x0000+smc->hw.iop) /* int. source register address (read only) */
+#define	ACL_A	(0x0000+smc->hw.iop) /* address counter low address (write only) */
+#define	ACH_A	(0x0002+smc->hw.iop) /* address counter high address (write only)*/
+#define	TRC_A	(0x0004+smc->hw.iop) /* transfer counter address (write only) */
+#define	PGR_A	(0x0006+smc->hw.iop) /* page register address (write only) */
+#define RQA_A	(0x2000+smc->hw.iop) /* Request reg. (write only) */
+#define	CSR_A	(0x3000+smc->hw.iop) /* control/status register address (r/w) */
+#ifdef UNIX
+#define	CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */
+#endif
+#define	PLC1_I	(0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */
+#define	PLC2_I	(0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */
+
+#ifndef	MULT_OEM
+#ifndef	OEM_CONCEPT
+#define	SKLOGO_STR	"SKFDDI"
+#else	/* OEM_CONCEPT */
+#define	SKLOGO_STR	OEM_FDDI_LOGO
+#endif	/* OEM_CONCEPT */
+#endif  /* MULT_OEM */
+#define	SADDRL	(24)		/* start address SKLOGO */
+#define	SA_MAC	(0)		/* start addr. MAC_AD within the PROM */
+#define	PRA_OFF	(0)
+#define SA_PMD_TYPE	(8)	/* start addr. PMD-Type */
+
+#define	CDID	(PRA(SADDRL))	/* Card ID int/O port addr. offset */
+#define	NEXT_CDID	((PRA(SADDRL+1)) - CDID)
+
+#define	SKFDDI_PSZ	32		/* address PROM size */
+
+#define	READ_PROM(a)	((u_char)inpw(a))
+#define	GET_PAGE(i)	outpw(PGR_A,(int)(i))
+
+#define	MAX_PAGES	16		/* 16 pages */
+#define	MAX_FADDR	0x2000		/* 8K per page */
+#define	VPP_OFF()	outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)))
+#define	VPP_ON()	outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \
+				CS_VPPSW)
+
+/*
+ * control/status register CSRA	bits (log. addr: 0x3000)
+ */
+/* write */
+#define CS_CRESET	0x01		/* Card reset (0=reset) */
+#define	CS_IMSK		0x02		/* enable IRQ (1=enable, 0=disable) */
+#define CS_RESINT1	0x04		/* PLINT1 reset */
+#define	CS_VPPSW	0x10		/* 12V power switch (0=off, 1=on) */
+#define CS_BYPASS	0x20		/* bypass switch (0=remove, 1=insert)*/
+#define CS_RESINT2	0x40		/* PLINT2 reset */
+/* read */
+#define	CS_BUSY		0x04		/* master transfer activ (=1) */
+#define	CS_SW_EPROM	0x08		/* 0=Application Soft. 1=BOOT-EPROM */
+#define	CS_BYSTAT	0x40		/* 0=Bypass exist, 1= ..not */
+#define	CS_SAS		0x80		/* single attachement station (=1) */
+
+/*
+ * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ.
+ */
+#define IS_MINTR1	0x01		/* FORMAC ST1U/L && ~IMSK1U/L*/
+#define IS_MINTR2	0x02		/* FORMAC ST2U/L && ~IMSK2U/L*/
+#define IS_PLINT1	0x04		/* PLC1 */
+#define IS_PLINT2	0x08		/* PLC2 */
+#define IS_TIMINT	0x10		/* Timer 82C54-2 */
+
+#define	ALL_IRSR	(IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT)
+
+#define	FPROM_SW()	(inpw(CSR_A)&CS_SW_EPROM)
+#define	DMA_BUSY()	(inpw(CSR_A)&CS_BUSY)
+#define CHECK_FIFO()
+#define	BUS_CHECK()
+
+/*
+ * set Host Request register (wr.)
+ */
+#define SET_HRQ(qup)	outpw(RQA_A+((qup)<<1),0)
+
+#ifndef UNIX
+#ifndef WINNT
+#define	CLI_FBI()	outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW)))
+#else
+#define	CLI_FBI()	outpw(CSR_A,(l_inpw(CSR_A) & \
+				(CS_CRESET|CS_BYPASS|CS_VPPSW)))
+#endif
+#else
+#define	CLI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \
+						(CS_CRESET|CS_BYPASS|CS_VPPSW)))
+#endif
+
+#ifndef UNIX
+#define	STI_FBI()	outpw(CSR_A,(inpw(CSR_A) & \
+				(CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
+#else
+#define	STI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \
+				(CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
+#endif
+
+#define CHECK_DMA()	{unsigned k = 10000 ;\
+			while (k && (DMA_BUSY())) k-- ;\
+			if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
+
+#define	GET_ISR()	~inpw(ISR_A)
+
+#endif	/* ISA */
+
+/*--------------------------------------------------------------------------*/
+#ifdef	PCI
+
+/*
+ *	(DV)	= only defined for Da Vinci
+ *	(ML)	= only defined for Monalisa
+ */
+
+/*
+ * Configuration Space header
+ */
+#define	PCI_VENDOR_ID	0x00	/* 16 bit	Vendor ID */
+#define	PCI_DEVICE_ID	0x02	/* 16 bit	Device ID */
+#define	PCI_COMMAND	0x04	/* 16 bit	Command */
+#define	PCI_STATUS	0x06	/* 16 bit	Status */
+#define	PCI_REV_ID	0x08	/*  8 bit	Revision ID */
+#define	PCI_CLASS_CODE	0x09	/* 24 bit	Class Code */
+#define	PCI_CACHE_LSZ	0x0c	/*  8 bit	Cache Line Size */
+#define	PCI_LAT_TIM	0x0d	/*  8 bit	Latency Timer */
+#define	PCI_HEADER_T	0x0e	/*  8 bit	Header Type */
+#define	PCI_BIST	0x0f	/*  8 bit	Built-in selftest */
+#define	PCI_BASE_1ST	0x10	/* 32 bit	1st Base address */
+#define	PCI_BASE_2ND	0x14	/* 32 bit	2nd Base address */
+/* Byte 18..2b:	Reserved */
+#define	PCI_SUB_VID	0x2c	/* 16 bit	Subsystem Vendor ID */
+#define	PCI_SUB_ID	0x2e	/* 16 bit	Subsystem ID */
+#define	PCI_BASE_ROM	0x30	/* 32 bit	Expansion ROM Base Address */
+/* Byte 34..33:	Reserved */
+#define PCI_CAP_PTR	0x34	/*  8 bit (ML)	Capabilities Ptr */
+/* Byte 35..3b:	Reserved */
+#define	PCI_IRQ_LINE	0x3c	/*  8 bit	Interrupt Line */
+#define	PCI_IRQ_PIN	0x3d	/*  8 bit	Interrupt Pin */
+#define	PCI_MIN_GNT	0x3e	/*  8 bit	Min_Gnt */
+#define	PCI_MAX_LAT	0x3f	/*  8 bit	Max_Lat */
+/* Device Dependent Region */
+#define	PCI_OUR_REG	0x40	/* 32 bit (DV)	Our Register */
+#define	PCI_OUR_REG_1	0x40	/* 32 bit (ML)	Our Register 1 */
+#define	PCI_OUR_REG_2	0x44	/* 32 bit (ML)	Our Register 2 */
+/* Power Management Region */
+#define PCI_PM_CAP_ID	0x48	/*  8 bit (ML)	Power Management Cap. ID */
+#define PCI_PM_NITEM	0x49	/*  8 bit (ML)	Next Item Ptr */
+#define PCI_PM_CAP_REG	0x4a	/* 16 bit (ML)	Power Management Capabilities */
+#define PCI_PM_CTL_STS	0x4c	/* 16 bit (ML)	Power Manag. Control/Status */
+/* Byte 0x4e:	Reserved */
+#define PCI_PM_DAT_REG	0x4f	/*  8 bit (ML)	Power Manag. Data Register */
+/* VPD Region */
+#define	PCI_VPD_CAP_ID	0x50	/*  8 bit (ML)	VPD Cap. ID */
+#define PCI_VPD_NITEM	0x51	/*  8 bit (ML)	Next Item Ptr */
+#define PCI_VPD_ADR_REG	0x52	/* 16 bit (ML)	VPD Address Register */
+#define PCI_VPD_DAT_REG	0x54	/* 32 bit (ML)	VPD Data Register */
+/* Byte 58..ff:	Reserved */
+
+/*
+ * I2C Address (PCI Config)
+ *
+ * Note: The temperature and voltage sensors are relocated on a different
+ *	 I2C bus.
+ */
+#define I2C_ADDR_VPD	0xA0	/* I2C address for the VPD EEPROM */ 
+
+/*
+ * Define Bits and Values of the registers
+ */
+/*	PCI_VENDOR_ID	16 bit	Vendor ID */
+/*	PCI_DEVICE_ID	16 bit	Device ID */
+/* Values for Vendor ID and Device ID shall be patched into the code */
+/*	PCI_COMMAND	16 bit	Command */
+#define	PCI_FBTEN	0x0200	/* Bit 9:	Fast Back-To-Back enable */
+#define	PCI_SERREN	0x0100	/* Bit 8:	SERR enable */
+#define	PCI_ADSTEP	0x0080	/* Bit 7:	Address Stepping */
+#define	PCI_PERREN	0x0040	/* Bit 6:	Parity Report Response enable */
+#define	PCI_VGA_SNOOP	0x0020	/* Bit 5:	VGA palette snoop */
+#define	PCI_MWIEN	0x0010	/* Bit 4:	Memory write an inv cycl ena */
+#define	PCI_SCYCEN	0x0008	/* Bit 3:	Special Cycle enable */
+#define	PCI_BMEN	0x0004	/* Bit 2:	Bus Master enable */
+#define	PCI_MEMEN	0x0002	/* Bit 1:	Memory Space Access enable */
+#define	PCI_IOEN	0x0001	/* Bit 0:	IO Space Access enable */
+
+/*	PCI_STATUS	16 bit	Status */
+#define	PCI_PERR	0x8000	/* Bit 15:	Parity Error */
+#define	PCI_SERR	0x4000	/* Bit 14:	Signaled SERR */
+#define	PCI_RMABORT	0x2000	/* Bit 13:	Received Master Abort */
+#define	PCI_RTABORT	0x1000	/* Bit 12:	Received Target Abort */
+#define	PCI_STABORT	0x0800	/* Bit 11:	Sent Target Abort */
+#define	PCI_DEVSEL	0x0600	/* Bit 10..9:	DEVSEL Timing */
+#define	PCI_DEV_FAST	(0<<9)	/*		fast */
+#define	PCI_DEV_MEDIUM	(1<<9)	/*		medium */
+#define	PCI_DEV_SLOW	(2<<9)	/*		slow */
+#define	PCI_DATAPERR	0x0100	/* Bit 8:	DATA Parity error detected */
+#define	PCI_FB2BCAP	0x0080	/* Bit 7:	Fast Back-to-Back Capability */
+#define	PCI_UDF		0x0040	/* Bit 6:	User Defined Features */
+#define PCI_66MHZCAP	0x0020	/* Bit 5:	66 MHz PCI bus clock capable */
+#define PCI_NEWCAP	0x0010	/* Bit 4:	New cap. list implemented */
+
+#define PCI_ERRBITS	(PCI_PERR|PCI_SERR|PCI_RMABORT|PCI_STABORT|PCI_DATAPERR)
+
+/*	PCI_REV_ID	8 bit	Revision ID */
+/*	PCI_CLASS_CODE	24 bit	Class Code */
+/*	Byte 2:		Base Class		(02) */
+/*	Byte 1:		SubClass		(02) */
+/*	Byte 0:		Programming Interface	(00) */
+
+/*	PCI_CACHE_LSZ	8 bit	Cache Line Size */
+/*	Possible values: 0,2,4,8,16	*/
+
+/*	PCI_LAT_TIM	8 bit	Latency Timer */
+
+/*	PCI_HEADER_T	8 bit	Header Type */
+#define	PCI_HD_MF_DEV	0x80	/* Bit 7:	0= single, 1= multi-func dev */
+#define	PCI_HD_TYPE	0x7f	/* Bit 6..0:	Header Layout 0= normal */
+
+/*	PCI_BIST	8 bit	Built-in selftest */
+#define	PCI_BIST_CAP	0x80	/* Bit 7:	BIST Capable */
+#define	PCI_BIST_ST	0x40	/* Bit 6:	Start BIST */
+#define	PCI_BIST_RET	0x0f	/* Bit 3..0:	Completion Code */
+
+/*	PCI_BASE_1ST	32 bit	1st Base address */
+#define	PCI_MEMSIZE	0x800L       /* use 2 kB Memory Base */
+#define	PCI_MEMBASE_BITS 0xfffff800L /* Bit 31..11:	Memory Base Address */
+#define	PCI_MEMSIZE_BIIS 0x000007f0L /* Bit 10..4:	Memory Size Req. */
+#define	PCI_PREFEN	0x00000008L  /* Bit 3:		Prefetchable */
+#define	PCI_MEM_TYP	0x00000006L  /* Bit 2..1:	Memory Type */
+#define	PCI_MEM32BIT	(0<<1)	     /* Base addr anywhere in 32 Bit range */
+#define	PCI_MEM1M	(1<<1)	     /* Base addr below 1 MegaByte */
+#define	PCI_MEM64BIT	(2<<1)	     /* Base addr anywhere in 64 Bit range */
+#define	PCI_MEMSPACE	0x00000001L  /* Bit 0:	Memory Space Indic. */
+
+/*	PCI_BASE_2ND	32 bit	2nd Base address */
+#define	PCI_IOBASE	0xffffff00L  /* Bit 31..8:  I/O Base address */
+#define	PCI_IOSIZE	0x000000fcL  /* Bit 7..2:   I/O Size Requirements */
+#define	PCI_IOSPACE	0x00000001L  /* Bit 0:	    I/O Space Indicator */
+
+/*	PCI_SUB_VID	16 bit	Subsystem Vendor ID */
+/*	PCI_SUB_ID	16 bit	Subsystem ID */
+
+/*	PCI_BASE_ROM	32 bit	Expansion ROM Base Address */
+#define	PCI_ROMBASE	0xfffe0000L  /* Bit 31..17: ROM BASE addres (1st) */
+#define	PCI_ROMBASZ	0x0001c000L  /* Bit 16..14: Treat as BASE or SIZE */
+#define	PCI_ROMSIZE	0x00003800L  /* Bit 13..11: ROM Size Requirements */
+#define	PCI_ROMEN	0x00000001L  /* Bit 0:	    Address Decode enable */
+
+/*	PCI_CAP_PTR	8 bit	New Capabilities Pointers */
+/*	PCI_IRQ_LINE	8 bit	Interrupt Line */
+/*	PCI_IRQ_PIN	8 bit	Interrupt Pin */
+/*	PCI_MIN_GNT	8 bit	Min_Gnt */
+/*	PCI_MAX_LAT	8 bit	Max_Lat */
+/* Device Dependent Region */
+/*	PCI_OUR_REG	(DV)	32 bit	Our Register */
+/*	PCI_OUR_REG_1	(ML)	32 bit	Our Register 1 */
+				  /*	 Bit 31..29:	reserved */
+#define	PCI_PATCH_DIR	(3L<<27)  /*(DV) Bit 28..27:	Ext Patchs direction */
+#define PCI_PATCH_DIR_0	(1L<<27)  /*(DV) Type of the pins EXT_PATCHS<1..0>   */
+#define PCI_PATCH_DIR_1 (1L<<28)  /*	   0 = input			     */
+				  /*	   1 = output			     */
+#define	PCI_EXT_PATCHS	(3L<<25)  /*(DV) Bit 26..25:	Extended Patches     */
+#define PCI_EXT_PATCH_0 (1L<<25)  /*(DV)				     */
+#define PCI_EXT_PATCH_1 (1L<<26)  /*	 CLK for MicroWire (ML)		     */
+#define PCI_VIO		(1L<<25)  /*(ML)				     */
+#define	PCI_EN_BOOT	(1L<<24)  /*	 Bit 24:	Enable BOOT via ROM  */
+				  /*	   1 = Don't boot with ROM	     */
+				  /*	   0 = Boot with ROM		     */
+#define	PCI_EN_IO	(1L<<23)  /*	 Bit 23:	Mapping to IO space  */
+#define	PCI_EN_FPROM	(1L<<22)  /*	 Bit 22:	FLASH mapped to mem? */
+				  /*	   1 = Map Flash to Memory	     */
+			  	  /*	   0 = Disable all addr. decoding    */
+#define	PCI_PAGESIZE	(3L<<20)  /*	 Bit 21..20:	FLASH Page Size	     */
+#define	PCI_PAGE_16	(0L<<20)  /*		16 k pages		     */
+#define	PCI_PAGE_32K	(1L<<20)  /*		32 k pages		     */
+#define	PCI_PAGE_64K	(2L<<20)  /*		64 k pages		     */
+#define	PCI_PAGE_128K	(3L<<20)  /*		128 k pages		     */
+				  /*	 Bit 19: reserved (ML) and (DV)	     */
+#define	PCI_PAGEREG	(7L<<16)  /*	 Bit 18..16:	Page Register	     */
+				  /*	 Bit 15:	reserved	     */
+#define	PCI_FORCE_BE	(1L<<14)  /*	 Bit 14:	Assert all BEs on MR */
+#define	PCI_DIS_MRL	(1L<<13)  /*	 Bit 13:	Disable Mem R Line   */
+#define	PCI_DIS_MRM	(1L<<12)  /*	 Bit 12:	Disable Mem R multip */
+#define	PCI_DIS_MWI	(1L<<11)  /*	 Bit 11:	Disable Mem W & inv  */
+#define	PCI_DISC_CLS	(1L<<10)  /*	 Bit 10:	Disc: cacheLsz bound */
+#define	PCI_BURST_DIS	(1L<<9)	  /*	 Bit  9:	Burst Disable	     */
+#define	PCI_BYTE_SWAP	(1L<<8)	  /*(DV) Bit  8:	Byte Swap in DATA    */
+#define	PCI_SKEW_DAS	(0xfL<<4) /*	 Bit 7..4:	Skew Ctrl, DAS Ext   */
+#define	PCI_SKEW_BASE	(0xfL<<0) /*	 Bit 3..0:	Skew Ctrl, Base	     */
+
+/*	PCI_OUR_REG_2	(ML)	32 bit	Our Register 2 (Monalisa only) */
+#define PCI_VPD_WR_TH	(0xffL<<24)	/* Bit 24..31	VPD Write Threshold  */
+#define	PCI_DEV_SEL	(0x7fL<<17)	/* Bit 17..23	EEPROM Device Select */
+#define	PCI_VPD_ROM_SZ	(7L<<14)	/* Bit 14..16	VPD ROM Size	     */
+					/* Bit 12..13	reserved	     */
+#define	PCI_PATCH_DIR2	(0xfL<<8)	/* Bit  8..11	Ext Patchs dir 2..5  */
+#define	PCI_PATCH_DIR_2	(1L<<8)		/* Bit  8	CS for MicroWire     */
+#define	PCI_PATCH_DIR_3	(1L<<9)
+#define	PCI_PATCH_DIR_4	(1L<<10)
+#define	PCI_PATCH_DIR_5	(1L<<11)
+#define PCI_EXT_PATCHS2 (0xfL<<4)	/* Bit  4..7	Extended Patches     */
+#define	PCI_EXT_PATCH_2	(1L<<4)		/* Bit  4	CS for MicroWire     */
+#define	PCI_EXT_PATCH_3	(1L<<5)
+#define	PCI_EXT_PATCH_4	(1L<<6)
+#define	PCI_EXT_PATCH_5	(1L<<7)
+#define	PCI_EN_DUMMY_RD	(1L<<3)		/* Bit  3	Enable Dummy Read    */
+#define PCI_REV_DESC	(1L<<2)		/* Bit  2	Reverse Desc. Bytes  */
+#define PCI_USEADDR64	(1L<<1)		/* Bit  1	Use 64 Bit Addresse  */
+#define PCI_USEDATA64	(1L<<0)		/* Bit  0	Use 64 Bit Data bus ext*/
+
+/* Power Management Region */
+/*	PCI_PM_CAP_ID		 8 bit (ML)	Power Management Cap. ID */
+/*	PCI_PM_NITEM		 8 bit (ML)	Next Item Ptr */
+/*	PCI_PM_CAP_REG		16 bit (ML)	Power Management Capabilities*/
+#define	PCI_PME_SUP	(0x1f<<11)	/* Bit 11..15	PM Manag. Event Support*/
+#define PCI_PM_D2_SUB	(1<<10)		/* Bit 10	D2 Support Bit	     */
+#define PCI_PM_D1_SUB	(1<<9)		/* Bit 9	D1 Support Bit       */
+					/* Bit 6..8 reserved		     */
+#define PCI_PM_DSI	(1<<5)		/* Bit 5	Device Specific Init.*/
+#define PCI_PM_APS	(1<<4)		/* Bit 4	Auxialiary Power Src */
+#define PCI_PME_CLOCK	(1<<3)		/* Bit 3	PM Event Clock       */
+#define PCI_PM_VER	(7<<0)		/* Bit 0..2	PM PCI Spec. version */
+
+/*	PCI_PM_CTL_STS		16 bit (ML)	Power Manag. Control/Status  */
+#define	PCI_PME_STATUS	(1<<15)		/* Bit 15 	PFA doesn't sup. PME#*/
+#define PCI_PM_DAT_SCL	(3<<13)		/* Bit 13..14	dat reg Scaling factor */
+#define PCI_PM_DAT_SEL	(0xf<<9)	/* Bit  9..12	PM data selector field */
+					/* Bit  7.. 2	reserved	     */
+#define PCI_PM_STATE	(3<<0)		/* Bit  0.. 1	Power Management State */
+#define PCI_PM_STATE_D0	(0<<0)		/* D0:	Operational (default) */
+#define	PCI_PM_STATE_D1	(1<<0)		/* D1:	not supported */
+#define PCI_PM_STATE_D2	(2<<0)		/* D2:	not supported */
+#define PCI_PM_STATE_D3 (3<<0)		/* D3:	HOT, Power Down and Reset */
+
+/*	PCI_PM_DAT_REG		 8 bit (ML)	Power Manag. Data Register */
+/* VPD Region */
+/*	PCI_VPD_CAP_ID		 8 bit (ML)	VPD Cap. ID */
+/*	PCI_VPD_NITEM		 8 bit (ML)	Next Item Ptr */
+/*	PCI_VPD_ADR_REG		16 bit (ML)	VPD Address Register */
+#define	PCI_VPD_FLAG	(1<<15)		/* Bit 15	starts VPD rd/wd cycle*/
+#define PCI_VPD_ADDR	(0x3fff<<0)	/* Bit  0..14	VPD address */
+
+/*	PCI_VPD_DAT_REG		32 bit (ML)	VPD Data Register */
+
+/*
+ *	Control Register File:
+ *	Bank 0
+ */
+#define	B0_RAP		0x0000	/*  8 bit register address port */
+	/* 0x0001 - 0x0003:	reserved */
+#define	B0_CTRL		0x0004	/*  8 bit control register */
+#define	B0_DAS		0x0005	/*  8 Bit control register (DAS) */
+#define	B0_LED		0x0006	/*  8 Bit LED register */
+#define	B0_TST_CTRL	0x0007	/*  8 bit test control register */
+#define	B0_ISRC		0x0008	/* 32 bit Interrupt source register */
+#define	B0_IMSK		0x000c	/* 32 bit Interrupt mask register */
+
+/* 0x0010 - 0x006b:	formac+ (supernet_3) fequently used registers */
+#define B0_CMDREG1	0x0010	/* write command reg 1 instruction */
+#define B0_CMDREG2	0x0014	/* write command reg 2 instruction */
+#define B0_ST1U		0x0010	/* read upper 16-bit of status reg 1 */
+#define B0_ST1L		0x0014	/* read lower 16-bit of status reg 1 */
+#define B0_ST2U		0x0018	/* read upper 16-bit of status reg 2 */
+#define B0_ST2L		0x001c	/* read lower 16-bit of status reg 2 */
+
+#define B0_MARR		0x0020	/* r/w the memory read addr register */
+#define B0_MARW		0x0024	/* r/w the memory write addr register*/
+#define B0_MDRU		0x0028	/* r/w upper 16-bit of mem. data reg */
+#define B0_MDRL		0x002c	/* r/w lower 16-bit of mem. data reg */
+
+#define	B0_MDREG3	0x0030	/* r/w Mode Register 3 */
+#define	B0_ST3U		0x0034	/* read upper 16-bit of status reg 3 */
+#define	B0_ST3L		0x0038	/* read lower 16-bit of status reg 3 */
+#define	B0_IMSK3U	0x003c	/* r/w upper 16-bit of IMSK reg 3 */
+#define	B0_IMSK3L	0x0040	/* r/w lower 16-bit of IMSK reg 3 */
+#define	B0_IVR		0x0044	/* read Interrupt Vector register */
+#define	B0_IMR		0x0048	/* r/w Interrupt mask register */
+/* 0x4c	Hidden */
+
+#define B0_CNTRL_A	0x0050	/* control register A (r/w) */
+#define B0_CNTRL_B	0x0054	/* control register B (r/w) */
+#define B0_INTR_MASK	0x0058	/* interrupt mask (r/w) */
+#define B0_XMIT_VECTOR	0x005c	/* transmit vector register (r/w) */
+
+#define B0_STATUS_A	0x0060	/* status register A (read only) */
+#define B0_STATUS_B	0x0064	/* status register B (read only) */
+#define B0_CNTRL_C	0x0068	/* control register C (r/w) */
+#define	B0_MDREG1	0x006c	/* r/w Mode Register 1 */
+
+#define	B0_R1_CSR	0x0070	/* 32 bit BMU control/status reg (rec q 1) */
+#define	B0_R2_CSR	0x0074	/* 32 bit BMU control/status reg (rec q 2)(DV)*/
+#define	B0_XA_CSR	0x0078	/* 32 bit BMU control/status reg (a xmit q) */
+#define	B0_XS_CSR	0x007c	/* 32 bit BMU control/status reg (s xmit q) */
+
+/*
+ *	Bank 1
+ *	- completely empty (this is the RAP Block window)
+ *	Note: if RAP = 1 this page is reserved
+ */
+
+/*
+ *	Bank 2
+ */
+#define	B2_MAC_0	0x0100	/*  8 bit MAC address Byte 0 */
+#define	B2_MAC_1	0x0101	/*  8 bit MAC address Byte 1 */
+#define	B2_MAC_2	0x0102	/*  8 bit MAC address Byte 2 */
+#define	B2_MAC_3	0x0103	/*  8 bit MAC address Byte 3 */
+#define	B2_MAC_4	0x0104	/*  8 bit MAC address Byte 4 */
+#define	B2_MAC_5	0x0105	/*  8 bit MAC address Byte 5 */
+#define	B2_MAC_6	0x0106	/*  8 bit MAC address Byte 6 (== 0) (DV) */
+#define	B2_MAC_7	0x0107	/*  8 bit MAC address Byte 7 (== 0) (DV) */
+
+#define B2_CONN_TYP	0x0108	/*  8 bit Connector type */
+#define B2_PMD_TYP	0x0109	/*  8 bit PMD type */
+				/* 0x010a - 0x010b:	reserved */
+	/* Eprom registers are currently of no use */
+#define B2_E_0		0x010c	/*  8 bit EPROM Byte 0 */
+#define B2_E_1		0x010d	/*  8 bit EPROM Byte 1 */
+#define B2_E_2		0x010e	/*  8 bit EPROM Byte 2 */
+#define B2_E_3		0x010f	/*  8 bit EPROM Byte 3 */
+#define B2_FAR		0x0110	/* 32 bit Flash-Prom Address Register/Counter */
+#define B2_FDP		0x0114	/*  8 bit Flash-Prom Data Port */
+				/* 0x0115 - 0x0117:	reserved */
+#define B2_LD_CRTL	0x0118	/*  8 bit loader control */
+#define B2_LD_TEST	0x0119	/*  8 bit loader test */
+				/* 0x011a - 0x011f:	reserved */
+#define B2_TI_INI	0x0120	/* 32 bit Timer init value */
+#define B2_TI_VAL	0x0124	/* 32 bit Timer value */
+#define B2_TI_CRTL	0x0128	/*  8 bit Timer control */
+#define B2_TI_TEST	0x0129	/*  8 Bit Timer Test */
+				/* 0x012a - 0x012f:	reserved */
+#define B2_WDOG_INI	0x0130	/* 32 bit Watchdog init value */
+#define B2_WDOG_VAL	0x0134	/* 32 bit Watchdog value */
+#define B2_WDOG_CRTL	0x0138	/*  8 bit Watchdog control */
+#define B2_WDOG_TEST	0x0139	/*  8 Bit Watchdog Test */
+				/* 0x013a - 0x013f:	reserved */
+#define B2_RTM_INI	0x0140	/* 32 bit RTM init value */
+#define B2_RTM_VAL	0x0144	/* 32 bit RTM value */
+#define B2_RTM_CRTL	0x0148	/*  8 bit RTM control */
+#define B2_RTM_TEST	0x0149	/*  8 Bit RTM Test */
+
+#define B2_TOK_COUNT	0x014c	/* (ML)	32 bit	Token Counter */
+#define B2_DESC_ADDR_H	0x0150	/* (ML) 32 bit	Desciptor Base Addr Reg High */
+#define B2_CTRL_2	0x0154	/* (ML)	 8 bit	Control Register 2 */
+#define B2_IFACE_REG	0x0155	/* (ML)	 8 bit	Interface Register */
+				/* 0x0156:		reserved */
+#define B2_TST_CTRL_2	0x0157	/* (ML)  8 bit	Test Control Register 2 */
+#define B2_I2C_CTRL	0x0158	/* (ML)	32 bit	I2C Control Register */
+#define B2_I2C_DATA	0x015c	/* (ML) 32 bit	I2C Data Register */
+
+#define B2_IRQ_MOD_INI	0x0160	/* (ML) 32 bit	IRQ Moderation Timer Init Reg. */
+#define B2_IRQ_MOD_VAL	0x0164	/* (ML)	32 bit	IRQ Moderation Timer Value */
+#define B2_IRQ_MOD_CTRL	0x0168	/* (ML)  8 bit	IRQ Moderation Timer Control */
+#define B2_IRQ_MOD_TEST	0x0169	/* (ML)	 8 bit	IRQ Moderation Timer Test */
+				/* 0x016a - 0x017f:	reserved */
+
+/*
+ *	Bank 3
+ */
+/*
+ * This is a copy of the Configuration register file (lower half)
+ */
+#define B3_CFG_SPC	0x180
+
+/*
+ *	Bank 4
+ */
+#define B4_R1_D		0x0200	/* 	4*32 bit current receive Descriptor  */
+#define B4_R1_DA	0x0210	/* 	32 bit current rec desc address	     */
+#define B4_R1_AC	0x0214	/* 	32 bit current receive Address Count */
+#define B4_R1_BC	0x0218	/*	32 bit current receive Byte Counter  */
+#define B4_R1_CSR	0x021c	/* 	32 bit BMU Control/Status Register   */
+#define B4_R1_F		0x0220	/* 	32 bit flag register		     */
+#define B4_R1_T1	0x0224	/* 	32 bit Test Register 1		     */
+#define B4_R1_T1_TR	0x0224	/* 	8 bit Test Register 1 TR	     */
+#define B4_R1_T1_WR	0x0225	/* 	8 bit Test Register 1 WR	     */
+#define B4_R1_T1_RD	0x0226	/* 	8 bit Test Register 1 RD	     */
+#define B4_R1_T1_SV	0x0227	/* 	8 bit Test Register 1 SV	     */
+#define B4_R1_T2	0x0228	/* 	32 bit Test Register 2		     */
+#define B4_R1_T3	0x022c	/* 	32 bit Test Register 3		     */
+#define B4_R1_DA_H	0x0230	/* (ML)	32 bit Curr Rx Desc Address High     */
+#define B4_R1_AC_H	0x0234	/* (ML)	32 bit Curr Addr Counter High dword  */
+				/* 0x0238 - 0x023f:	reserved	  */
+				/* Receive queue 2 is removed on Monalisa */
+#define B4_R2_D		0x0240	/* 4*32 bit current receive Descriptor	(q2) */
+#define B4_R2_DA	0x0250	/* 32 bit current rec desc address	(q2) */
+#define B4_R2_AC	0x0254	/* 32 bit current receive Address Count	(q2) */
+#define B4_R2_BC	0x0258	/* 32 bit current receive Byte Counter	(q2) */
+#define B4_R2_CSR	0x025c	/* 32 bit BMU Control/Status Register	(q2) */
+#define B4_R2_F		0x0260	/* 32 bit flag register			(q2) */
+#define B4_R2_T1	0x0264	/* 32 bit Test Register 1		(q2) */
+#define B4_R2_T1_TR	0x0264	/* 8 bit Test Register 1 TR		(q2) */
+#define B4_R2_T1_WR	0x0265	/* 8 bit Test Register 1 WR		(q2) */
+#define B4_R2_T1_RD	0x0266	/* 8 bit Test Register 1 RD		(q2) */
+#define B4_R2_T1_SV	0x0267	/* 8 bit Test Register 1 SV		(q2) */
+#define B4_R2_T2	0x0268	/* 32 bit Test Register 2		(q2) */
+#define B4_R2_T3	0x026c	/* 32 bit Test Register 3		(q2) */
+				/* 0x0270 - 0x027c:	reserved */
+
+/*
+ *	Bank 5
+ */
+#define B5_XA_D		0x0280	/* 4*32 bit current transmit Descriptor	(xa) */
+#define B5_XA_DA	0x0290	/* 32 bit current tx desc address	(xa) */
+#define B5_XA_AC	0x0294	/* 32 bit current tx Address Count	(xa) */
+#define B5_XA_BC	0x0298	/* 32 bit current tx Byte Counter	(xa) */
+#define B5_XA_CSR	0x029c	/* 32 bit BMU Control/Status Register	(xa) */
+#define B5_XA_F		0x02a0	/* 32 bit flag register			(xa) */
+#define B5_XA_T1	0x02a4	/* 32 bit Test Register 1		(xa) */
+#define B5_XA_T1_TR	0x02a4	/* 8 bit Test Register 1 TR		(xa) */
+#define B5_XA_T1_WR	0x02a5	/* 8 bit Test Register 1 WR		(xa) */
+#define B5_XA_T1_RD	0x02a6	/* 8 bit Test Register 1 RD		(xa) */
+#define B5_XA_T1_SV	0x02a7	/* 8 bit Test Register 1 SV		(xa) */
+#define B5_XA_T2	0x02a8	/* 32 bit Test Register 2		(xa) */
+#define B5_XA_T3	0x02ac	/* 32 bit Test Register 3		(xa) */
+#define B5_XA_DA_H	0x02b0	/* (ML)	32 bit Curr Tx Desc Address High     */
+#define B5_XA_AC_H	0x02b4	/* (ML)	32 bit Curr Addr Counter High dword  */
+				/* 0x02b8 - 0x02bc:	reserved */
+#define B5_XS_D		0x02c0	/* 4*32 bit current transmit Descriptor	(xs) */
+#define B5_XS_DA	0x02d0	/* 32 bit current tx desc address	(xs) */
+#define B5_XS_AC	0x02d4	/* 32 bit current transmit Address Count(xs) */
+#define B5_XS_BC	0x02d8	/* 32 bit current transmit Byte Counter	(xs) */
+#define B5_XS_CSR	0x02dc	/* 32 bit BMU Control/Status Register	(xs) */
+#define B5_XS_F		0x02e0	/* 32 bit flag register			(xs) */
+#define B5_XS_T1	0x02e4	/* 32 bit Test Register 1		(xs) */
+#define B5_XS_T1_TR	0x02e4	/* 8 bit Test Register 1 TR		(xs) */
+#define B5_XS_T1_WR	0x02e5	/* 8 bit Test Register 1 WR		(xs) */
+#define B5_XS_T1_RD	0x02e6	/* 8 bit Test Register 1 RD		(xs) */
+#define B5_XS_T1_SV	0x02e7	/* 8 bit Test Register 1 SV		(xs) */
+#define B5_XS_T2	0x02e8	/* 32 bit Test Register 2		(xs) */
+#define B5_XS_T3	0x02ec	/* 32 bit Test Register 3		(xs) */
+#define B5_XS_DA_H	0x02f0	/* (ML)	32 bit Curr Tx Desc Address High     */
+#define B5_XS_AC_H	0x02f4	/* (ML)	32 bit Curr Addr Counter High dword  */
+				/* 0x02f8 - 0x02fc:	reserved */
+
+/*
+ *	Bank 6
+ */
+/* External PLC-S registers (SN2 compatibility for DV) */
+/* External registers (ML) */
+#define B6_EXT_REG	0x300
+
+/*
+ *	Bank 7
+ */
+/* DAS PLC-S Registers */
+
+/*
+ *	Bank 8 - 15
+ */
+/* IFCP registers */
+
+/*---------------------------------------------------------------------------*/
+/* Definitions of the Bits in the registers */
+
+/*	B0_RAP		16 bit register address port */
+#define	RAP_RAP		0x0f	/* Bit 3..0:	0 = block0, .., f = block15 */
+
+/*	B0_CTRL		8 bit control register */
+#define CTRL_FDDI_CLR	(1<<7)	/* Bit 7: (ML)	Clear FDDI Reset */
+#define CTRL_FDDI_SET	(1<<6)	/* Bit 6: (ML)	Set FDDI Reset */
+#define	CTRL_HPI_CLR	(1<<5)	/* Bit 5:	Clear HPI SM reset */
+#define	CTRL_HPI_SET	(1<<4)	/* Bit 4:	Set HPI SM reset */
+#define	CTRL_MRST_CLR	(1<<3)	/* Bit 3:	Clear Master reset */
+#define	CTRL_MRST_SET	(1<<2)	/* Bit 2:	Set Master reset */
+#define	CTRL_RST_CLR	(1<<1)	/* Bit 1:	Clear Software reset */
+#define	CTRL_RST_SET	(1<<0)	/* Bit 0:	Set Software reset */
+
+/*	B0_DAS		8 Bit control register (DAS) */
+#define BUS_CLOCK	(1<<7)	/* Bit 7: (ML)	Bus Clock 0/1 = 33/66MHz */
+#define BUS_SLOT_SZ	(1<<6)	/* Bit 6: (ML)	Slot Size 0/1 = 32/64 bit slot*/
+				/* Bit 5..4:	reserved */
+#define	DAS_AVAIL	(1<<3)	/* Bit 3:	1 = DAS, 0 = SAS */
+#define DAS_BYP_ST	(1<<2)	/* Bit 2:	1 = avail,SAS, 0 = not avail */
+#define DAS_BYP_INS	(1<<1)	/* Bit 1:	1 = insert Bypass */
+#define DAS_BYP_RMV	(1<<0)	/* Bit 0:	1 = remove Bypass */
+
+/*	B0_LED		8 Bit LED register */
+				/* Bit 7..6:	reserved */
+#define LED_2_ON	(1<<5)	/* Bit 5:	1 = switch LED_2 on (left,gn)*/
+#define LED_2_OFF	(1<<4)	/* Bit 4:	1 = switch LED_2 off */
+#define LED_1_ON	(1<<3)	/* Bit 3:	1 = switch LED_1 on (mid,yel)*/
+#define LED_1_OFF	(1<<2)	/* Bit 2:	1 = switch LED_1 off */
+#define LED_0_ON	(1<<1)	/* Bit 1:	1 = switch LED_0 on (rght,gn)*/
+#define LED_0_OFF	(1<<0)	/* Bit 0:	1 = switch LED_0 off */
+/* This hardware defines are very ugly therefore we define some others */
+
+#define LED_GA_ON	LED_2_ON	/* S port = A port */
+#define LED_GA_OFF	LED_2_OFF	/* S port = A port */
+#define LED_MY_ON	LED_1_ON
+#define LED_MY_OFF	LED_1_OFF
+#define LED_GB_ON	LED_0_ON
+#define LED_GB_OFF	LED_0_OFF
+
+/*	B0_TST_CTRL	8 bit test control register */
+#define	TST_FRC_DPERR_MR	(1<<7)	/* Bit 7:  force DATAPERR on MST RE. */
+#define	TST_FRC_DPERR_MW	(1<<6)	/* Bit 6:  force DATAPERR on MST WR. */
+#define	TST_FRC_DPERR_TR	(1<<5)	/* Bit 5:  force DATAPERR on TRG RE. */
+#define	TST_FRC_DPERR_TW	(1<<4)	/* Bit 4:  force DATAPERR on TRG WR. */
+#define	TST_FRC_APERR_M		(1<<3)	/* Bit 3:  force ADDRPERR on MST     */
+#define	TST_FRC_APERR_T		(1<<2)	/* Bit 2:  force ADDRPERR on TRG     */
+#define	TST_CFG_WRITE_ON	(1<<1)	/* Bit 1:  ena configuration reg. WR */
+#define	TST_CFG_WRITE_OFF	(1<<0)	/* Bit 0:  dis configuration reg. WR */
+
+/*	B0_ISRC		32 bit Interrupt source register */
+					/* Bit 31..28:	reserved	     */
+#define IS_I2C_READY	(1L<<27)	/* Bit 27: (ML)	IRQ on end of I2C tx */
+#define IS_IRQ_SW	(1L<<26)	/* Bit 26: (ML)	SW forced IRQ	     */
+#define IS_EXT_REG	(1L<<25)	/* Bit 25: (ML) IRQ from external reg*/
+#define	IS_IRQ_STAT	(1L<<24)	/* Bit 24:	IRQ status execption */
+					/*   PERR, RMABORT, RTABORT DATAPERR */
+#define	IS_IRQ_MST_ERR	(1L<<23)	/* Bit 23:	IRQ master error     */
+					/*   RMABORT, RTABORT, DATAPERR	     */
+#define	IS_TIMINT	(1L<<22)	/* Bit 22:	IRQ_TIMER	*/
+#define	IS_TOKEN	(1L<<21)	/* Bit 21:	IRQ_RTM		*/
+/*
+ * Note: The DAS is our First Port (!=PA)
+ */
+#define	IS_PLINT1	(1L<<20)	/* Bit 20:	IRQ_PHY_DAS	*/
+#define	IS_PLINT2	(1L<<19)	/* Bit 19:	IRQ_IFCP_4	*/
+#define	IS_MINTR3	(1L<<18)	/* Bit 18:	IRQ_IFCP_3/IRQ_PHY */
+#define	IS_MINTR2	(1L<<17)	/* Bit 17:	IRQ_IFCP_2/IRQ_MAC_2 */
+#define	IS_MINTR1	(1L<<16)	/* Bit 16:	IRQ_IFCP_1/IRQ_MAC_1 */
+/* Receive Queue 1 */
+#define	IS_R1_P		(1L<<15)	/* Bit 15:	Parity Error (q1) */
+#define	IS_R1_B		(1L<<14)	/* Bit 14:	End of Buffer (q1) */
+#define	IS_R1_F		(1L<<13)	/* Bit 13:	End of Frame (q1) */
+#define	IS_R1_C		(1L<<12)	/* Bit 12:	Encoding Error (q1) */
+/* Receive Queue 2 */
+#define	IS_R2_P		(1L<<11)	/* Bit 11: (DV)	Parity Error (q2) */
+#define	IS_R2_B		(1L<<10)	/* Bit 10: (DV)	End of Buffer (q2) */
+#define	IS_R2_F		(1L<<9)		/* Bit	9: (DV)	End of Frame (q2) */
+#define	IS_R2_C		(1L<<8)		/* Bit	8: (DV)	Encoding Error (q2) */
+/* Asynchronous Transmit queue */
+					/* Bit  7:	reserved */
+#define	IS_XA_B		(1L<<6)		/* Bit	6:	End of Buffer (xa) */
+#define	IS_XA_F		(1L<<5)		/* Bit	5:	End of Frame (xa) */
+#define	IS_XA_C		(1L<<4)		/* Bit	4:	Encoding Error (xa) */
+/* Synchronous Transmit queue */
+					/* Bit  3:	reserved */
+#define	IS_XS_B		(1L<<2)		/* Bit	2:	End of Buffer (xs) */
+#define	IS_XS_F		(1L<<1)		/* Bit	1:	End of Frame (xs) */
+#define	IS_XS_C		(1L<<0)		/* Bit	0:	Encoding Error (xs) */
+
+/*
+ * Define all valid interrupt source Bits from GET_ISR ()
+ */
+#define	ALL_IRSR	0x01ffff77L	/* (DV) */
+#define	ALL_IRSR_ML	0x0ffff077L	/* (ML) */
+
+
+/*	B0_IMSK		32 bit Interrupt mask register */
+/*
+ * The Bit definnition of this register are the same as of the interrupt
+ * source register. These definition are directly derived from the Hardware
+ * spec.
+ */
+					/* Bit 31..28:	reserved	     */
+#define IRQ_I2C_READY	(1L<<27)	/* Bit 27: (ML)	IRQ on end of I2C tx */
+#define IRQ_SW		(1L<<26)	/* Bit 26: (ML)	SW forced IRQ	     */
+#define IRQ_EXT_REG	(1L<<25)	/* Bit 25: (ML) IRQ from external reg*/
+#define	IRQ_STAT	(1L<<24)	/* Bit 24:	IRQ status execption */
+					/*   PERR, RMABORT, RTABORT DATAPERR */
+#define	IRQ_MST_ERR	(1L<<23)	/* Bit 23:	IRQ master error     */
+					/*   RMABORT, RTABORT, DATAPERR	     */
+#define	IRQ_TIMER	(1L<<22)	/* Bit 22:	IRQ_TIMER	*/
+#define	IRQ_RTM		(1L<<21)	/* Bit 21:	IRQ_RTM		*/
+#define	IRQ_DAS		(1L<<20)	/* Bit 20:	IRQ_PHY_DAS	*/
+#define	IRQ_IFCP_4	(1L<<19)	/* Bit 19:	IRQ_IFCP_4	*/
+#define	IRQ_IFCP_3	(1L<<18)	/* Bit 18:	IRQ_IFCP_3/IRQ_PHY */
+#define	IRQ_IFCP_2	(1L<<17)	/* Bit 17:	IRQ_IFCP_2/IRQ_MAC_2 */
+#define	IRQ_IFCP_1	(1L<<16)	/* Bit 16:	IRQ_IFCP_1/IRQ_MAC_1 */
+/* Receive Queue 1 */
+#define	IRQ_R1_P	(1L<<15)	/* Bit 15:	Parity Error (q1) */
+#define	IRQ_R1_B	(1L<<14)	/* Bit 14:	End of Buffer (q1) */
+#define	IRQ_R1_F	(1L<<13)	/* Bit 13:	End of Frame (q1) */
+#define	IRQ_R1_C	(1L<<12)	/* Bit 12:	Encoding Error (q1) */
+/* Receive Queue 2 */
+#define	IRQ_R2_P	(1L<<11)	/* Bit 11: (DV)	Parity Error (q2) */
+#define	IRQ_R2_B	(1L<<10)	/* Bit 10: (DV)	End of Buffer (q2) */
+#define	IRQ_R2_F	(1L<<9)		/* Bit	9: (DV)	End of Frame (q2) */
+#define	IRQ_R2_C	(1L<<8)		/* Bit	8: (DV)	Encoding Error (q2) */
+/* Asynchronous Transmit queue */
+					/* Bit  7:	reserved */
+#define	IRQ_XA_B	(1L<<6)		/* Bit	6:	End of Buffer (xa) */
+#define	IRQ_XA_F	(1L<<5)		/* Bit	5:	End of Frame (xa) */
+#define	IRQ_XA_C	(1L<<4)		/* Bit	4:	Encoding Error (xa) */
+/* Synchronous Transmit queue */
+					/* Bit  3:	reserved */
+#define	IRQ_XS_B	(1L<<2)		/* Bit	2:	End of Buffer (xs) */
+#define	IRQ_XS_F	(1L<<1)		/* Bit	1:	End of Frame (xs) */
+#define	IRQ_XS_C	(1L<<0)		/* Bit	0:	Encoding Error (xs) */
+
+/* 0x0010 - 0x006b:	formac+ (supernet_3) fequently used registers */
+/*	B0_R1_CSR	32 bit BMU control/status reg (rec q 1 ) */
+/*	B0_R2_CSR	32 bit BMU control/status reg (rec q 2 ) */
+/*	B0_XA_CSR	32 bit BMU control/status reg (a xmit q ) */
+/*	B0_XS_CSR	32 bit BMU control/status reg (s xmit q ) */
+/* The registers are the same as B4_R1_CSR, B4_R2_CSR, B5_Xa_CSR, B5_XS_CSR */
+
+/*	B2_MAC_0	8 bit MAC address Byte 0 */
+/*	B2_MAC_1	8 bit MAC address Byte 1 */
+/*	B2_MAC_2	8 bit MAC address Byte 2 */
+/*	B2_MAC_3	8 bit MAC address Byte 3 */
+/*	B2_MAC_4	8 bit MAC address Byte 4 */
+/*	B2_MAC_5	8 bit MAC address Byte 5 */
+/*	B2_MAC_6	8 bit MAC address Byte 6 (== 0) (DV) */
+/*	B2_MAC_7	8 bit MAC address Byte 7 (== 0) (DV) */
+
+/*	B2_CONN_TYP	8 bit Connector type */
+/*	B2_PMD_TYP	8 bit PMD type */
+/*	Values of connector and PMD type comply to SysKonnect internal std */
+
+/*	The EPROM register are currently of no use */
+/*	B2_E_0		8 bit EPROM Byte 0 */
+/*	B2_E_1		8 bit EPROM Byte 1 */
+/*	B2_E_2		8 bit EPROM Byte 2 */
+/*	B2_E_3		8 bit EPROM Byte 3 */
+
+/*	B2_FAR		32 bit Flash-Prom Address Register/Counter */
+#define	FAR_ADDR	0x1ffffL	/* Bit 16..0:	FPROM Address mask */
+
+/*	B2_FDP		8 bit Flash-Prom Data Port */
+
+/*	B2_LD_CRTL	8 bit loader control */
+/*	Bits are currently reserved */
+
+/*	B2_LD_TEST	8 bit loader test */
+#define	LD_T_ON		(1<<3)	/* Bit 3:    Loader Testmode on */
+#define	LD_T_OFF	(1<<2)	/* Bit 2:    Loader Testmode off */
+#define	LD_T_STEP	(1<<1)	/* Bit 1:    Decrement FPROM addr. Counter */
+#define	LD_START	(1<<0)	/* Bit 0:    Start loading FPROM */
+
+/*	B2_TI_INI	32 bit Timer init value */
+/*	B2_TI_VAL	32 bit Timer value */
+/*	B2_TI_CRTL	8 bit Timer control */
+/*	B2_TI_TEST	8 Bit Timer Test */
+/*	B2_WDOG_INI	32 bit Watchdog init value */
+/*	B2_WDOG_VAL	32 bit Watchdog value */
+/*	B2_WDOG_CRTL	8 bit Watchdog control */
+/*	B2_WDOG_TEST	8 Bit Watchdog Test */
+/*	B2_RTM_INI	32 bit RTM init value */
+/*	B2_RTM_VAL	32 bit RTM value */
+/*	B2_RTM_CRTL	8 bit RTM control */
+/*	B2_RTM_TEST	8 Bit RTM Test */
+/*	B2_<TIM>_CRTL	8 bit <TIM> control */
+/*	B2_IRQ_MOD_INI	32 bit IRQ Moderation Timer Init Reg.	(ML) */
+/*	B2_IRQ_MOD_VAL	32 bit IRQ Moderation Timer Value	(ML) */
+/*	B2_IRQ_MOD_CTRL	8 bit IRQ Moderation Timer Control	(ML) */
+/*	B2_IRQ_MOD_TEST	8 bit IRQ Moderation Timer Test		(ML) */
+#define GET_TOK_CT	(1<<4)	/* Bit 4: Get the Token Counter (RTM) */
+#define TIM_RES_TOK	(1<<3)	/* Bit 3: RTM Status: 1 == restricted */
+#define TIM_ALARM	(1<<3)	/* Bit 3: Timer Alarm (WDOG) */
+#define TIM_START	(1<<2)	/* Bit 2: Start Timer (TI,WDOG,RTM,IRQ_MOD)*/
+#define TIM_STOP	(1<<1)	/* Bit 1: Stop Timer (TI,WDOG,RTM,IRQ_MOD) */
+#define TIM_CL_IRQ	(1<<0)	/* Bit 0: Clear Timer IRQ (TI,WDOG,RTM) */
+/*	B2_<TIM>_TEST	8 Bit <TIM> Test */
+#define	TIM_T_ON	(1<<2)	/* Bit 2: Test mode on (TI,WDOG,RTM,IRQ_MOD) */
+#define	TIM_T_OFF	(1<<1)	/* Bit 1: Test mode off (TI,WDOG,RTM,IRQ_MOD) */
+#define	TIM_T_STEP	(1<<0)	/* Bit 0: Test step (TI,WDOG,RTM,IRQ_MOD) */
+
+/*	B2_TOK_COUNT	0x014c	(ML)	32 bit	Token Counter */
+/*	B2_DESC_ADDR_H	0x0150	(ML)	32 bit	Desciptor Base Addr Reg High */
+/*	B2_CTRL_2	0x0154	(ML)	 8 bit	Control Register 2 */
+				/* Bit 7..5:	reserved		*/
+#define CTRL_CL_I2C_IRQ (1<<4)	/* Bit 4:	Clear I2C IRQ		*/
+#define CTRL_ST_SW_IRQ	(1<<3)	/* Bit 3:	Set IRQ SW Request	*/
+#define CTRL_CL_SW_IRQ	(1<<2)	/* Bit 2:	Clear IRQ SW Request	*/
+#define CTRL_STOP_DONE	(1<<1)	/* Bit 1:	Stop Master is finished */
+#define	CTRL_STOP_MAST	(1<<0)	/* Bit 0:	Command Bit to stop the master*/
+
+/*	B2_IFACE_REG	0x0155	(ML)	 8 bit	Interface Register */
+				/* Bit 7..3:	reserved		*/
+#define	IF_I2C_DATA_DIR	(1<<2)	/* Bit 2:	direction of IF_I2C_DATA*/
+#define IF_I2C_DATA	(1<<1)	/* Bit 1:	I2C Data Port		*/
+#define	IF_I2C_CLK	(1<<0)	/* Bit 0:	I2C Clock Port		*/
+
+				/* 0x0156:		reserved */
+/*	B2_TST_CTRL_2	0x0157	(ML)	 8 bit	Test Control Register 2 */
+					/* Bit 7..4:	reserved */
+					/* force the following error on */
+					/* the next master read/write	*/
+#define TST_FRC_DPERR_MR64	(1<<3)	/* Bit 3:	DataPERR RD 64	*/
+#define TST_FRC_DPERR_MW64	(1<<2)	/* Bit 2:	DataPERR WR 64	*/
+#define TST_FRC_APERR_1M64	(1<<1)	/* Bit 1:	AddrPERR on 1. phase */
+#define TST_FRC_APERR_2M64	(1<<0)	/* Bit 0:	AddrPERR on 2. phase */
+
+/*	B2_I2C_CTRL	0x0158	(ML)	32 bit	I2C Control Register	       */
+#define	I2C_FLAG	(1L<<31)	/* Bit 31:	Start read/write if WR */
+#define I2C_ADDR	(0x7fffL<<16)	/* Bit 30..16:	Addr to be read/written*/
+#define	I2C_DEV_SEL	(0x7fL<<9)	/* Bit  9..15:	I2C Device Select      */
+					/* Bit  5.. 8:	reserved	       */
+#define I2C_BURST_LEN	(1L<<4)		/* Bit  4	Burst Len, 1/4 bytes   */
+#define I2C_DEV_SIZE	(7L<<1)		/* Bit	1.. 3:	I2C Device Size	       */
+#define I2C_025K_DEV	(0L<<1)		/*		0: 256 Bytes or smaller*/
+#define I2C_05K_DEV	(1L<<1)		/* 		1: 512	Bytes	       */
+#define	I2C_1K_DEV	(2L<<1)		/*		2: 1024 Bytes	       */
+#define I2C_2K_DEV	(3L<<1)		/*		3: 2048	Bytes	       */
+#define	I2C_4K_DEV	(4L<<1)		/*		4: 4096 Bytes	       */
+#define	I2C_8K_DEV	(5L<<1)		/*		5: 8192 Bytes	       */
+#define	I2C_16K_DEV	(6L<<1)		/*		6: 16384 Bytes	       */
+#define	I2C_32K_DEV	(7L<<1)		/*		7: 32768 Bytes	       */
+#define I2C_STOP_BIT	(1<<0)		/* Bit  0:	Interrupt I2C transfer */
+
+/*
+ * I2C Addresses
+ *
+ * The temperature sensor and the voltage sensor are on the same I2C bus.
+ * Note: The voltage sensor (Micorwire) will be selected by PCI_EXT_PATCH_1
+ *	 in PCI_OUR_REG 1.
+ */
+#define	I2C_ADDR_TEMP	0x90	/* I2C Address Temperature Sensor */
+
+/*	B2_I2C_DATA	0x015c	(ML)	32 bit	I2C Data Register */
+
+/*	B4_R1_D		4*32 bit current receive Descriptor	(q1) */
+/*	B4_R1_DA	32 bit current rec desc address		(q1) */
+/*	B4_R1_AC	32 bit current receive Address Count	(q1) */
+/*	B4_R1_BC	32 bit current receive Byte Counter	(q1) */
+/*	B4_R1_CSR	32 bit BMU Control/Status Register	(q1) */
+/*	B4_R1_F		32 bit flag register			(q1) */
+/*	B4_R1_T1	32 bit Test Register 1		 	(q1) */
+/*	B4_R1_T2	32 bit Test Register 2		 	(q1) */
+/*	B4_R1_T3	32 bit Test Register 3		 	(q1) */
+/*	B4_R2_D		4*32 bit current receive Descriptor	(q2) */
+/*	B4_R2_DA	32 bit current rec desc address		(q2) */
+/*	B4_R2_AC	32 bit current receive Address Count	(q2) */
+/*	B4_R2_BC	32 bit current receive Byte Counter	(q2) */
+/*	B4_R2_CSR	32 bit BMU Control/Status Register	(q2) */
+/*	B4_R2_F		32 bit flag register			(q2) */
+/*	B4_R2_T1	32 bit Test Register 1			(q2) */
+/*	B4_R2_T2	32 bit Test Register 2			(q2) */
+/*	B4_R2_T3	32 bit Test Register 3			(q2) */
+/*	B5_XA_D		4*32 bit current receive Descriptor	(xa) */
+/*	B5_XA_DA	32 bit current rec desc address		(xa) */
+/*	B5_XA_AC	32 bit current receive Address Count	(xa) */
+/*	B5_XA_BC	32 bit current receive Byte Counter	(xa) */
+/*	B5_XA_CSR	32 bit BMU Control/Status Register	(xa) */
+/*	B5_XA_F		32 bit flag register			(xa) */
+/*	B5_XA_T1	32 bit Test Register 1			(xa) */
+/*	B5_XA_T2	32 bit Test Register 2			(xa) */
+/*	B5_XA_T3	32 bit Test Register 3			(xa) */
+/*	B5_XS_D		4*32 bit current receive Descriptor	(xs) */
+/*	B5_XS_DA	32 bit current rec desc address		(xs) */
+/*	B5_XS_AC	32 bit current receive Address Count	(xs) */
+/*	B5_XS_BC	32 bit current receive Byte Counter	(xs) */
+/*	B5_XS_CSR	32 bit BMU Control/Status Register	(xs) */
+/*	B5_XS_F		32 bit flag register			(xs) */
+/*	B5_XS_T1	32 bit Test Register 1			(xs) */
+/*	B5_XS_T2	32 bit Test Register 2			(xs) */
+/*	B5_XS_T3	32 bit Test Register 3			(xs) */
+/*	B5_<xx>_CSR	32 bit BMU Control/Status Register	(xx) */
+#define	CSR_DESC_CLEAR	(1L<<21)    /* Bit 21:	Clear Reset for Descr */
+#define	CSR_DESC_SET	(1L<<20)    /* Bit 20:	Set Reset for Descr */
+#define	CSR_FIFO_CLEAR	(1L<<19)    /* Bit 19:	Clear Reset for FIFO */
+#define	CSR_FIFO_SET	(1L<<18)    /* Bit 18:	Set Reset for FIFO */
+#define	CSR_HPI_RUN	(1L<<17)    /* Bit 17:	Release HPI SM */
+#define	CSR_HPI_RST	(1L<<16)    /* Bit 16:	Reset HPI SM to Idle */
+#define	CSR_SV_RUN	(1L<<15)    /* Bit 15:	Release Supervisor SM */
+#define	CSR_SV_RST	(1L<<14)    /* Bit 14:	Reset Supervisor SM */
+#define	CSR_DREAD_RUN	(1L<<13)    /* Bit 13:	Release Descr Read SM */
+#define	CSR_DREAD_RST	(1L<<12)    /* Bit 12:	Reset Descr Read SM */
+#define	CSR_DWRITE_RUN	(1L<<11)    /* Bit 11:	Rel. Descr Write SM */
+#define	CSR_DWRITE_RST	(1L<<10)    /* Bit 10:	Reset Descr Write SM */
+#define	CSR_TRANS_RUN	(1L<<9)     /* Bit 9:	Release Transfer SM */
+#define	CSR_TRANS_RST	(1L<<8)     /* Bit 8:	Reset Transfer SM */
+				    /* Bit 7..5: reserved */
+#define	CSR_START	(1L<<4)     /* Bit 4:	Start Rec/Xmit Queue */
+#define	CSR_IRQ_CL_P	(1L<<3)     /* Bit 3:	Clear Parity IRQ, Rcv */
+#define	CSR_IRQ_CL_B	(1L<<2)     /* Bit 2:	Clear EOB IRQ */
+#define	CSR_IRQ_CL_F	(1L<<1)     /* Bit 1:	Clear EOF IRQ */
+#define	CSR_IRQ_CL_C	(1L<<0)     /* Bit 0:	Clear ERR IRQ */
+
+#define CSR_SET_RESET	(CSR_DESC_SET|CSR_FIFO_SET|CSR_HPI_RST|CSR_SV_RST|\
+			CSR_DREAD_RST|CSR_DWRITE_RST|CSR_TRANS_RST)
+#define CSR_CLR_RESET	(CSR_DESC_CLEAR|CSR_FIFO_CLEAR|CSR_HPI_RUN|CSR_SV_RUN|\
+			CSR_DREAD_RUN|CSR_DWRITE_RUN|CSR_TRANS_RUN)
+
+
+/*	B5_<xx>_F	32 bit flag register		 (xx) */
+					/* Bit 28..31:	reserved	      */
+#define F_ALM_FULL	(1L<<27)	/* Bit 27: (ML)	FIFO almost full      */
+#define F_FIFO_EOF	(1L<<26)	/* Bit 26: (ML)	Fag bit in FIFO       */
+#define F_WM_REACHED	(1L<<25)	/* Bit 25: (ML)	Watermark reached     */
+#define F_UP_DW_USED	(1L<<24)	/* Bit 24: (ML) Upper Dword used (bug)*/
+					/* Bit 23: 	reserved	      */
+#define F_FIFO_LEVEL	(0x1fL<<16)	/* Bit 16..22:(ML) # of Qwords in FIFO*/
+					/* Bit  8..15: 	reserved	      */
+#define F_ML_WATER_M	0x0000ffL	/* Bit  0.. 7:(ML) Watermark	      */
+#define	FLAG_WATER	0x00001fL	/* Bit 4..0:(DV) Level of req data tr.*/
+
+/*	B5_<xx>_T1	32 bit Test Register 1		 (xx) */
+/*		Holds four State Machine control Bytes */
+#define	SM_CRTL_SV	(0xffL<<24) /* Bit 31..24:  Control Supervisor SM */
+#define	SM_CRTL_RD	(0xffL<<16) /* Bit 23..16:  Control Read Desc SM */
+#define	SM_CRTL_WR	(0xffL<<8)  /* Bit 15..8:   Control Write Desc SM */
+#define	SM_CRTL_TR	(0xffL<<0)  /* Bit 7..0:    Control Transfer SM */
+
+/*	B4_<xx>_T1_TR	8 bit Test Register 1 TR		(xx) */
+/*	B4_<xx>_T1_WR	8 bit Test Register 1 WR		(xx) */
+/*	B4_<xx>_T1_RD	8 bit Test Register 1 RD		(xx) */
+/*	B4_<xx>_T1_SV	8 bit Test Register 1 SV		(xx) */
+/* The control status byte of each machine looks like ... */
+#define	SM_STATE	0xf0	/* Bit 7..4:	State which shall be loaded */
+#define	SM_LOAD		0x08	/* Bit 3:	Load the SM with SM_STATE */
+#define	SM_TEST_ON	0x04	/* Bit 2:	Switch on SM Test Mode */
+#define	SM_TEST_OFF	0x02	/* Bit 1:	Go off the Test Mode */
+#define	SM_STEP		0x01	/* Bit 0:	Step the State Machine */
+
+/* The coding of the states */
+#define	SM_SV_IDLE	0x0	/* Supervisor	Idle		Tr/Re	     */
+#define	SM_SV_RES_START	0x1	/* Supervisor	Res_Start	Tr/Re	     */
+#define	SM_SV_GET_DESC	0x3	/* Supervisor	Get_Desc	Tr/Re	     */
+#define	SM_SV_CHECK	0x2	/* Supervisor	Check		Tr/Re	     */
+#define	SM_SV_MOV_DATA	0x6	/* Supervisor	Move_Data	Tr/Re	     */
+#define	SM_SV_PUT_DESC	0x7	/* Supervisor	Put_Desc	Tr/Re	     */
+#define	SM_SV_SET_IRQ	0x5	/* Supervisor	Set_Irq		Tr/Re	     */
+
+#define	SM_RD_IDLE	0x0	/* Read Desc.	Idle		Tr/Re	     */
+#define	SM_RD_LOAD	0x1	/* Read Desc.	Load		Tr/Re	     */
+#define	SM_RD_WAIT_TC	0x3	/* Read Desc.	Wait_TC		Tr/Re	     */
+#define	SM_RD_RST_EOF	0x6	/* Read Desc.	Reset_EOF	   Re	     */
+#define	SM_RD_WDONE_R	0x2	/* Read Desc.	Wait_Done	   Re	     */
+#define	SM_RD_WDONE_T	0x4	/* Read Desc.	Wait_Done	Tr   	     */
+
+#define	SM_TR_IDLE	0x0	/* Trans. Data	Idle		Tr/Re	     */
+#define	SM_TR_LOAD	0x3	/* Trans. Data	Load		Tr/Re	     */
+#define	SM_TR_LOAD_R_ML	0x1	/* Trans. Data	Load		  /Re	(ML) */
+#define	SM_TR_WAIT_TC	0x2	/* Trans. Data	Wait_TC		Tr/Re	     */
+#define	SM_TR_WDONE	0x4	/* Trans. Data	Wait_Done	Tr/Re	     */
+
+#define	SM_WR_IDLE	0x0	/* Write Desc.	Idle		Tr/Re	     */
+#define	SM_WR_ABLEN	0x1	/* Write Desc.	Act_Buf_Length	Tr/Re	     */
+#define	SM_WR_LD_A4	0x2	/* Write Desc.	Load_A4		   Re	     */
+#define	SM_WR_RES_OWN	0x2	/* Write Desc.	Res_OWN		Tr   	     */
+#define	SM_WR_WAIT_EOF	0x3	/* Write Desc.	Wait_EOF	   Re	     */
+#define	SM_WR_LD_N2C_R	0x4	/* Write Desc.	Load_N2C	   Re	     */
+#define	SM_WR_WAIT_TC_R	0x5	/* Write Desc.	Wait_TC		   Re	     */
+#define	SM_WR_WAIT_TC4	0x6	/* Write Desc.	Wait_TC4	   Re	     */
+#define	SM_WR_LD_A_T	0x6	/* Write Desc.	Load_A		Tr   	     */
+#define	SM_WR_LD_A_R	0x7	/* Write Desc.	Load_A		   Re	     */
+#define	SM_WR_WAIT_TC_T	0x7	/* Write Desc.	Wait_TC		Tr   	     */
+#define	SM_WR_LD_N2C_T	0xc	/* Write Desc.	Load_N2C	Tr   	     */
+#define	SM_WR_WDONE_T	0x9	/* Write Desc.	Wait_Done	Tr   	     */
+#define	SM_WR_WDONE_R	0xc	/* Write Desc.	Wait_Done	   Re	     */
+#define SM_WR_LD_D_AD	0xe	/* Write Desc.  Load_Dumr_A	   Re	(ML) */
+#define SM_WR_WAIT_D_TC	0xf	/* Write Desc.	Wait_Dumr_TC	   Re	(ML) */
+
+/*	B5_<xx>_T2	32 bit Test Register 2		 (xx) */
+/* Note: This register is only defined for the transmit queues */
+				/* Bit 31..8:	reserved */
+#define	AC_TEST_ON	(1<<7)	/* Bit 7:	Address Counter Test Mode on */
+#define	AC_TEST_OFF	(1<<6)	/* Bit 6:	Address Counter Test Mode off*/
+#define	BC_TEST_ON	(1<<5)	/* Bit 5:	Byte Counter Test Mode on */
+#define	BC_TEST_OFF	(1<<4)	/* Bit 4:	Byte Counter Test Mode off */
+#define	TEST_STEP04	(1<<3)	/* Bit 3:	Inc AC/Dec BC by 4 */
+#define	TEST_STEP03	(1<<2)	/* Bit 2:	Inc AC/Dec BC by 3 */
+#define	TEST_STEP02	(1<<1)	/* Bit 1:	Inc AC/Dec BC by 2 */
+#define	TEST_STEP01	(1<<0)	/* Bit 0:	Inc AC/Dec BC by 1 */
+
+/*	B5_<xx>_T3	32 bit Test Register 3		 (xx) */
+/* Note: This register is only defined for the transmit queues */
+				/* Bit 31..8:	reserved */
+#define T3_MUX_2	(1<<7)	/* Bit 7: (ML)	Mux position MSB */
+#define T3_VRAM_2	(1<<6)	/* Bit 6: (ML)	Virtual RAM buffer addr MSB */
+#define	T3_LOOP		(1<<5)	/* Bit 5: 	Set Loopback (Xmit) */
+#define	T3_UNLOOP	(1<<4)	/* Bit 4: 	Unset Loopback (Xmit) */
+#define	T3_MUX		(3<<2)	/* Bit 3..2:	Mux position */
+#define	T3_VRAM		(3<<0)	/* Bit 1..0:	Virtual RAM buffer Address */
+
+/* PCI card IDs */
+/*
+ * Note: The following 4 byte definitions shall not be used! Use OEM Concept!
+ */
+#define	PCI_VEND_ID0	0x48		/* PCI vendor ID (SysKonnect) */
+#define	PCI_VEND_ID1	0x11		/* PCI vendor ID (SysKonnect) */
+					/*		 (High byte) */
+#define	PCI_DEV_ID0	0x00		/* PCI device ID */
+#define	PCI_DEV_ID1	0x40		/* PCI device ID (High byte) */
+
+/*#define PCI_CLASS	0x02*/		/* PCI class code: network device */
+#define PCI_NW_CLASS	0x02		/* PCI class code: network device */
+#define PCI_SUB_CLASS	0x02		/* PCI subclass ID: FDDI device */
+#define PCI_PROG_INTFC	0x00		/* PCI programming Interface (=0) */
+
+/*
+ * address transmision from logical to physical offset address on board
+ */
+#define	FMA(a)	(0x0400|((a)<<2))	/* FORMAC+ (r/w) (SN3) */
+#define	P1(a)	(0x0380|((a)<<2))	/* PLC1 (r/w) (DAS) */
+#define	P2(a)	(0x0600|((a)<<2))	/* PLC2 (r/w) (covered by the SN3) */
+#define PRA(a)	(B2_MAC_0 + (a))	/* configuration PROM (MAC address) */
+
+/*
+ * FlashProm specification
+ */
+#define	MAX_PAGES	0x20000L	/* Every byte has a single page */
+#define	MAX_FADDR	1		/* 1 byte per page */
+
+/*
+ * Receive / Transmit Buffer Control word
+ */
+#define	BMU_OWN		(1UL<<31)	/* OWN bit: 0 == host, 1 == adapter */
+#define	BMU_STF		(1L<<30)	/* Start of Frame ?		*/
+#define	BMU_EOF		(1L<<29)	/* End of Frame ?		*/
+#define	BMU_EN_IRQ_EOB	(1L<<28)	/* Enable "End of Buffer" IRQ	*/
+#define	BMU_EN_IRQ_EOF	(1L<<27)	/* Enable "End of Frame" IRQ	*/
+#define	BMU_DEV_0	(1L<<26)	/* RX: don't transfer to system mem */
+#define BMU_SMT_TX	(1L<<25)	/* TX: if set, buffer type SMT_MBuf */
+#define BMU_ST_BUF	(1L<<25)	/* RX: copy of start of frame */
+#define BMU_UNUSED	(1L<<24)	/* Set if the Descr is curr unused */
+#define BMU_SW		(3L<<24)	/* 2 Bits reserved for SW usage */
+#define	BMU_CHECK	0x00550000L	/* To identify the control word */
+#define	BMU_BBC		0x0000FFFFL	/* R/T Buffer Byte Count        */
+
+/*
+ * physical address offset + IO-Port base address
+ */
+#ifdef MEM_MAPPED_IO
+#define	ADDR(a)		(char far *) smc->hw.iop+(a)
+#define	ADDRS(smc,a)	(char far *) (smc)->hw.iop+(a)
+#else
+#define	ADDR(a)	(((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), \
+	(smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \
+	(smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
+#define	ADDRS(smc,a) (((a)>>7) ? (outp((smc)->hw.iop+B0_RAP,(a)>>7), \
+	((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0)))) : \
+	((smc)->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
+#endif
+
+/*
+ * Define a macro to access the configuration space
+ */
+#define PCI_C(a)	ADDR(B3_CFG_SPC + (a))	/* PCI Config Space */
+
+#define EXT_R(a)	ADDR(B6_EXT_REG + (a))	/* External Registers */
+
+/*
+ * Define some values needed for the MAC address (PROM)
+ */
+#define	SA_MAC		(0)	/* start addr. MAC_AD within the PROM */
+#define	PRA_OFF		(0)	/* offset correction when 4th byte reading */
+
+#define	SKFDDI_PSZ	8	/* address PROM size */
+
+#define	FM_A(a)	ADDR(FMA(a))	/* FORMAC Plus physical addr */
+#define	P1_A(a)	ADDR(P1(a))	/* PLC1 (r/w) */
+#define	P2_A(a)	ADDR(P2(a))	/* PLC2 (r/w) (DAS) */
+#define PR_A(a)	ADDR(PRA(a))	/* config. PROM (MAC address) */
+
+/*
+ * Macro to read the PROM
+ */
+#define	READ_PROM(a)	((u_char)inp(a))
+
+#define	GET_PAGE(bank)	outpd(ADDR(B2_FAR),bank)
+#define	VPP_ON()
+#define	VPP_OFF()
+
+/*
+ * Note: Values of the Interrupt Source Register are defined above
+ */
+#define ISR_A		ADDR(B0_ISRC)
+#define	GET_ISR()		inpd(ISR_A)
+#define GET_ISR_SMP(iop)	inpd((iop)+B0_ISRC)
+#define	CHECK_ISR()		(inpd(ISR_A) & inpd(ADDR(B0_IMSK)))
+#define CHECK_ISR_SMP(iop)	(inpd((iop)+B0_ISRC) & inpd((iop)+B0_IMSK))
+
+#define	BUS_CHECK()
+
+/*
+ * CLI_FBI:	Disable Board Interrupts
+ * STI_FBI:	Enable Board Interrupts
+ */
+#ifndef UNIX
+#define	CLI_FBI()	outpd(ADDR(B0_IMSK),0)
+#else
+#define	CLI_FBI(smc)	outpd(ADDRS((smc),B0_IMSK),0)
+#endif
+
+#ifndef UNIX
+#define	STI_FBI()	outpd(ADDR(B0_IMSK),smc->hw.is_imask)
+#else
+#define	STI_FBI(smc)	outpd(ADDRS((smc),B0_IMSK),(smc)->hw.is_imask)
+#endif
+
+#define CLI_FBI_SMP(iop)	outpd((iop)+B0_IMSK,0)
+#define	STI_FBI_SMP(smc,iop)	outpd((iop)+B0_IMSK,(smc)->hw.is_imask)
+
+#endif	/* PCI */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * 12 bit transfer (dword) counter:
+ *	(ISA:	2*trc = number of byte)
+ *	(EISA:	4*trc = number of byte)
+ *	(MCA:	4*trc = number of byte)
+ */
+#define	MAX_TRANS	(0x0fff)
+
+/*
+ * PC PIC
+ */
+#define	MST_8259 (0x20)
+#define	SLV_8259 (0xA0)
+
+#define TPS		(18)		/* ticks per second */
+
+/*
+ * error timer defs
+ */
+#define	TN		(4)	/* number of supported timer = TN+1 */
+#define	SNPPND_TIME	(5)	/* buffer memory access over mem. data reg. */
+
+#define	MAC_AD	0x405a0000
+
+#define MODR1	FM_A(FM_MDREG1)	/* mode register 1 */
+#define MODR2	FM_A(FM_MDREG2)	/* mode register 2 */
+
+#define CMDR1	FM_A(FM_CMDREG1)	/* command register 1 */
+#define CMDR2	FM_A(FM_CMDREG2)	/* command register 2 */
+
+
+/*
+ * function defines
+ */
+#define	CLEAR(io,mask)		outpw((io),inpw(io)&(~(mask)))
+#define	SET(io,mask)		outpw((io),inpw(io)|(mask))
+#define	GET(io,mask)		(inpw(io)&(mask))
+#define	SETMASK(io,val,mask)	outpw((io),(inpw(io) & ~(mask)) | (val))
+
+/*
+ * PHY Port A (PA) = PLC 1
+ * With SuperNet 3 PHY-A and PHY S are identical.
+ */
+#define	PLC(np,reg)	(((np) == PA) ? P2_A(reg) : P1_A(reg))
+
+/*
+ * set memory address register for write and read
+ */
+#define	MARW(ma)	outpw(FM_A(FM_MARW),(unsigned int)(ma))
+#define	MARR(ma)	outpw(FM_A(FM_MARR),(unsigned int)(ma))
+
+/*
+ * read/write from/to memory data register
+ */
+/* write double word */
+#define	MDRW(dd)	outpw(FM_A(FM_MDRU),(unsigned int)((dd)>>16)) ;\
+			outpw(FM_A(FM_MDRL),(unsigned int)(dd))
+
+#ifndef WINNT
+/* read double word */
+#define	MDRR()		(((long)inpw(FM_A(FM_MDRU))<<16) + inpw(FM_A(FM_MDRL)))
+
+/* read FORMAC+ 32-bit status register */
+#define	GET_ST1()	(((long)inpw(FM_A(FM_ST1U))<<16) + inpw(FM_A(FM_ST1L)))
+#define	GET_ST2()	(((long)inpw(FM_A(FM_ST2U))<<16) + inpw(FM_A(FM_ST2L)))
+#ifdef	SUPERNET_3
+#define	GET_ST3()	(((long)inpw(FM_A(FM_ST3U))<<16) + inpw(FM_A(FM_ST3L)))
+#endif
+#else
+/* read double word */
+#define MDRR()		inp2w((FM_A(FM_MDRU)),(FM_A(FM_MDRL)))
+
+/* read FORMAC+ 32-bit status register */
+#define GET_ST1()	inp2w((FM_A(FM_ST1U)),(FM_A(FM_ST1L)))
+#define GET_ST2()	inp2w((FM_A(FM_ST2U)),(FM_A(FM_ST2L)))
+#ifdef	SUPERNET_3
+#define GET_ST3()	inp2w((FM_A(FM_ST3U)),(FM_A(FM_ST3L)))
+#endif
+#endif
+
+/* Special timer macro for 82c54 */
+				/* timer access over data bus bit 8..15 */
+#define	OUT_82c54_TIMER(port,val)	outpw(TI_A(port),(val)<<8)
+#define	IN_82c54_TIMER(port)		((inpw(TI_A(port))>>8) & 0xff)
+
+
+#ifdef	DEBUG
+#define	DB_MAC(mac,st) {if (debug_mac & 0x1)\
+				printf("M") ;\
+			if (debug_mac & 0x2)\
+				printf("\tMAC %d status 0x%08lx\n",mac,st) ;\
+			if (debug_mac & 0x4)\
+				dp_mac(mac,st) ;\
+}
+
+#define	DB_PLC(p,iev) {	if (debug_plc & 0x1)\
+				printf("P") ;\
+			if (debug_plc & 0x2)\
+				printf("\tPLC %s Int 0x%04x\n", \
+					(p == PA) ? "A" : "B", iev) ;\
+			if (debug_plc & 0x4)\
+				dp_plc(p,iev) ;\
+}
+
+#define	DB_TIMER() {	if (debug_timer & 0x1)\
+				printf("T") ;\
+			if (debug_timer & 0x2)\
+				printf("\tTimer ISR\n") ;\
+}
+
+#else	/* no DEBUG */
+
+#define	DB_MAC(mac,st)
+#define	DB_PLC(p,iev)
+#define	DB_TIMER()
+
+#endif	/* no DEBUG */
+
+#define	INC_PTR(sp,cp,ep)	if (++cp == ep) cp = sp
+/*
+ * timer defs
+ */
+#define	COUNT(t)	((t)<<6)	/* counter */
+#define	RW_OP(o)	((o)<<4)	/* read/write operation */
+#define	TMODE(m)	((m)<<1)	/* timer mode */
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/skfbiinc.h linux.18p8/drivers/net/skfp/h/skfbiinc.h
--- linux.vanilla/drivers/net/skfp/h/skfbiinc.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/skfbiinc.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,123 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_SKFBIINC_
+#define _SKFBIINC_
+
+#include "h/supern_2.h"
+
+/*
+ * special defines for use into .asm files
+ */
+#define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1)
+
+#ifdef	ISA
+#define DMA_BUSY_CHECK	CSRA
+#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT)
+#define	HRQR		(RQAA+(RQ_RRQ<<1))
+#define	HRQW		(RQAA+(RQ_WA2<<1))
+#define	HRQA0		(RQAA+(RQ_WA0<<1))
+#define HRQSQ		(RQAA+(RQ_WSQ<<1))
+#endif
+
+#ifdef	EISA
+#define	DMA_BUSY_CHECK	CSRA
+#define DMA_HIGH_WORD	0x0400
+#define DMA_MASK_M	0x0a
+#define DMA_MODE_M	0x0b
+#define DMA_BYTE_PTR_M	0x0c
+#define DMA_MASK_S	0x0d4
+#define DMA_MODE_S	0x0d6
+#define DMA_BYTE_PTR_S	0x0d8
+#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC)
+#endif	/* EISA */
+
+#ifdef	MCA
+#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
+			 IS_CHCK_L | IS_BUSERR)
+#endif
+
+#ifdef PCI
+#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
+			 IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
+			 IS_R1_C | IS_XA_C | IS_XS_C)
+#endif
+
+#ifdef	PCI
+#define	ISR_MASK	(IS_MINTR1 | IS_R1_F | IS_XS_F| IS_XA_F | IMASK_FAST)
+#else
+#define	ISR_MASK	(IS_MINTR1 | IS_MINTR2 | IMASK_FAST)
+#endif
+
+#define	FMA_FM_CMDREG1	FMA(FM_CMDREG1)
+#define	FMA_FM_CMDREG2	FMA(FM_CMDREG2)
+#define	FMA_FM_STMCHN	FMA(FM_STMCHN)
+#define	FMA_FM_RPR	FMA(FM_RPR)
+#define	FMA_FM_WPXA0	FMA(FM_WPXA0)
+#define	FMA_FM_WPXA2	FMA(FM_WPXA2)
+#define	FMA_FM_MARR	FMA(FM_MARR)
+#define	FMA_FM_MARW	FMA(FM_MARW)
+#define	FMA_FM_MDRU	FMA(FM_MDRU)
+#define	FMA_FM_MDRL	FMA(FM_MDRL)
+#define	FMA_ST1L	FMA(FM_ST1L)
+#define	FMA_ST1U	FMA(FM_ST1U)
+#define	FMA_ST2L	FMA(FM_ST2L)
+#define	FMA_ST2U	FMA(FM_ST2U)
+#ifdef	SUPERNET_3
+#define FMA_ST3L	FMA(FM_ST3L)
+#define FMA_ST3U	FMA(FM_ST3U)
+#endif
+
+#define TMODE_RRQ	RQ_RRQ
+#define TMODE_WAQ2	RQ_WA2
+#define	HSRA		HSR(0)
+
+
+#define FMA_FM_ST1L	FMA_ST1L
+#define FMA_FM_ST1U	FMA_ST1U
+#define FMA_FM_ST2L	FMA_ST2L
+#define FMA_FM_ST2U	FMA_ST2U
+#ifdef	SUPERNET_3
+#define FMA_FM_ST3L	FMA_ST3L
+#define FMA_FM_ST3U	FMA_ST3U
+#endif
+
+#define FMA_FM_SWPR	FMA(FM_SWPR)
+
+#define FMA_FM_RPXA0	FMA(FM_RPXA0)
+
+#define	FMA_FM_RPXS	FMA(FM_RPXS)
+#define	FMA_FM_WPXS	FMA(FM_WPXS)
+
+#define	FMA_FM_IMSK1U	FMA(FM_IMSK1U)
+#define	FMA_FM_IMSK1L	FMA(FM_IMSK1L)
+
+#define	FMA_FM_EAS	FMA(FM_EAS)
+#define	FMA_FM_EAA0	FMA(FM_EAA0)
+
+#define	TMODE_WAQ0	RQ_WA0
+#define TMODE_WSQ	RQ_WSQ
+
+/* Define default for DRV_PCM_STATE_CHANGE */
+#ifndef	DRV_PCM_STATE_CHANGE
+#define	DRV_PCM_STATE_CHANGE(smc,plc,p_state)	/* nothing */
+#endif
+
+/* Define default for DRV_RMT_INDICATION */
+#ifndef	DRV_RMT_INDICATION
+#define	DRV_RMT_INDICATION(smc,i)	/* nothing */
+#endif
+
+#endif	/* n_SKFBIINC_ */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/smc.h linux.18p8/drivers/net/skfp/h/smc.h
--- linux.vanilla/drivers/net/skfp/h/smc.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/smc.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,471 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_SCMECM_
+#define _SCMECM_
+
+#if	defined(PCI) && !defined(OSDEF)
+/*
+ * In the case of the PCI bus the file osdef1st.h must be present
+ */
+#define	OSDEF
+#endif
+
+#ifdef	PCI
+#ifndef	SUPERNET_3
+#define	SUPERNET_3
+#endif
+#ifndef	TAG_MODE
+#define	TAG_MODE
+#endif
+#endif
+
+/*
+ * include all other files in required order
+ * the following files must have been included before:
+ *	types.h
+ *	fddi.h
+ */
+#ifdef	OSDEF
+#include "h/osdef1st.h"
+#endif	/* OSDEF */
+#ifdef	OEM_CONCEPT
+#include "oemdef.h"
+#endif	/* OEM_CONCEPT */
+#include "h/smt.h"
+#include "h/cmtdef.h"
+#include "h/fddimib.h"
+#include "h/targethw.h"		/* all target hw dependencies */
+#include "h/targetos.h"		/* all target os dependencies */
+#ifdef	ESS
+#include "h/sba.h"
+#endif
+
+/*
+ * Event Queue
+ *	queue.c
+ * events are class/value pairs
+ *	class	is addressee, e.g. RMT, PCM etc.
+ *	value	is command, e.g. line state change, ring op change etc.
+ */
+struct event_queue {
+	u_short	class ;			/* event class */
+	u_short	event ;			/* event value */
+} ;
+
+/*
+ * define event queue as circular buffer
+ */
+#ifdef	CONCENTRATOR
+#define MAX_EVENT	128
+#else	/* nCONCENTRATOR */
+#define MAX_EVENT	64
+#endif	/* nCONCENTRATOR */
+
+struct s_queue {
+
+	struct event_queue ev_queue[MAX_EVENT];
+	struct event_queue *ev_put ;
+	struct event_queue *ev_get ;
+} ;
+
+/*
+ * ECM - Entity Coordination Management
+ * ecm.c
+ */
+struct s_ecm {
+	u_char path_test ;		/* ECM path test variable */
+	u_char sb_flag ;		/* ECM stuck bypass */
+	u_char DisconnectFlag ;		/* jd 05-Aug-1999 Bug #10419 
+					 * ECM disconnected */
+	u_char ecm_line_state ;		/* flag to dispatcher : line states */
+	u_long trace_prop ;		/* ECM Trace_Prop flag >= 16 bits !! */
+	/* NUMPHYS note:
+	 * this variable must have enough bits to hold all entiies in
+	 * the station. So NUMPHYS may not be greater than 31.
+	 */
+	char	ec_pad[2] ;
+	struct smt_timer ecm_timer ;	/* timer */
+} ;
+
+
+/*
+ * RMT - Ring Management
+ * rmt.c
+ */
+struct s_rmt {
+	u_char dup_addr_test ;		/* state of dupl. addr. test */
+	u_char da_flag ;		/* flag : duplicate address det. */
+	u_char loop_avail ;		/* flag : MAC available for loopback */
+	u_char sm_ma_avail ;		/* flag : MAC available for SMT */
+	u_char no_flag ;		/* flag : ring not operational */
+	u_char bn_flag ;		/* flag : MAC reached beacon state */
+	u_char jm_flag ;		/* flag : jamming in NON_OP_DUP */
+	u_char rm_join ;		/* CFM flag RM_Join */
+	u_char rm_loop ;		/* CFM flag RM_Loop */
+
+	long fast_rm_join ;		/* bit mask of active ports */
+	/*
+	 * timer and flags
+	 */
+	struct smt_timer rmt_timer0 ;	/* timer 0 */
+	struct smt_timer rmt_timer1 ;	/* timer 1 */
+	struct smt_timer rmt_timer2 ;	/* timer 2 */
+	u_char timer0_exp ;		/* flag : timer 0 expired */
+	u_char timer1_exp ;		/* flag : timer 1 expired */
+	u_char timer2_exp ;		/* flag : timer 2 expired */
+
+	u_char rm_pad1[1] ;
+} ;
+
+/*
+ * CFM - Configuration Management
+ * cfm.c
+ * used for SAS and DAS
+ */
+struct s_cfm {
+	u_char cf_state;		/* CFM state machine current state */
+	u_char cf_pad[3] ;
+} ;
+
+/*
+ * CEM - Configuration Element Management
+ * cem.c
+ * used for Concentrator
+ */
+#ifdef	CONCENTRATOR
+struct s_cem {
+	int	ce_state ;	/* CEM state */
+	int	ce_port ;	/* PA PB PM PM+1 .. */
+	int	ce_type ;	/* TA TB TS TM */
+} ;
+
+/*
+ * linked list of CCEs in current token path
+ */
+struct s_c_ring {
+	struct s_c_ring	*c_next ;
+	char		c_entity ;
+} ;
+
+struct mib_path_config {
+	u_long	fddimibPATHConfigSMTIndex;
+	u_long	fddimibPATHConfigPATHIndex;
+	u_long	fddimibPATHConfigTokenOrder;
+	u_long	fddimibPATHConfigResourceType;
+#define SNMP_RES_TYPE_MAC	2	/* Resource is a MAC */
+#define SNMP_RES_TYPE_PORT	4	/* Resource is a PORT */
+	u_long	fddimibPATHConfigResourceIndex;
+	u_long	fddimibPATHConfigCurrentPath;
+#define SNMP_PATH_ISOLATED	1	/* Current path is isolated */
+#define SNMP_PATH_LOCAL		2	/* Current path is local */
+#define SNMP_PATH_SECONDARY	3	/* Current path is secondary */
+#define SNMP_PATH_PRIMARY	4	/* Current path is primary */
+#define SNMP_PATH_CONCATENATED	5	/* Current path is concatenated */
+#define SNMP_PATH_THRU		6	/* Current path is thru */
+};
+
+
+#endif
+
+/*
+ * PCM connect states
+ */
+#define PCM_DISABLED	0
+#define PCM_CONNECTING	1
+#define PCM_STANDBY	2
+#define PCM_ACTIVE	3
+
+struct s_pcm {
+	u_char	pcm_pad[3] ;
+} ;
+
+/*
+ * PHY struct
+ * one per physical port
+ */
+struct s_phy {
+	/* Inter Module Globals */
+	struct fddi_mib_p	*mib ;
+
+	u_char np ;		/* index 0 .. NUMPHYS */
+	u_char cf_join ;
+	u_char cf_loop ;
+	u_char wc_flag ;	/* withhold connection flag */
+	u_char pc_mode ;	/* Holds the negotiated mode of the PCM */
+	u_char pc_lem_fail ;	/* flag : LCT failed */
+	u_char lc_test ;
+	u_char scrub ;		/* CFM flag Scrub -> PCM */
+	char phy_name ;
+	u_char pmd_type[2] ;	/* SK connector/transceiver type codes */
+#define PMD_SK_CONN	0	/* pmd_type[PMD_SK_CONN] = Connector */
+#define PMD_SK_PMD	1	/* pmd_type[PMD_SK_PMD] = Xver */
+	u_char pmd_scramble ;	/* scrambler on/off */
+
+	/* inner Module Globals */
+	u_char curr_ls ;	/* current line state */
+	u_char ls_flag ;
+	u_char rc_flag ;
+	u_char tc_flag ;
+	u_char td_flag ;
+	u_char bitn ;
+	u_char tr_flag ;	/* trace recvd while in active */
+	u_char twisted ;	/* flag to indicate an A-A or B-B connection */
+	u_char t_val[NUMBITS] ;	/* transmit bits for signaling */
+	u_char r_val[NUMBITS] ;	/* receive bits for signaling */
+	u_long t_next[NUMBITS] ;
+	struct smt_timer pcm_timer0 ;
+	struct smt_timer pcm_timer1 ;
+	struct smt_timer pcm_timer2 ;
+	u_char timer0_exp ;
+	u_char timer1_exp ;
+	u_char timer2_exp ;
+	u_char pcm_pad1[1] ;
+	int	cem_pst ;	/* CEM privae state; used for dual homing */
+	struct lem_counter lem ;
+#ifdef	AMDPLC
+	struct s_plc	plc ;
+#endif
+} ;
+
+/*
+ * timer package
+ * smttimer.c
+ */
+struct s_timer {
+	struct smt_timer	*st_queue ;
+	struct smt_timer	st_fast ;
+} ;
+
+/*
+ * SRF types and data
+ */
+#define SMT_EVENT_BASE			1
+#define SMT_EVENT_MAC_PATH_CHANGE	(SMT_EVENT_BASE+0)
+#define SMT_EVENT_MAC_NEIGHBOR_CHANGE	(SMT_EVENT_BASE+1)
+#define SMT_EVENT_PORT_PATH_CHANGE	(SMT_EVENT_BASE+2)
+#define SMT_EVENT_PORT_CONNECTION	(SMT_EVENT_BASE+3)
+
+#define SMT_IS_CONDITION(x)			((x)>=SMT_COND_BASE)
+
+#define SMT_COND_BASE		(SMT_EVENT_PORT_CONNECTION+1)
+#define SMT_COND_SMT_PEER_WRAP		(SMT_COND_BASE+0)
+#define SMT_COND_SMT_HOLD		(SMT_COND_BASE+1)
+#define SMT_COND_MAC_FRAME_ERROR	(SMT_COND_BASE+2)
+#define SMT_COND_MAC_DUP_ADDR		(SMT_COND_BASE+3)
+#define SMT_COND_MAC_NOT_COPIED		(SMT_COND_BASE+4)
+#define SMT_COND_PORT_EB_ERROR		(SMT_COND_BASE+5)
+#define SMT_COND_PORT_LER		(SMT_COND_BASE+6)
+
+#define SR0_WAIT	0
+#define SR1_HOLDOFF	1
+#define SR2_DISABLED	2
+
+struct s_srf {
+	u_long	SRThreshold ;			/* threshold value */
+	u_char	RT_Flag ;			/* report transmitted flag */
+	u_char	sr_state ;			/* state-machine */
+	u_char	any_report ;			/* any report required */
+	u_long	TSR ;				/* timer */
+	u_short	ring_status ;			/* IBM ring status */
+} ;
+
+/*
+ * IBM token ring status
+ */
+#define RS_RES15	(1<<15)			/* reserved */
+#define RS_HARDERROR	(1<<14)			/* ring down */
+#define RS_SOFTERROR	(1<<13)			/* sent SRF */
+#define RS_BEACON	(1<<12)			/* transmitted beacon */
+#define RS_PATHTEST	(1<<11)			/* path test failed */
+#define RS_SELFTEST	(1<<10)			/* selftest required */
+#define RS_RES9		(1<< 9)			/* reserved */
+#define RS_DISCONNECT	(1<< 8)			/* remote disconnect */
+#define RS_RES7		(1<< 7)			/* reserved */
+#define RS_DUPADDR	(1<< 6)			/* duplicate address */
+#define RS_NORINGOP	(1<< 5)			/* no ring op */
+#define RS_VERSION	(1<< 4)			/* SMT version mismatch */
+#define RS_STUCKBYPASSS	(1<< 3)			/* stuck bypass */
+#define RS_EVENT	(1<< 2)			/* FDDI event occured */
+#define RS_RINGOPCHANGE	(1<< 1)			/* ring op changed */
+#define RS_RES0		(1<< 0)			/* reserved */
+
+#define RS_SET(smc,bit) \
+	ring_status_indication(smc,smc->srf.ring_status |= bit)
+#define RS_CLEAR(smc,bit)	\
+	ring_status_indication(smc,smc->srf.ring_status &= ~bit)
+
+#define RS_CLEAR_EVENT	(0xffff & ~(RS_NORINGOP))
+
+/* Define the AIX-event-Notification as null function if it isn't defined */
+/* in the targetos.h file */
+#ifndef AIX_EVENT
+#define AIX_EVENT(smc,opt0,opt1,opt2,opt3)	/* nothing */
+#endif
+
+struct s_srf_evc {
+	u_char	evc_code ;			/* event code type */
+	u_char	evc_index ;			/* index for mult. instances */
+	u_char	evc_rep_required ;		/* report required */
+	u_short	evc_para ;			/* SMT Para Number */
+	u_char	*evc_cond_state ;		/* condition state */
+	u_char	*evc_multiple ;			/* multiple occurence */
+} ;
+
+/*
+ * Values used by frame based services
+ * smt.c
+ */
+#define SMT_MAX_TEST		5
+#define SMT_TID_NIF		0		/* pending NIF request */
+#define SMT_TID_NIF_TEST	1		/* pending NIF test */
+#define SMT_TID_ECF_UNA		2		/* pending ECF UNA test */
+#define SMT_TID_ECF_DNA		3		/* pending ECF DNA test */
+#define SMT_TID_ECF		4		/* pending ECF test */
+
+struct smt_values {
+	u_long		smt_tvu ;		/* timer valid una */
+	u_long		smt_tvd ;		/* timer valid dna */
+	u_long		smt_tid ;		/* transaction id */
+	u_long		pend[SMT_MAX_TEST] ;	/* TID of requests */
+	u_long		uniq_time ;		/* unique time stamp */
+	u_short		uniq_ticks  ;		/* unique time stamp */
+	u_short		please_reconnect ;	/* flag : reconnect */
+	u_long		smt_last_lem ;
+	u_long		smt_last_notify ;
+	struct smt_timer	smt_timer ;	/* SMT NIF timer */
+	u_long		last_tok_time[NUMMACS];	/* token cnt emulation */
+} ;
+
+/*
+ * SMT/CMT configurable parameters
+ */
+#define SMT_DAS	0			/* dual attach */
+#define SMT_SAS	1			/* single attach */
+#define SMT_NAC	2			/* null attach concentrator */
+
+struct smt_config {
+	u_char	attach_s ;		/* CFM attach to secondary path */
+	u_char	sas ;			/* SMT_DAS/SAS/NAC */
+	u_char	build_ring_map ;	/* build ringmap if TRUE */
+	u_char	numphys ;		/* number of active phys */
+	u_char	sc_pad[1] ;
+
+	u_long	pcm_tb_min ;		/* PCM : TB_Min timer value */
+	u_long	pcm_tb_max ;		/* PCM : TB_Max timer value */
+	u_long	pcm_c_min ;		/* PCM : C_Min timer value */
+	u_long	pcm_t_out ;		/* PCM : T_Out timer value */
+	u_long	pcm_tl_min ;		/* PCM : TL_min timer value */
+	u_long	pcm_lc_short ;		/* PCM : LC_Short timer value */
+	u_long	pcm_lc_medium ;		/* PCM : LC_Medium timer value */
+	u_long	pcm_lc_long ;		/* PCM : LC_Long timer value */
+	u_long	pcm_lc_extended ;	/* PCM : LC_Extended timer value */
+	u_long	pcm_t_next_9 ;		/* PCM : T_Next[9] timer value */
+	u_long	pcm_ns_max ;		/* PCM : NS_Max timer value */
+
+	u_long	ecm_i_max ;		/* ECM : I_Max timer value */
+	u_long	ecm_in_max ;		/* ECM : IN_Max timer value */
+	u_long	ecm_td_min ;		/* ECM : TD_Min timer */
+	u_long	ecm_test_done ;		/* ECM : path test done timer */
+	u_long	ecm_check_poll ;	/* ECM : check bypass poller */
+
+	u_long	rmt_t_non_op ;		/* RMT : T_Non_OP timer value */
+	u_long	rmt_t_stuck ;		/* RMT : T_Stuck timer value */
+	u_long	rmt_t_direct ;		/* RMT : T_Direct timer value */
+	u_long	rmt_t_jam ;		/* RMT : T_Jam timer value */
+	u_long	rmt_t_announce ;	/* RMT : T_Announce timer value */
+	u_long	rmt_t_poll ;		/* RMT : claim/beacon poller */
+	u_long  rmt_dup_mac_behavior ;  /* Flag for the beavior of SMT if
+					 * a Duplicate MAC Address was detected.
+					 * FALSE: SMT will leave finaly the ring
+					 * TRUE:  SMT will reinstert into the ring
+					 */
+	u_long	mac_d_max ;		/* MAC : D_Max timer value */
+
+	u_long lct_short ;		/* LCT : error threshhold */
+	u_long lct_medium ;		/* LCT : error threshhold */
+	u_long lct_long ;		/* LCT : error threshhold */
+	u_long lct_extended ;		/* LCT : error threshhold */
+} ;
+
+#ifdef	DEBUG
+/*
+ * Debugging struct sometimes used in smc
+ */
+struct	smt_debug {
+	int	d_smtf ;
+	int	d_smt ;
+	int	d_ecm ;
+	int	d_rmt ;
+	int	d_cfm ;
+	int	d_pcm ;
+	int	d_plc ;
+#ifdef	ESS
+	int	d_ess ;
+#endif
+#ifdef	SBA
+	int	d_sba ;
+#endif
+	struct	os_debug	d_os;	/* Include specific OS DEBUG struct */
+} ;
+
+#ifndef	DEBUG_BRD
+/* all boards shall be debugged with one debug struct */
+extern	struct	smt_debug	debug;	/* Declaration of debug struct */
+#endif	/* DEBUG_BRD */
+
+#endif	/* DEBUG */
+
+/*
+ * the SMT Context Struct SMC
+ * this struct contains ALL global variables of SMT
+ */
+struct s_smc {
+	struct s_smt_os	os ;		/* os specific */
+	struct s_smt_hw	hw ;		/* hardware */
+
+/*
+ * NOTE: os and hw MUST BE the first two structs
+ * anything beyond hw WILL BE SET TO ZERO in smt_set_defaults()
+ */
+	struct smt_config s ;		/* smt constants */
+	struct smt_values sm ;		/* smt variables */
+	struct s_ecm	e ;		/* ecm */
+	struct s_rmt	r ;		/* rmt */
+	struct s_cfm	cf ;		/* cfm/cem */
+#ifdef	CONCENTRATOR
+	struct s_cem	ce[NUMPHYS] ;	/* cem */
+	struct s_c_ring	cr[NUMPHYS+NUMMACS] ;
+#endif
+	struct s_pcm	p ;		/* pcm */
+	struct s_phy	y[NUMPHYS] ;	/* phy */
+	struct s_queue	q ;		/* queue */
+	struct s_timer	t ;		/* timer */
+	struct s_srf srf ;		/* SRF */
+	struct s_srf_evc evcs[6+NUMPHYS*4] ;
+	struct fddi_mib	mib ;		/* __THE_MIB__ */
+#ifdef	SBA
+	struct s_sba	sba ;		/* SBA variables */
+#endif
+#ifdef	ESS
+	struct s_ess	ess ;		/* Ess variables */
+#endif
+#if	defined(DEBUG) && defined(DEBUG_BRD)
+	/* If you want all single board to be debugged separately */
+	struct smt_debug	debug;	/* Declaration of debug struct */
+#endif	/* DEBUG_BRD && DEBUG */
+} ;
+
+#endif	/* _SCMECM_ */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/smt.h linux.18p8/drivers/net/skfp/h/smt.h
--- linux.vanilla/drivers/net/skfp/h/smt.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/smt.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,882 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *	SMT 7.2 frame definitions
+ */
+
+#ifndef	_SMT_
+#define _SMT_
+
+/* #define SMT5_10 */
+#define SMT6_10
+#define SMT7_20
+
+#define	OPT_PMF		/* if parameter management is supported */
+#define	OPT_SRF		/* if status report is supported */
+
+/*
+ * SMT frame version 5.1
+ */
+
+#define SMT_VID	0x0001			/* V 5.1 .. 6.1 */
+#define SMT_VID_2 0x0002		/* V 7.2 */
+
+struct smt_sid {
+	u_char	sid_oem[2] ;			/* implementation spec. */
+	struct fddi_addr sid_node ;		/* node address */
+} ;
+
+typedef u_char	t_station_id[8] ;
+
+/*
+ * note on alignment :
+ * sizeof(struct smt_header) = 32
+ * all parameters are long aligned
+ * if struct smt_header starts at offset 0, all longs are aligned correctly
+ * (FC starts at offset 3)
+ */
+_packed struct smt_header {
+	struct fddi_addr    	smt_dest ;	/* destination address */
+	struct fddi_addr	smt_source ;	/* source address */
+	u_char			smt_class ;	/* NIF, SIF ... */
+	u_char			smt_type ;	/* req., response .. */
+	u_short			smt_version ;	/* version id */
+	u_int			smt_tid ;	/* transaction ID */
+	struct smt_sid		smt_sid ;	/* station ID */
+	u_short			smt_pad ;	/* pad with 0 */
+	u_short			smt_len ;	/* length of info field */
+} ;
+#define SWAP_SMTHEADER	"662sl8ss"
+
+#if	0
+/*
+ * MAC FC values
+ */
+#define FC_SMT_INFO	0x41		/* SMT info */
+#define FC_SMT_NSA	0x4f		/* SMT Next Station Addressing */
+#endif
+
+
+/*
+ * type codes
+ */
+#define SMT_ANNOUNCE	0x01		/* announcement */
+#define SMT_REQUEST	0x02		/* request */
+#define SMT_REPLY	0x03		/* reply */
+
+/*
+ * class codes
+ */
+#define SMT_NIF		0x01		/* neighbor information frames */
+#define SMT_SIF_CONFIG	0x02		/* station information configuration */
+#define SMT_SIF_OPER	0x03		/* station information operation */
+#define SMT_ECF		0x04		/* echo frames */
+#define SMT_RAF		0x05		/* resource allocation */
+#define SMT_RDF		0x06		/* request denied */
+#define SMT_SRF		0x07		/* status report */
+#define SMT_PMF_GET	0x08		/* parameter management get */
+#define SMT_PMF_SET	0x09		/* parameter management set */
+#define SMT_ESF		0xff		/* extended service */
+
+#define SMT_MAX_ECHO_LEN	4458	/* max length of SMT Echo */
+#if	defined(CONC) || defined(CONC_II)
+#define SMT_TEST_ECHO_LEN	50	/* test length of SMT Echo */
+#else
+#define SMT_TEST_ECHO_LEN	SMT_MAX_ECHO_LEN	/* test length */
+#endif
+
+#define SMT_MAX_INFO_LEN	(4352-20)	/* max length for SMT info */
+
+
+/*
+ * parameter types
+ */
+
+struct smt_para {
+	u_short	p_type ;		/* type */
+	u_short	p_len ;			/* length of parameter */
+} ;
+
+#define PARA_LEN	(sizeof(struct smt_para))
+
+#define SMTSETPARA(p,t)		(p)->para.p_type = (t),\
+				(p)->para.p_len = sizeof(*(p)) - PARA_LEN
+
+/*
+ * P01 : Upstream Neighbor Address, UNA
+ */
+#define SMT_P_UNA	0x0001		/* upstream neighbor address */
+#define SWAP_SMT_P_UNA	"s6"
+
+struct smt_p_una {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	una_pad ;
+	struct fddi_addr una_node ;	/* node address, zero if unknown */
+} ;
+
+/*
+ * P02 : Station Descriptor
+ */
+#define SMT_P_SDE	0x0002		/* station descriptor */
+#define SWAP_SMT_P_SDE	"1111"
+
+#define SMT_SDE_STATION		0	/* end node */
+#define SMT_SDE_CONCENTRATOR	1	/* concentrator */
+
+struct smt_p_sde {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char	sde_type ;		/* station type */
+	u_char	sde_mac_count ;		/* number of MACs */
+	u_char	sde_non_master ;	/* number of A,B or S ports */
+	u_char	sde_master ;		/* number of S ports on conc. */
+} ;
+
+/*
+ * P03 : Station State
+ */
+#define SMT_P_STATE	0x0003		/* station state */
+#define SWAP_SMT_P_STATE	"scc"
+
+struct smt_p_state {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	st_pad ;
+	u_char	st_topology ;		/* topology */
+	u_char	st_dupl_addr ;		/* duplicate address detected */
+} ;
+#define SMT_ST_WRAPPED		(1<<0)	/* station wrapped */
+#define SMT_ST_UNATTACHED	(1<<1)	/* unattached concentrator */
+#define SMT_ST_TWISTED_A	(1<<2)	/* A-A connection, twisted ring */
+#define SMT_ST_TWISTED_B	(1<<3)	/* B-B connection, twisted ring */
+#define SMT_ST_ROOTED_S		(1<<4)	/* rooted station */
+#define SMT_ST_SRF		(1<<5)	/* SRF protocol supported */
+#define SMT_ST_SYNC_SERVICE	(1<<6)	/* use synchronous bandwidth */
+
+#define SMT_ST_MY_DUPA		(1<<0)	/* my station detected dupl. */
+#define SMT_ST_UNA_DUPA		(1<<1)	/* my UNA detected duplicate */
+
+/*
+ * P04 : timestamp
+ */
+#define SMT_P_TIMESTAMP	0x0004		/* time stamp */
+#define SWAP_SMT_P_TIMESTAMP	"8"
+struct smt_p_timestamp {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char	ts_time[8] ;		/* time, resolution 80nS, unique */
+} ;
+
+/*
+ * P05 : station policies
+ */
+#define SMT_P_POLICY	0x0005		/* station policies */
+#define SWAP_SMT_P_POLICY	"ss"
+
+struct smt_p_policy {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	pl_config ;
+	u_short pl_connect ;		/* bit string POLICY_AA ... */
+} ;
+#define SMT_PL_HOLD		1	/* hold policy supported (Dual MAC) */
+
+/*
+ * P06 : latency equivalent
+ */
+#define SMT_P_LATENCY	0x0006		/* latency */
+#define SWAP_SMT_P_LATENCY	"ssss"
+
+/*
+ * note: latency has two phy entries by definition
+ * for a SAS, the 2nd one is null
+ */
+struct smt_p_latency {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	lt_phyout_idx1 ;	/* index */
+	u_short	lt_latency1 ;		/* latency , unit : byte clock */
+	u_short	lt_phyout_idx2 ;	/* 0 if SAS */
+	u_short	lt_latency2 ;		/* 0 if SAS */
+} ;
+
+/*
+ * P07 : MAC neighbors
+ */
+#define SMT_P_NEIGHBORS	0x0007		/* MAC neighbor description */
+#define SWAP_SMT_P_NEIGHBORS	"ss66"
+
+struct smt_p_neighbor {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	nb_mib_index ;		/* MIB index */
+	u_short	nb_mac_index ;		/* n+1 .. n+m, m = #MACs, n = #PHYs */
+	struct fddi_addr nb_una ;	/* UNA , 0 for unknown */
+	struct fddi_addr nb_dna ;	/* DNA , 0 for unknown */
+} ;
+
+/*
+ * PHY record
+ */
+#define SMT_PHY_A	0		/* A port */
+#define SMT_PHY_B	1		/* B port */
+#define SMT_PHY_S	2		/* slave port */
+#define SMT_PHY_M	3		/* master port */
+
+#define SMT_CS_DISABLED	0		/* connect state : disabled */
+#define SMT_CS_CONNECTING	1	/* connect state : connecting */
+#define SMT_CS_STANDBY	2		/* connect state : stand by */
+#define SMT_CS_ACTIVE	3		/* connect state : active */
+
+#define SMT_RM_NONE	0
+#define SMT_RM_MAC	1
+
+struct smt_phy_rec {
+	u_short	phy_mib_index ;		/* MIB index */
+	u_char	phy_type ;		/* A/B/S/M */
+	u_char	phy_connect_state ;	/* disabled/connecting/active */
+	u_char	phy_remote_type ;	/* A/B/S/M */
+	u_char	phy_remote_mac ;	/* none/remote */
+	u_short	phy_resource_idx ;	/* 1 .. n */
+} ;
+
+/*
+ * MAC record
+ */
+struct smt_mac_rec {
+	struct fddi_addr mac_addr ;		/* MAC address */
+	u_short		mac_resource_idx ;	/* n+1 .. n+m */
+} ;
+
+/*
+ * P08 : path descriptors
+ * should be really an array ; however our environment has a fixed number of
+ * PHYs and MACs
+ */
+#define SMT_P_PATH	0x0008			/* path descriptor */
+#define SWAP_SMT_P_PATH	"[6s]"
+
+struct smt_p_path {
+	struct smt_para	para ;		/* generic parameter header */
+	struct smt_phy_rec	pd_phy[2] ;	/* PHY A */
+	struct smt_mac_rec	pd_mac ;	/* MAC record */
+} ;
+
+/*
+ * P09 : MAC status
+ */
+#define SMT_P_MAC_STATUS	0x0009		/* MAC status */
+#define SWAP_SMT_P_MAC_STATUS	"sslllllllll"
+
+struct smt_p_mac_status {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short st_mib_index ;		/* MIB index */
+	u_short	st_mac_index ;		/* n+1 .. n+m */
+	u_int	st_t_req ;		/* T_Req */
+	u_int	st_t_neg ;		/* T_Neg */
+	u_int	st_t_max ;		/* T_Max */
+	u_int	st_tvx_value ;		/* TVX_Value */
+	u_int	st_t_min ;		/* T_Min */
+	u_int	st_sba ;		/* synchr. bandwidth alloc */
+	u_int	st_frame_ct ;		/* frame counter */
+	u_int	st_error_ct ;		/* error counter */
+	u_int	st_lost_ct ;		/* lost frames counter */
+} ;
+
+/*
+ * P0A : PHY link error rate monitoring
+ */
+#define SMT_P_LEM	0x000a		/* link error monitor */
+#define SWAP_SMT_P_LEM	"ssccccll"
+/*
+ * units of lem_cutoff,lem_alarm,lem_estimate : 10**-x
+ */
+struct smt_p_lem {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	lem_mib_index ;		/* MIB index */
+	u_short	lem_phy_index ;		/* 1 .. n */
+	u_char	lem_pad2 ;		/* be nice and make it even . */
+	u_char	lem_cutoff ;		/* 0x4 .. 0xf, default 0x7 */
+	u_char	lem_alarm ;		/* 0x4 .. 0xf, default 0x8 */
+	u_char	lem_estimate ;		/* 0x0 .. 0xff */
+	u_int	lem_reject_ct ;		/* 0x00000000 .. 0xffffffff */
+	u_int	lem_ct ;		/* 0x00000000 .. 0xffffffff */
+} ;
+
+/*
+ * P0B : MAC frame counters
+ */
+#define SMT_P_MAC_COUNTER 0x000b	/* MAC frame counters */
+#define SWAP_SMT_P_MAC_COUNTER	"ssll"
+
+struct smt_p_mac_counter {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	mc_mib_index ;		/* MIB index */
+	u_short	mc_index ;		/* mac index */
+	u_int	mc_receive_ct ;		/* receive counter */
+	u_int	mc_transmit_ct ;	/* transmit counter */
+} ;
+
+/*
+ * P0C : MAC frame not copied counter
+ */
+#define SMT_P_MAC_FNC	0x000c		/* MAC frame not copied counter */
+#define SWAP_SMT_P_MAC_FNC	"ssl"
+
+struct smt_p_mac_fnc {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	nc_mib_index ;		/* MIB index */
+	u_short	nc_index ;		/* mac index */
+	u_int	nc_counter ;		/* not copied counter */
+} ;
+
+
+/*
+ * P0D : MAC priority values
+ */
+#define SMT_P_PRIORITY	0x000d		/* MAC priority values */
+#define SWAP_SMT_P_PRIORITY	"ssl"
+
+struct smt_p_priority {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	pr_mib_index ;		/* MIB index */
+	u_short	pr_index ;		/* mac index */
+	u_int	pr_priority[7] ;	/* priority values */
+} ;
+
+/*
+ * P0E : PHY elasticity buffer status
+ */
+#define SMT_P_EB	0x000e		/* PHY EB status */
+#define SWAP_SMT_P_EB	"ssl"
+
+struct smt_p_eb {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	eb_mib_index ;		/* MIB index */
+	u_short	eb_index ;		/* phy index */
+	u_int	eb_error_ct ;		/* # of eb overflows */
+} ;
+
+/*
+ * P0F : manufacturer field
+ */
+#define SMT_P_MANUFACTURER	0x000f	/* manufacturer field */
+#define SWAP_SMT_P_MANUFACTURER	""
+
+struct smp_p_manufacturer {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char mf_data[32] ;		/* OUI + arbitrary data */
+} ;
+
+/*
+ * P10 : user field
+ */
+#define SMT_P_USER		0x0010	/* manufacturer field */
+#define SWAP_SMT_P_USER	""
+
+struct smp_p_user {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char us_data[32] ;		/* arbitrary data */
+} ;
+
+
+
+/*
+ * P11 : echo data
+ */
+#define SMT_P_ECHODATA	0x0011		/* echo data */
+#define SWAP_SMT_P_ECHODATA	""
+
+struct smt_p_echo {
+	struct smt_para	para ;		/* generic parameter header */
+	u_char	ec_data[SMT_MAX_ECHO_LEN-4] ;	/* echo data */
+} ;
+
+/*
+ * P12 : reason code
+ */
+#define SMT_P_REASON	0x0012		/* reason code */
+#define SWAP_SMT_P_REASON	"l"
+
+struct smt_p_reason {
+	struct smt_para	para ;		/* generic parameter header */
+	u_int	rdf_reason ;		/* CLASS/VERSION */
+} ;
+#define SMT_RDF_CLASS	0x00000001	/* class not supported */
+#define SMT_RDF_VERSION	0x00000002	/* version not supported */
+#define SMT_RDF_SUCCESS	0x00000003	/* success (PMF) */
+#define SMT_RDF_BADSET	0x00000004	/* bad set count (PMF) */
+#define SMT_RDF_ILLEGAL 0x00000005	/* read only (PMF) */
+#define SMT_RDF_NOPARAM	0x6		/* paramter not supported (PMF) */
+#define SMT_RDF_RANGE	0x8		/* out of range */
+#define SMT_RDF_AUTHOR	0x9		/* not autohorized */
+#define SMT_RDF_LENGTH	0x0a		/* length error */
+#define SMT_RDF_TOOLONG	0x0b		/* length error */
+#define SMT_RDF_SBA	0x0d		/* SBA denied */
+
+/*
+ * P13 : refused frame beginning
+ */
+#define SMT_P_REFUSED	0x0013		/* refused frame beginning */
+#define SWAP_SMT_P_REFUSED	"l"
+
+struct smt_p_refused {
+	struct smt_para	para ;		/* generic parameter header */
+	u_int	ref_fc ;		/* 3 bytes 0 + FC */
+	struct smt_header	ref_header ;	/* refused header */
+} ;
+
+/*
+ * P14 : supported SMT versions
+ */
+#define SMT_P_VERSION	0x0014		/* SMT supported versions */
+#define SWAP_SMT_P_VERSION	"sccss"
+
+struct smt_p_version {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	v_pad ;
+	u_char	v_n ;			/* 1 .. 0xff, #versions */
+	u_char	v_index ;		/* 1 .. 0xff, index of op. v. */
+	u_short	v_version[1] ;		/* list of min. 1 version */
+	u_short	v_pad2 ;		/* pad if necessary */
+} ;
+
+/*
+ * P15 : Resource Type
+ */
+#define	SWAP_SMT_P0015		"l"
+
+struct smt_p_0015 {
+	struct smt_para	para ;		/* generic parameter header */
+	u_int		res_type ;	/* recsource type */
+} ;
+
+#define	SYNC_BW		0x00000001L	/* Synchronous Bandwidth */
+
+/*
+ * P16 : SBA Command
+ */
+#define	SWAP_SMT_P0016		"l"
+
+struct smt_p_0016 {
+	struct smt_para	para ;		/* generic parameter header */
+	u_int		sba_cmd ;	/* command for the SBA */
+} ;
+
+#define	REQUEST_ALLOCATION	0x1	/* req allocation of sync bandwidth */
+#define	REPORT_ALLOCATION	0x2	/* rep of sync bandwidth allocation */
+#define	CHANGE_ALLOCATION	0x3	/* forces a station using sync band-*/
+					/* width to change its current allo-*/
+					/* cation */
+
+/*
+ * P17 : SBA Payload Request
+ */
+#define	SWAP_SMT_P0017		"l"
+
+struct smt_p_0017 {
+	struct smt_para	para ;		/* generic parameter header */
+	int		sba_pl_req ;	/* total sync bandwidth measured in */
+} ;					/* bytes per 125 us */
+
+/*
+ * P18 : SBA Overhead Request
+ */
+#define	SWAP_SMT_P0018		"l"
+
+struct smt_p_0018 {
+	struct smt_para	para ;		/* generic parameter header */
+	int		sba_ov_req ;	/* total sync bandwidth req for overhead*/
+} ;					/* measuered in bytes per T_Neg */
+
+/*
+ * P19 : SBA Allocation Address
+ */
+#define	SWAP_SMT_P0019		"s6"
+
+struct smt_p_0019 {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short		sba_pad ;
+	struct fddi_addr alloc_addr ;	/* Allocation Address */
+} ;
+
+/*
+ * P1A : SBA Category
+ */
+#define	SWAP_SMT_P001A		"l"
+
+struct smt_p_001a {
+	struct smt_para	para ;		/* generic parameter header */
+	u_int		category ;	/* Allocator defined classification */
+} ;
+
+/*
+ * P1B : Maximum T_Neg
+ */
+#define	SWAP_SMT_P001B		"l"
+
+struct smt_p_001b {
+	struct smt_para	para ;		/* generic parameter header */
+	u_int		max_t_neg ;	/* longest T_NEG for the sync service*/
+} ;
+
+/*
+ * P1C : Minimum SBA Segment Size
+ */
+#define	SWAP_SMT_P001C		"l"
+
+struct smt_p_001c {
+	struct smt_para	para ;		/* generic parameter header */
+	u_int		min_seg_siz ;	/* smallest number of bytes per frame*/
+} ;
+
+/*
+ * P1D : SBA Allocatable
+ */
+#define	SWAP_SMT_P001D		"l"
+
+struct smt_p_001d {
+	struct smt_para	para ;		/* generic parameter header */
+	u_int		allocatable ;	/* total sync bw availabel for alloc */
+} ;
+
+/*
+ * P20 0B : frame status capabilities
+ * NOTE: not in swap table, is used by smt.c AND PMF table
+ */
+#define SMT_P_FSC	0x200b
+/* #define SWAP_SMT_P_FSC	"ssss" */
+
+struct smt_p_fsc {
+	struct smt_para	para ;		/* generic parameter header */
+	u_short	fsc_pad0 ;
+	u_short	fsc_mac_index ;		/* mac index 1 .. ff */
+	u_short	fsc_pad1 ;
+	u_short	fsc_value ;		/* FSC_TYPE[0-2] */
+} ;
+
+#define FSC_TYPE0	0		/* "normal" node (A/C handling) */
+#define FSC_TYPE1	1		/* Special A/C indicator forwarding */
+#define FSC_TYPE2	2		/* Special A/C indicator forwarding */
+
+/*
+ * P00 21 : user defined authoriziation (see pmf.c)
+ */
+#define SMT_P_AUTHOR	0x0021
+
+/*
+ * notification parameters
+ */
+#define SWAP_SMT_P1048	"ll"
+struct smt_p_1048 {
+	u_int p1048_flag ;
+	u_int p1048_cf_state ;
+} ;
+
+/*
+ * NOTE: all 2xxx 3xxx and 4xxx must include the INDEX in the swap string,
+ *	even so the INDEX is NOT part of the struct.
+ *	INDEX is already swapped in pmf.c, format in string is '4'
+ */
+#define SWAP_SMT_P208C	"4lss66"
+struct smt_p_208c {
+	u_int			p208c_flag ;
+	u_short			p208c_pad ;
+	u_short			p208c_dupcondition ;
+	struct	fddi_addr	p208c_fddilong ;
+	struct	fddi_addr	p208c_fddiunalong ;
+} ;
+
+#define SWAP_SMT_P208D	"4lllll"
+struct smt_p_208d {
+	u_int			p208d_flag ;
+	u_int			p208d_frame_ct ;
+	u_int			p208d_error_ct ;
+	u_int			p208d_lost_ct ;
+	u_int			p208d_ratio ;
+} ;
+
+#define SWAP_SMT_P208E	"4llll"
+struct smt_p_208e {
+	u_int			p208e_flag ;
+	u_int			p208e_not_copied ;
+	u_int			p208e_copied ;
+	u_int			p208e_not_copied_ratio ;
+} ;
+
+#define SWAP_SMT_P208F	"4ll6666s6"
+
+struct smt_p_208f {
+	u_int			p208f_multiple ;
+	u_int			p208f_nacondition ;
+	struct fddi_addr	p208f_old_una ;
+	struct fddi_addr	p208f_new_una ;
+	struct fddi_addr	p208f_old_dna ;
+	struct fddi_addr	p208f_new_dna ;
+	u_short			p208f_curren_path ;
+	struct fddi_addr	p208f_smt_address ;
+} ;
+
+#define SWAP_SMT_P2090	"4lssl"
+
+struct smt_p_2090 {
+	u_int			p2090_multiple ;
+	u_short			p2090_availablepaths ;
+	u_short			p2090_currentpath ;
+	u_int			p2090_requestedpaths ;
+} ;
+
+/*
+ * NOTE:
+ * special kludge for parameters 320b,320f,3210
+ * these parameters are part of RAF frames
+ * RAF frames are parsed in SBA.C and must be swapped
+ * PMF.C has special code to avoid double swapping
+ */
+#ifdef	LITTLE_ENDIAN
+#define SBAPATHINDEX	(0x01000000L)
+#else
+#define SBAPATHINDEX	(0x01L)
+#endif
+
+#define	SWAP_SMT_P320B	"42s"
+
+struct	smt_p_320b {
+	struct smt_para para ;	/* generic parameter header */
+	u_int	mib_index ;
+	u_short path_pad ;
+	u_short	path_index ;
+} ;
+
+#define	SWAP_SMT_P320F	"4l"
+
+struct	smt_p_320f {
+	struct smt_para para ;	/* generic parameter header */
+	u_int	mib_index ;
+	u_int	mib_payload ;
+} ;
+
+#define	SWAP_SMT_P3210	"4l"
+
+struct	smt_p_3210 {
+	struct smt_para para ;	/* generic parameter header */
+	u_int	mib_index ;
+	u_int	mib_overhead ;
+} ;
+
+#define SWAP_SMT_P4050	"4l1111ll"
+
+struct smt_p_4050 {
+	u_int			p4050_flag ;
+	u_char			p4050_pad ;
+	u_char			p4050_cutoff ;
+	u_char			p4050_alarm ;
+	u_char			p4050_estimate ;
+	u_int			p4050_reject_ct ;
+	u_int			p4050_ct ;
+} ;
+
+#define SWAP_SMT_P4051	"4lssss"
+struct smt_p_4051 {
+	u_int			p4051_multiple ;
+	u_short			p4051_porttype ;
+	u_short			p4051_connectstate ;
+	u_short			p4051_pc_neighbor ;
+	u_short			p4051_pc_withhold ;
+} ;
+
+#define SWAP_SMT_P4052	"4ll"
+struct smt_p_4052 {
+	u_int			p4052_flag ;
+	u_int			p4052_eberrorcount ;
+} ;
+
+#define SWAP_SMT_P4053	"4lsslss"
+
+struct smt_p_4053 {
+	u_int			p4053_multiple ;
+	u_short			p4053_availablepaths ;
+	u_short			p4053_currentpath ;
+	u_int			p4053_requestedpaths ;
+	u_short			p4053_mytype ;
+	u_short			p4053_neighbortype ;
+} ;
+
+
+#define SMT_P_SETCOUNT	0x1035
+#define SWAP_SMT_P_SETCOUNT	"l8"
+
+struct smt_p_setcount {
+	struct smt_para	para ;		/* generic parameter header */
+	u_int		count ;
+	u_char		timestamp[8] ;
+} ;
+
+/*
+ * SMT FRAMES
+ */
+
+/*
+ * NIF : neighbor information frames
+ */
+struct smt_nif {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_una	una ;		/* UNA */
+	struct smt_p_sde	sde ;		/* station descriptor */
+	struct smt_p_state	state ;		/* station state */
+#ifdef	SMT6_10
+	struct smt_p_fsc	fsc ;		/* frame status cap. */
+#endif
+} ;
+
+/*
+ * SIF : station information frames
+ */
+struct smt_sif_config {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_timestamp	ts ;		/* time stamp */
+	struct smt_p_sde	sde ;		/* station descriptor */
+	struct smt_p_version	version ;	/* supported versions */
+	struct smt_p_state	state ;		/* station state */
+	struct smt_p_policy	policy ;	/* station policy */
+	struct smt_p_latency	latency ;	/* path latency */
+	struct smt_p_neighbor	neighbor ;	/* neighbors, we have only one*/
+#ifdef	OPT_PMF
+	struct smt_p_setcount	setcount ;	 /* Set Count mandatory */
+#endif
+	/* WARNING : path MUST BE LAST FIELD !!! (see smt.c:smt_fill_path) */
+	struct smt_p_path	path ;		/* path descriptor */
+} ;
+#define SIZEOF_SMT_SIF_CONFIG	(sizeof(struct smt_sif_config)- \
+				 sizeof(struct smt_p_path))
+
+struct smt_sif_operation {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_timestamp	ts ;		/* time stamp */
+	struct smt_p_mac_status	status ;	/* mac status */
+	struct smt_p_mac_counter mc ;		/* MAC counter */
+	struct smt_p_mac_fnc 	fnc ;		/* MAC frame not copied */
+	struct smp_p_manufacturer man ;		/* manufacturer field */
+	struct smp_p_user	user ;		/* user field */
+#ifdef	OPT_PMF
+	struct smt_p_setcount	setcount ;	 /* Set Count mandatory */
+#endif
+	/* must be last */
+	struct smt_p_lem	lem[1] ;	/* phy lem status */
+} ;
+#define SIZEOF_SMT_SIF_OPERATION	(sizeof(struct smt_sif_operation)- \
+					 sizeof(struct smt_p_lem))
+
+/*
+ * ECF : echo frame
+ */
+struct smt_ecf {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_echo	ec_echo ;	/* echo parameter */
+} ;
+#define SMT_ECF_LEN	(sizeof(struct smt_header)+sizeof(struct smt_para))
+
+/*
+ * RDF : request denied frame
+ */
+struct smt_rdf {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_reason	reason ;	/* reason code */
+	struct smt_p_version	version ;	/* supported versions */
+	struct smt_p_refused	refused ;	/* refused frame fragment */
+} ;
+
+/*
+ * SBA Request Allocation Responce Frame
+ */
+struct smt_sba_alc_res {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+	struct smt_p_reason	reason ;	/* reason code */
+	struct smt_p_320b	path ;		/* path type */
+	struct smt_p_320f	payload ;	/* current SBA payload */
+	struct smt_p_3210	overhead ;	/* current SBA overhead */
+	struct smt_p_0019	a_addr ;	/* Allocation Address */
+	struct smt_p_001a	cat ;		/* Category - from the request */
+	struct smt_p_001d	alloc ;		/* SBA Allocatable */
+} ;
+
+/*
+ * SBA Request Allocation Request Frame
+ */
+struct smt_sba_alc_req {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+	struct smt_p_320b	path ;		/* path type */
+	struct smt_p_0017	pl_req ;	/* requested payload */
+	struct smt_p_0018	ov_req ;	/* requested SBA overhead */
+	struct smt_p_320f	payload ;	/* current SBA payload */
+	struct smt_p_3210	overhead ;	/* current SBA overhead */
+	struct smt_p_0019	a_addr ;	/* Allocation Address */
+	struct smt_p_001a	cat ;		/* Category - from the request */
+	struct smt_p_001b	tneg ;		/* max T-NEG */
+	struct smt_p_001c	segm ;		/* minimum segment size */
+} ;
+
+/*
+ * SBA Change Allocation Request Frame
+ */
+struct smt_sba_chg {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+	struct smt_p_320b	path ;		/* path type */
+	struct smt_p_320f	payload ;	/* current SBA payload */
+	struct smt_p_3210	overhead ;	/* current SBA overhead */
+	struct smt_p_001a	cat ;		/* Category - from the request */
+} ;
+
+/*
+ * SBA Report Allocation Request Frame
+ */
+struct smt_sba_rep_req {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+} ;
+
+/*
+ * SBA Report Allocation Response Frame
+ */
+struct smt_sba_rep_res {
+	struct smt_header	smt ;		/* generic header */
+	struct smt_p_0015	s_type ;	/* resource type */
+	struct smt_p_0016	cmd ;		/* SBA command */
+	struct smt_p_320b	path ;		/* path type */
+	struct smt_p_320f	payload ;	/* current SBA payload */
+	struct smt_p_3210	overhead ;	/* current SBA overhead */
+} ;
+
+/*
+ * actions
+ */
+#define SMT_STATION_ACTION	1
+#define SMT_STATION_ACTION_CONNECT	0
+#define SMT_STATION_ACTION_DISCONNECT	1
+#define SMT_STATION_ACTION_PATHTEST	2
+#define SMT_STATION_ACTION_SELFTEST	3
+#define SMT_STATION_ACTION_DISABLE_A	4
+#define SMT_STATION_ACTION_DISABLE_B	5
+#define SMT_STATION_ACTION_DISABLE_M	6
+
+#define SMT_PORT_ACTION		2
+#define SMT_PORT_ACTION_MAINT	0
+#define SMT_PORT_ACTION_ENABLE	1
+#define SMT_PORT_ACTION_DISABLE	2
+#define SMT_PORT_ACTION_START	3
+#define SMT_PORT_ACTION_STOP	4
+
+#endif	/* _SMT_ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/smt_p.h linux.18p8/drivers/net/skfp/h/smt_p.h
--- linux.vanilla/drivers/net/skfp/h/smt_p.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/smt_p.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,326 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * defines for all SMT attributes
+ */
+
+/*
+ * this boring file was produced by perl
+ * thanks Larry !
+ */
+#define	SMT_P0012	0x0012
+
+#define	SMT_P0015	0x0015
+#define	SMT_P0016	0x0016
+#define	SMT_P0017	0x0017
+#define	SMT_P0018	0x0018
+#define	SMT_P0019	0x0019
+
+#define	SMT_P001A	0x001a
+#define	SMT_P001B	0x001b
+#define	SMT_P001C	0x001c
+#define	SMT_P001D	0x001d
+
+#define	SMT_P100A	0x100a
+#define	SMT_P100B	0x100b
+#define	SMT_P100C	0x100c
+#define	SMT_P100D	0x100d
+#define	SMT_P100E	0x100e
+#define	SMT_P100F	0x100f
+#define	SMT_P1010	0x1010
+#define	SMT_P1011	0x1011
+#define	SMT_P1012	0x1012
+#define	SMT_P1013	0x1013
+#define	SMT_P1014	0x1014
+#define	SMT_P1015	0x1015
+#define	SMT_P1016	0x1016
+#define	SMT_P1017	0x1017
+#define	SMT_P1018	0x1018
+#define	SMT_P1019	0x1019
+#define	SMT_P101A	0x101a
+#define	SMT_P101B	0x101b
+#define	SMT_P101C	0x101c
+#define	SMT_P101D	0x101d
+#define	SMT_P101E	0x101e
+#define	SMT_P101F	0x101f
+#define	SMT_P1020	0x1020
+#define	SMT_P1021	0x1021
+#define	SMT_P1022	0x1022
+#define	SMT_P1023	0x1023
+#define	SMT_P1024	0x1024
+#define	SMT_P1025	0x1025
+#define	SMT_P1026	0x1026
+#define	SMT_P1027	0x1027
+#define	SMT_P1028	0x1028
+#define	SMT_P1029	0x1029
+#define	SMT_P102A	0x102a
+#define	SMT_P102B	0x102b
+#define	SMT_P102C	0x102c
+#define	SMT_P102D	0x102d
+#define	SMT_P102E	0x102e
+#define	SMT_P102F	0x102f
+#define	SMT_P1030	0x1030
+#define	SMT_P1031	0x1031
+#define	SMT_P1032	0x1032
+#define	SMT_P1033	0x1033
+#define	SMT_P1034	0x1034
+#define	SMT_P1035	0x1035
+#define	SMT_P1036	0x1036
+#define	SMT_P1037	0x1037
+#define	SMT_P1038	0x1038
+#define	SMT_P1039	0x1039
+#define	SMT_P103A	0x103a
+#define	SMT_P103B	0x103b
+#define	SMT_P103C	0x103c
+#define	SMT_P103D	0x103d
+#define	SMT_P103E	0x103e
+#define	SMT_P103F	0x103f
+#define	SMT_P1040	0x1040
+#define	SMT_P1041	0x1041
+#define	SMT_P1042	0x1042
+#define	SMT_P1043	0x1043
+#define	SMT_P1044	0x1044
+#define	SMT_P1045	0x1045
+#define	SMT_P1046	0x1046
+#define	SMT_P1047	0x1047
+#define	SMT_P1048	0x1048
+#define	SMT_P1049	0x1049
+#define	SMT_P104A	0x104a
+#define	SMT_P104B	0x104b
+#define	SMT_P104C	0x104c
+#define	SMT_P104D	0x104d
+#define	SMT_P104E	0x104e
+#define	SMT_P104F	0x104f
+#define	SMT_P1050	0x1050
+#define	SMT_P1051	0x1051
+#define	SMT_P1052	0x1052
+#define	SMT_P1053	0x1053
+#define	SMT_P1054	0x1054
+
+#define	SMT_P10F0	0x10f0
+#define	SMT_P10F1	0x10f1
+#ifdef	ESS
+#define	SMT_P10F2	0x10f2
+#define	SMT_P10F3	0x10f3
+#define	SMT_P10F4	0x10f4
+#define	SMT_P10F5	0x10f5
+#define	SMT_P10F6	0x10f6
+#define	SMT_P10F7	0x10f7
+#endif
+#ifdef	SBA
+#define	SMT_P10F8	0x10f8
+#define	SMT_P10F9	0x10f9
+#endif
+
+#define	SMT_P200A	0x200a
+#define	SMT_P200B	0x200b
+#define	SMT_P200C	0x200c
+#define	SMT_P200D	0x200d
+#define	SMT_P200E	0x200e
+#define	SMT_P200F	0x200f
+#define	SMT_P2010	0x2010
+#define	SMT_P2011	0x2011
+#define	SMT_P2012	0x2012
+#define	SMT_P2013	0x2013
+#define	SMT_P2014	0x2014
+#define	SMT_P2015	0x2015
+#define	SMT_P2016	0x2016
+#define	SMT_P2017	0x2017
+#define	SMT_P2018	0x2018
+#define	SMT_P2019	0x2019
+#define	SMT_P201A	0x201a
+#define	SMT_P201B	0x201b
+#define	SMT_P201C	0x201c
+#define	SMT_P201D	0x201d
+#define	SMT_P201E	0x201e
+#define	SMT_P201F	0x201f
+#define	SMT_P2020	0x2020
+#define	SMT_P2021	0x2021
+#define	SMT_P2022	0x2022
+#define	SMT_P2023	0x2023
+#define	SMT_P2024	0x2024
+#define	SMT_P2025	0x2025
+#define	SMT_P2026	0x2026
+#define	SMT_P2027	0x2027
+#define	SMT_P2028	0x2028
+#define	SMT_P2029	0x2029
+#define	SMT_P202A	0x202a
+#define	SMT_P202B	0x202b
+#define	SMT_P202C	0x202c
+#define	SMT_P202D	0x202d
+#define	SMT_P202E	0x202e
+#define	SMT_P202F	0x202f
+#define	SMT_P2030	0x2030
+#define	SMT_P2031	0x2031
+#define	SMT_P2032	0x2032
+#define	SMT_P2033	0x2033
+#define	SMT_P2034	0x2034
+#define	SMT_P2035	0x2035
+#define	SMT_P2036	0x2036
+#define	SMT_P2037	0x2037
+#define	SMT_P2038	0x2038
+#define	SMT_P2039	0x2039
+#define	SMT_P203A	0x203a
+#define	SMT_P203B	0x203b
+#define	SMT_P203C	0x203c
+#define	SMT_P203D	0x203d
+#define	SMT_P203E	0x203e
+#define	SMT_P203F	0x203f
+#define	SMT_P2040	0x2040
+#define	SMT_P2041	0x2041
+#define	SMT_P2042	0x2042
+#define	SMT_P2043	0x2043
+#define	SMT_P2044	0x2044
+#define	SMT_P2045	0x2045
+#define	SMT_P2046	0x2046
+#define	SMT_P2047	0x2047
+#define	SMT_P2048	0x2048
+#define	SMT_P2049	0x2049
+#define	SMT_P204A	0x204a
+#define	SMT_P204B	0x204b
+#define	SMT_P204C	0x204c
+#define	SMT_P204D	0x204d
+#define	SMT_P204E	0x204e
+#define	SMT_P204F	0x204f
+#define	SMT_P2050	0x2050
+#define	SMT_P2051	0x2051
+#define	SMT_P2052	0x2052
+#define	SMT_P2053	0x2053
+#define	SMT_P2054	0x2054
+#define	SMT_P2055	0x2055
+#define	SMT_P2056	0x2056
+#define	SMT_P2057	0x2057
+#define	SMT_P2058	0x2058
+#define	SMT_P2059	0x2059
+#define	SMT_P205A	0x205a
+#define	SMT_P205B	0x205b
+#define	SMT_P205C	0x205c
+#define	SMT_P205D	0x205d
+#define	SMT_P205E	0x205e
+#define	SMT_P205F	0x205f
+#define	SMT_P2060	0x2060
+#define	SMT_P2061	0x2061
+#define	SMT_P2062	0x2062
+#define	SMT_P2063	0x2063
+#define	SMT_P2064	0x2064
+#define	SMT_P2065	0x2065
+#define	SMT_P2066	0x2066
+#define	SMT_P2067	0x2067
+#define	SMT_P2068	0x2068
+#define	SMT_P2069	0x2069
+#define	SMT_P206A	0x206a
+#define	SMT_P206B	0x206b
+#define	SMT_P206C	0x206c
+#define	SMT_P206D	0x206d
+#define	SMT_P206E	0x206e
+#define	SMT_P206F	0x206f
+#define	SMT_P2070	0x2070
+#define	SMT_P2071	0x2071
+#define	SMT_P2072	0x2072
+#define	SMT_P2073	0x2073
+#define	SMT_P2074	0x2074
+#define	SMT_P2075	0x2075
+#define	SMT_P2076	0x2076
+
+#define	SMT_P208C	0x208c
+#define	SMT_P208D	0x208d
+#define	SMT_P208E	0x208e
+#define	SMT_P208F	0x208f
+#define	SMT_P2090	0x2090
+
+#define	SMT_P20F0	0x20F0
+#define	SMT_P20F1	0x20F1
+
+#define	SMT_P320A	0x320a
+#define	SMT_P320B	0x320b
+#define	SMT_P320C	0x320c
+#define	SMT_P320D	0x320d
+#define	SMT_P320E	0x320e
+#define	SMT_P320F	0x320f
+#define	SMT_P3210	0x3210
+#define	SMT_P3211	0x3211
+#define	SMT_P3212	0x3212
+#define	SMT_P3213	0x3213
+#define	SMT_P3214	0x3214
+#define	SMT_P3215	0x3215
+#define	SMT_P3216	0x3216
+#define	SMT_P3217	0x3217
+
+#define	SMT_P400A	0x400a
+#define	SMT_P400B	0x400b
+#define	SMT_P400C	0x400c
+#define	SMT_P400D	0x400d
+#define	SMT_P400E	0x400e
+#define	SMT_P400F	0x400f
+#define	SMT_P4010	0x4010
+#define	SMT_P4011	0x4011
+#define	SMT_P4012	0x4012
+#define	SMT_P4013	0x4013
+#define	SMT_P4014	0x4014
+#define	SMT_P4015	0x4015
+#define	SMT_P4016	0x4016
+#define	SMT_P4017	0x4017
+#define	SMT_P4018	0x4018
+#define	SMT_P4019	0x4019
+#define	SMT_P401A	0x401a
+#define	SMT_P401B	0x401b
+#define	SMT_P401C	0x401c
+#define	SMT_P401D	0x401d
+#define	SMT_P401E	0x401e
+#define	SMT_P401F	0x401f
+#define	SMT_P4020	0x4020
+#define	SMT_P4021	0x4021
+#define	SMT_P4022	0x4022
+#define	SMT_P4023	0x4023
+#define	SMT_P4024	0x4024
+#define	SMT_P4025	0x4025
+#define	SMT_P4026	0x4026
+#define	SMT_P4027	0x4027
+#define	SMT_P4028	0x4028
+#define	SMT_P4029	0x4029
+#define	SMT_P402A	0x402a
+#define	SMT_P402B	0x402b
+#define	SMT_P402C	0x402c
+#define	SMT_P402D	0x402d
+#define	SMT_P402E	0x402e
+#define	SMT_P402F	0x402f
+#define	SMT_P4030	0x4030
+#define	SMT_P4031	0x4031
+#define	SMT_P4032	0x4032
+#define	SMT_P4033	0x4033
+#define	SMT_P4034	0x4034
+#define	SMT_P4035	0x4035
+#define	SMT_P4036	0x4036
+#define	SMT_P4037	0x4037
+#define	SMT_P4038	0x4038
+#define	SMT_P4039	0x4039
+#define	SMT_P403A	0x403a
+#define	SMT_P403B	0x403b
+#define	SMT_P403C	0x403c
+#define	SMT_P403D	0x403d
+#define	SMT_P403E	0x403e
+#define	SMT_P403F	0x403f
+#define	SMT_P4040	0x4040
+#define	SMT_P4041	0x4041
+#define	SMT_P4042	0x4042
+#define	SMT_P4043	0x4043
+#define	SMT_P4044	0x4044
+#define	SMT_P4045	0x4045
+#define	SMT_P4046	0x4046
+
+#define	SMT_P4050	0x4050
+#define	SMT_P4051	0x4051
+#define	SMT_P4052	0x4052
+#define	SMT_P4053	0x4053
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/smtstate.h linux.18p8/drivers/net/skfp/h/smtstate.h
--- linux.vanilla/drivers/net/skfp/h/smtstate.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/smtstate.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,100 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *	SMT state definitions
+ */
+
+#ifndef	KERNEL
+/*
+ * PCM states
+ */
+#define PC0_OFF			0
+#define PC1_BREAK		1
+#define PC2_TRACE		2
+#define PC3_CONNECT		3
+#define PC4_NEXT		4
+#define PC5_SIGNAL		5
+#define PC6_JOIN		6
+#define PC7_VERIFY		7
+#define PC8_ACTIVE		8
+#define PC9_MAINT		9
+
+/*
+ * PCM modes
+ */
+#define PM_NONE			0
+#define PM_PEER			1
+#define PM_TREE			2
+
+/*
+ * PCM type
+ */
+#define TA			0
+#define TB			1
+#define TS			2
+#define TM			3
+#define TNONE			4
+
+/*
+ * CFM states
+ */
+#define SC0_ISOLATED	0		/* isolated */
+#define SC1_WRAP_A	5		/* wrap A */
+#define SC2_WRAP_B	6		/* wrap B */
+#define SC4_THRU_A	12		/* through A */
+#define SC5_THRU_B	7		/* through B (SMt 6.2) */
+#define SC7_WRAP_S	8		/* SAS */
+
+/*
+ * ECM states
+ */
+#define EC0_OUT		0
+#define EC1_IN		1
+#define EC2_TRACE	2
+#define EC3_LEAVE	3
+#define EC4_PATH_TEST	4
+#define EC5_INSERT	5
+#define EC6_CHECK	6
+#define EC7_DEINSERT	7
+
+/*
+ * RMT states
+ */
+#define RM0_ISOLATED	0
+#define RM1_NON_OP	1		/* not operational */
+#define RM2_RING_OP	2		/* ring operational */
+#define RM3_DETECT	3		/* detect dupl addresses */
+#define RM4_NON_OP_DUP	4		/* dupl. addr detected */
+#define RM5_RING_OP_DUP	5		/* ring oper. with dupl. addr */
+#define RM6_DIRECTED	6		/* sending directed beacons */
+#define RM7_TRACE	7		/* trace initiated */
+#endif
+
+struct pcm_state {
+	unsigned char	pcm_type ;		/* TA TB TS TM */
+	unsigned char	pcm_state ;		/* state PC[0-9]_* */
+	unsigned char	pcm_mode ;		/* PM_{NONE,PEER,TREE} */
+	unsigned char	pcm_neighbor ;		/* TA TB TS TM */
+	unsigned char	pcm_bsf ;		/* flag bs : TRUE/FALSE */
+	unsigned char	pcm_lsf ;		/* flag ls : TRUE/FALSE */
+	unsigned char	pcm_lct_fail ;		/* counter lct_fail */
+	unsigned char	pcm_ls_rx ;		/* rx line state */
+	short		pcm_r_val ;		/* signaling bits */
+	short		pcm_t_val ;		/* signaling bits */
+} ;
+
+struct smt_state {
+	struct pcm_state pcm_state[NUMPHYS] ;	/* port A & port B */
+} ;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/supern_2.h linux.18p8/drivers/net/skfp/h/supern_2.h
--- linux.vanilla/drivers/net/skfp/h/supern_2.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/supern_2.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,1059 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	defines for AMD Supernet II chip set
+	the chips are refered to as
+		FPLUS	Formac Plus
+		PLC	Physical Layer
+
+	added defines for AMD Supernet III chip set
+	added comments on differences between Supernet II and Supernet III
+	added defines for the Motorola ELM (MOT_ELM)
+*/
+
+#ifndef	_SUPERNET_
+#define _SUPERNET_
+
+/*
+ * Define Supernet 3 when used
+ */
+#ifdef	PCI
+#ifndef	SUPERNET_3
+#define	SUPERNET_3
+#endif
+#define TAG
+#endif
+
+#define	MB	0xff
+#define	MW	0xffff
+#define	MD	0xffffffff
+
+/*
+ * FORMAC frame status (rx_msext)
+ */
+#define	FS_EI		(1<<2)
+#define	FS_AI		(1<<1)
+#define	FS_CI		(1<<0)
+
+#define FS_MSVALID	(1<<15)		/* end of queue */
+#define FS_MSRABT	(1<<14)		/* frame was aborted during reception*/
+#define FS_SSRCRTG	(1<<12)		/* if SA has set MSB (source-routing)*/
+#define FS_SEAC2	(FS_EI<<9)	/* error indicator */
+#define FS_SEAC1	(FS_AI<<9)	/* address indicator */
+#define FS_SEAC0	(FS_CI<<9)	/* copy indicator */
+#define FS_SFRMERR	(1<<8)		/* error detected (CRC or length) */
+#define FS_SADRRG	(1<<7)		/* address recognized */
+#define FS_SFRMTY2	(1<<6)		/* frame-class bit */
+#define FS_SFRMTY1	(1<<5)		/* frame-type bit (impementor) */
+#define FS_SFRMTY0	(1<<4)		/* frame-type bit (LLC) */
+#define FS_ERFBB1	(1<<1)		/* byte offset (depends on LSB bit) */
+#define FS_ERFBB0	(1<<0)		/*  - " - */
+
+/*
+ * status frame type
+ */
+#define	FRM_SMT		(0)	/* asynchr. frames */
+#define	FRM_LLCA	(1)
+#define	FRM_IMPA	(2)	
+#define	FRM_MAC		(4)	/* synchr. frames */
+#define	FRM_LLCS	(5)
+#define	FRM_IMPS	(6)
+
+/*
+ * bits in rx_descr.i	(receive frame status word)
+ */
+#define RX_MSVALID	((long)1<<31)	/* memory status valid */
+#define RX_MSRABT	((long)1<<30)	/* memory status receive abort */
+#define RX_FS_E		((long)FS_SEAC2<<16)	/* error indicator */
+#define RX_FS_A		((long)FS_SEAC1<<16)	/* address indicator */
+#define RX_FS_C		((long)FS_SEAC0<<16)	/* copy indicator */
+#define RX_FS_CRC	((long)FS_SFRMERR<<16)/* error detected */
+#define RX_FS_ADDRESS	((long)FS_SADRRG<<16)	/* address recognized */
+#define RX_FS_MAC	((long)FS_SFRMTY2<<16)/* MAC frame */
+#define RX_FS_SMT	((long)0<<16)		/* SMT frame */
+#define RX_FS_IMPL	((long)FS_SFRMTY1<<16)/* implementer frame */
+#define RX_FS_LLC	((long)FS_SFRMTY0<<16)/* LLC frame */
+
+/*
+ * receive frame descriptor
+ */
+union rx_descr {
+	struct {
+#ifdef	LITTLE_ENDIAN
+	unsigned	rx_length :16 ;	/* frame length lower/upper byte */
+	unsigned	rx_erfbb  :2 ;	/* received frame byte boundary */
+	unsigned	rx_reserv2:2 ;	/* reserved */	
+	unsigned	rx_sfrmty :3 ;	/* frame type bits */
+	unsigned	rx_sadrrg :1 ;	/* DA == MA or broad-/multicast */
+	unsigned	rx_sfrmerr:1 ;	/* received frame not valid */
+	unsigned	rx_seac0  :1 ;	/* frame-copied  C-indicator */
+	unsigned	rx_seac1  :1 ;	/* address-match A-indicator */
+	unsigned	rx_seac2  :1 ;	/* frame-error   E-indicator */
+	unsigned	rx_ssrcrtg:1 ;	/* == 1 SA has MSB set */
+	unsigned	rx_reserv1:1 ;	/* reserved */	
+	unsigned	rx_msrabt :1 ;	/* memory status receive abort */
+	unsigned	rx_msvalid:1 ;	/* memory status valid */
+#else
+	unsigned	rx_msvalid:1 ;	/* memory status valid */
+	unsigned	rx_msrabt :1 ;	/* memory status receive abort */
+	unsigned	rx_reserv1:1 ;	/* reserved */	
+	unsigned	rx_ssrcrtg:1 ;	/* == 1 SA has MSB set */
+	unsigned	rx_seac2  :1 ;	/* frame-error   E-indicator */
+	unsigned	rx_seac1  :1 ;	/* address-match A-indicator */
+	unsigned	rx_seac0  :1 ;	/* frame-copied  C-indicator */
+	unsigned	rx_sfrmerr:1 ;	/* received frame not valid */
+	unsigned	rx_sadrrg :1 ;	/* DA == MA or broad-/multicast */
+	unsigned	rx_sfrmty :3 ;	/* frame type bits */
+	unsigned	rx_erfbb  :2 ;	/* received frame byte boundary */
+	unsigned	rx_reserv2:2 ;	/* reserved */	
+	unsigned	rx_length :16 ;	/* frame length lower/upper byte */
+#endif
+	} r ;
+	long	i ;
+} ;
+
+/* defines for Receive Frame Descriptor access */
+#define RD_S_ERFBB	0x00030000L	/* received frame byte boundary */
+#define RD_S_RES2	0x000c0000L	/* reserved */
+#define RD_S_SFRMTY	0x00700000L	/* frame type bits */
+#define RD_S_SADRRG	0x00800000L	/* DA == MA or broad-/multicast */
+#define RD_S_SFRMERR	0x01000000L	/* received frame not valid */
+#define	RD_S_SEAC	0x0e000000L	/* frame status indicators */
+#define RD_S_SEAC0	0x02000000L	/* frame-copied  case-indicator */
+#define RD_S_SEAC1	0x04000000L	/* address-match A-indicator */
+#define RD_S_SEAC2	0x08000000L	/* frame-error   E-indicator */
+#define RD_S_SSRCRTG	0x10000000L	/* == 1 SA has MSB set */
+#define RD_S_RES1	0x20000000L	/* reserved */
+#define RD_S_MSRABT	0x40000000L	/* memory status receive abort */
+#define RD_S_MSVALID	0x80000000L	/* memory status valid */
+
+#define	RD_STATUS	0xffff0000L
+#define	RD_LENGTH	0x0000ffffL
+
+/* defines for Receive Frames Status Word values */
+/*RD_S_SFRMTY*/
+#define RD_FRM_SMT	(unsigned long)(0<<20)     /* asynchr. frames */
+#define RD_FRM_LLCA	(unsigned long)(1<<20)
+#define RD_FRM_IMPA	(unsigned long)(2<<20)
+#define RD_FRM_MAC	(unsigned long)(4<<20)     /* synchr. frames */
+#define RD_FRM_LLCS	(unsigned long)(5<<20)
+#define RD_FRM_IMPS	(unsigned long)(6<<20)
+
+#define TX_DESCRIPTOR	0x40000000L
+#define TX_OFFSET_3	0x18000000L
+
+#define TXP1	2
+
+/*
+ * transmit frame descriptor
+ */
+union tx_descr {
+	struct {
+#ifdef	LITTLE_ENDIAN
+	unsigned	tx_length:16 ;	/* frame length lower/upper byte */
+	unsigned	tx_res	 :8 ;	/* reserved 	 (bit 16..23) */
+	unsigned	tx_xmtabt:1 ;	/* transmit abort */
+	unsigned	tx_nfcs  :1 ;	/* no frame check sequence */
+	unsigned	tx_xdone :1 ;	/* give up token */
+	unsigned	tx_rpxm  :2 ;	/* byte offset */
+	unsigned	tx_pat1  :2 ;	/* must be TXP1 */
+	unsigned	tx_more	 :1 ;	/* more frame in chain */
+#else
+	unsigned	tx_more	 :1 ;	/* more frame in chain */
+	unsigned	tx_pat1  :2 ;	/* must be TXP1 */
+	unsigned	tx_rpxm  :2 ;	/* byte offset */
+	unsigned	tx_xdone :1 ;	/* give up token */
+	unsigned	tx_nfcs  :1 ;	/* no frame check sequence */
+	unsigned	tx_xmtabt:1 ;	/* transmit abort */
+	unsigned	tx_res	 :8 ;	/* reserved 	 (bit 16..23) */
+	unsigned	tx_length:16 ;	/* frame length lower/upper byte */
+#endif
+	} t ;
+	long	i ;
+} ;
+
+/* defines for Transmit Descriptor access */
+#define	TD_C_MORE	0x80000000L	/* more frame in chain */
+#define	TD_C_DESCR	0x60000000L	/* must be TXP1 */
+#define	TD_C_TXFBB	0x18000000L	/* byte offset */
+#define	TD_C_XDONE	0x04000000L	/* give up token */
+#define TD_C_NFCS	0x02000000L	/* no frame check sequence */
+#define TD_C_XMTABT	0x01000000L	/* transmit abort */
+
+#define	TD_C_LNCNU	0x0000ff00L	
+#define TD_C_LNCNL	0x000000ffL
+#define TD_C_LNCN	0x0000ffffL	/* frame length lower/upper byte */
+ 
+/*
+ * transmit pointer
+ */
+union tx_pointer {
+	struct t {
+#ifdef	LITTLE_ENDIAN
+	unsigned	tp_pointer:16 ;	/* pointer to tx_descr (low/high) */
+	unsigned	tp_res	  :8 ;	/* reserved 	 (bit 16..23) */
+	unsigned	tp_pattern:8 ;	/* fixed pattern (bit 24..31) */
+#else
+	unsigned	tp_pattern:8 ;	/* fixed pattern (bit 24..31) */
+	unsigned	tp_res	  :8 ;	/* reserved 	 (bit 16..23) */
+	unsigned	tp_pointer:16 ;	/* pointer to tx_descr (low/high) */
+#endif
+	} t ;
+	long	i ;
+} ;
+
+/* defines for Nontag Mode Pointer access */
+#define	TD_P_CNTRL	0xff000000L
+#define TD_P_RPXU	0x0000ff00L
+#define TD_P_RPXL	0x000000ffL
+#define TD_P_RPX	0x0000ffffL
+
+
+#define TX_PATTERN	0xa0
+#define TX_POINTER_END	0xa0000000L
+#define TX_INT_PATTERN	0xa0000000L
+
+struct tx_queue {
+	struct tx_queue *tq_next ;
+	u_short tq_pack_offset ;	/* offset buffer memory */
+	u_char  tq_pad[2] ;
+} ;
+
+/*
+	defines for FORMAC Plus (Am79C830)
+*/
+
+/*
+ *  FORMAC+ read/write (r/w) registers
+ */
+#define FM_CMDREG1	0x00		/* write command reg 1 instruction */
+#define FM_CMDREG2	0x01		/* write command reg 2 instruction */
+#define FM_ST1U		0x00		/* read upper 16-bit of status reg 1 */
+#define FM_ST1L		0x01		/* read lower 16-bit of status reg 1 */
+#define FM_ST2U		0x02		/* read upper 16-bit of status reg 2 */
+#define FM_ST2L		0x03		/* read lower 16-bit of status reg 2 */
+#define FM_IMSK1U	0x04		/* r/w upper 16-bit of IMSK 1 */
+#define FM_IMSK1L	0x05		/* r/w lower 16-bit of IMSK 1 */
+#define FM_IMSK2U	0x06		/* r/w upper 16-bit of IMSK 2 */
+#define FM_IMSK2L	0x07		/* r/w lower 16-bit of IMSK 2 */
+#define FM_SAID		0x08		/* r/w short addr.-individual */
+#define FM_LAIM		0x09		/* r/w long addr.-ind. (MSW of LAID) */
+#define FM_LAIC		0x0a		/* r/w long addr.-ind. (middle)*/
+#define FM_LAIL		0x0b		/* r/w long addr.-ind. (LSW) */
+#define FM_SAGP		0x0c		/* r/w short address-group */
+#define FM_LAGM		0x0d		/* r/w long addr.-gr. (MSW of LAGP) */
+#define FM_LAGC		0x0e		/* r/w long addr.-gr. (middle) */
+#define FM_LAGL		0x0f		/* r/w long addr.-gr. (LSW) */
+#define FM_MDREG1	0x10		/* r/w 16-bit mode reg 1 */
+#define FM_STMCHN	0x11		/* read state-machine reg */
+#define FM_MIR1		0x12		/* read upper 16-bit of MAC Info Reg */
+#define FM_MIR0		0x13		/* read lower 16-bit of MAC Info Reg */
+#define FM_TMAX		0x14		/* r/w 16-bit TMAX reg */
+#define FM_TVX		0x15		/* write 8-bit TVX reg with NP7-0
+					   read TVX on NP7-0, timer on NP15-8*/
+#define FM_TRT		0x16		/* r/w upper 16-bit of TRT timer */
+#define FM_THT		0x17		/* r/w upper 16-bit of THT timer */
+#define FM_TNEG		0x18		/* read upper 16-bit of TNEG (TTRT) */
+#define FM_TMRS		0x19		/* read lower 5-bit of TNEG,TRT,THT */
+			/* F E D C  B A 9 8  7 6 5 4  3 2 1 0
+			   x |-TNEG4-0| |-TRT4-0-| |-THT4-0-| (x-late count) */
+#define FM_TREQ0	0x1a		/* r/w 16-bit TREQ0 reg (LSW of TRT) */
+#define FM_TREQ1	0x1b		/* r/w 16-bit TREQ1 reg (MSW of TRT) */
+#define FM_PRI0		0x1c		/* r/w priority r. for asyn.-queue 0 */
+#define FM_PRI1		0x1d		/* r/w priority r. for asyn.-queue 1 */
+#define FM_PRI2		0x1e		/* r/w priority r. for asyn.-queue 2 */
+#define FM_TSYNC	0x1f		/* r/w 16-bit of the TSYNC register */
+#define FM_MDREG2	0x20		/* r/w 16-bit mode reg 2 */
+#define FM_FRMTHR	0x21		/* r/w the frame threshold register */
+#define FM_EACB		0x22		/* r/w end addr of claim/beacon area */
+#define FM_EARV		0x23		/* r/w end addr of receive queue */
+/* Supernet 3 */
+#define	FM_EARV1	FM_EARV
+
+#define FM_EAS		0x24		/* r/w end addr of synchr. queue */
+#define FM_EAA0		0x25		/* r/w end addr of asyn. queue 0 */
+#define FM_EAA1		0x26		/* r/w end addr of asyn. queue 1 */
+#define FM_EAA2		0x27		/* r/w end addr of asyn. queue 2 */
+#define FM_SACL		0x28		/* r/w start addr of claim frame */
+#define FM_SABC		0x29		/* r/w start addr of beacon frame */
+#define FM_WPXSF	0x2a		/* r/w the write ptr. for special fr.*/
+#define FM_RPXSF	0x2b		/* r/w the read ptr. for special fr. */
+#define FM_RPR		0x2d		/* r/w the read ptr. for receive qu. */
+#define FM_WPR		0x2e		/* r/w the write ptr. for receive qu.*/
+#define FM_SWPR		0x2f		/* r/w the shadow wr.-ptr. for rec.q.*/
+/* Supernet 3 */ 
+#define FM_RPR1         FM_RPR   
+#define FM_WPR1         FM_WPR 
+#define FM_SWPR1        FM_SWPR
+
+#define FM_WPXS		0x30		/* r/w the write ptr. for synchr. qu.*/
+#define FM_WPXA0	0x31		/* r/w the write ptr. for asyn. qu.0 */
+#define FM_WPXA1	0x32		/* r/w the write ptr. for asyn. qu.1 */
+#define FM_WPXA2	0x33		/* r/w the write ptr. for asyn. qu.2 */
+#define FM_SWPXS	0x34		/* r/w the shadow wr.-ptr. for syn.q.*/
+#define FM_SWPXA0	0x35		/* r/w the shad. wr.-ptr. for asyn.q0*/
+#define FM_SWPXA1	0x36		/* r/w the shad. wr.-ptr. for asyn.q1*/
+#define FM_SWPXA2	0x37		/* r/w the shad. wr.-ptr. for asyn.q2*/
+#define FM_RPXS		0x38		/* r/w the read ptr. for synchr. qu. */
+#define FM_RPXA0	0x39		/* r/w the read ptr. for asyn. qu. 0 */
+#define FM_RPXA1	0x3a		/* r/w the read ptr. for asyn. qu. 1 */
+#define FM_RPXA2	0x3b		/* r/w the read ptr. for asyn. qu. 2 */
+#define FM_MARR		0x3c		/* r/w the memory read addr register */
+#define FM_MARW		0x3d		/* r/w the memory write addr register*/
+#define FM_MDRU		0x3e		/* r/w upper 16-bit of mem. data reg */
+#define FM_MDRL		0x3f		/* r/w lower 16-bit of mem. data reg */
+
+/* following instructions relate to MAC counters and timer */
+#define FM_TMSYNC	0x40		/* r/w upper 16 bits of TMSYNC timer */
+#define FM_FCNTR	0x41		/* r/w the 16-bit frame counter */
+#define FM_LCNTR	0x42		/* r/w the 16-bit lost counter */
+#define FM_ECNTR	0x43		/* r/w the 16-bit error counter */
+
+/* Supernet 3:	extensions to old register block */
+#define	FM_FSCNTR	0x44		/* r/? Frame Strip Counter */
+#define	FM_FRSELREG	0x45		/* r/w Frame Selection Register */
+
+/* Supernet 3:	extensions for 2. receive queue etc. */
+#define	FM_MDREG3	0x60		/* r/w Mode Register 3 */
+#define	FM_ST3U		0x61		/* read upper 16-bit of status reg 3 */
+#define	FM_ST3L		0x62		/* read lower 16-bit of status reg 3 */
+#define	FM_IMSK3U	0x63		/* r/w upper 16-bit of IMSK reg 3 */
+#define	FM_IMSK3L	0x64		/* r/w lower 16-bit of IMSK reg 3 */
+#define	FM_IVR		0x65		/* read Interrupt Vector register */
+#define	FM_IMR		0x66		/* r/w Interrupt mask register */
+/* 0x67	Hidden */
+#define	FM_RPR2		0x68		/* r/w the read ptr. for rec. qu. 2 */
+#define	FM_WPR2		0x69		/* r/w the write ptr. for rec. qu. 2 */
+#define	FM_SWPR2	0x6a		/* r/w the shadow wptr. for rec. q. 2 */
+#define	FM_EARV2	0x6b		/* r/w end addr of rec. qu. 2 */
+#define	FM_UNLCKDLY	0x6c		/* r/w Auto Unlock Delay register */
+					/* Bit 15-8: RECV2 unlock threshold */
+					/* Bit  7-0: RECV1 unlock threshold */
+/* 0x6f-0x73	Hidden */
+#define	FM_LTDPA1	0x79		/* r/w Last Trans desc ptr for A1 qu. */
+/* 0x80-0x9a	PLCS registers of built-in PLCS  (Supernet 3 only) */
+
+/* Supernet 3: Adderss Filter Registers */
+#define	FM_AFCMD	0xb0		/* r/w Address Filter Command Reg */
+#define	FM_AFSTAT	0xb2		/* r/w Address Filter Status Reg */
+#define	FM_AFBIST	0xb4		/* r/w Address Filter BIST signature */
+#define	FM_AFCOMP2	0xb6		/* r/w Address Filter Comparand 2 */
+#define	FM_AFCOMP1	0xb8		/* r/w Address Filter Comparand 1 */
+#define	FM_AFCOMP0	0xba		/* r/w Address Filter Comparand 0 */
+#define	FM_AFMASK2	0xbc		/* r/w Address Filter Mask 2 */
+#define	FM_AFMASK1	0xbe		/* r/w Address Filter Mask 1 */
+#define	FM_AFMASK0	0xc0		/* r/w Address Filter Mask 0 */
+#define	FM_AFPERS	0xc2		/* r/w Address Filter Personality Reg */
+
+/* Supernet 3: Orion (PDX?) Registers */
+#define	FM_ORBIST	0xd0		/* r/w Orion BIST signature */
+#define	FM_ORSTAT	0xd2		/* r/w Orion Status Register */
+
+
+/*
+ * Mode Register 1 (MDREG1)
+ */
+#define FM_RES0		0x0001		/* reserved */
+					/* SN3: other definition */
+#define	FM_XMTINH_HOLD	0x0002		/* transmit-inhibit/hold bit */
+					/* SN3: other definition */
+#define	FM_HOFLXI	0x0003		/* SN3: Hold / Flush / Inhibit */
+#define	FM_FULL_HALF	0x0004		/* full-duplex/half-duplex bit */
+#define	FM_LOCKTX	0x0008		/* lock-transmit-asynchr.-queues bit */
+#define FM_EXGPA0	0x0010		/* extended-group-addressing bit 0 */
+#define FM_EXGPA1	0x0020		/* extended-group-addressing bit 1 */
+#define FM_DISCRY	0x0040		/* disable-carry bit */
+					/* SN3: reserved */
+#define FM_SELRA	0x0080		/* select input from PHY (1=RA,0=RB) */
+
+#define FM_ADDET	0x0700		/* address detection */
+#define FM_MDAMA	(0<<8)		/* address detection : DA = MA */
+#define FM_MDASAMA	(1<<8)		/* address detection : DA=MA||SA=MA */
+#define	FM_MRNNSAFNMA	(2<<8)		/* rec. non-NSA frames DA=MA&&SA!=MA */
+#define	FM_MRNNSAF	(3<<8)		/* rec. non-NSA frames DA = MA */
+#define	FM_MDISRCV	(4<<8)		/* disable receive function */
+#define	FM_MRES0	(5<<8)		/* reserve */
+#define	FM_MLIMPROM	(6<<8)		/* limited-promiscuous mode */
+#define FM_MPROMISCOUS	(7<<8)		/* address detection : promiscous */
+
+#define FM_SELSA	0x0800		/* select-short-address bit */
+
+#define FM_MMODE	0x7000		/* mode select */
+#define FM_MINIT	(0<<12)		/* initialize */
+#define FM_MMEMACT	(1<<12)		/* memory activate */
+#define FM_MONLINESP	(2<<12)		/* on-line special */
+#define FM_MONLINE	(3<<12)		/* on-line (FDDI operational mode) */
+#define FM_MILOOP	(4<<12)		/* internal loopback */
+#define FM_MRES1	(5<<12)		/* reserved */
+#define FM_MRES2	(6<<12)		/* reserved */
+#define FM_MELOOP	(7<<12)		/* external loopback */
+
+#define	FM_SNGLFRM	0x8000		/* single-frame-receive mode */
+					/* SN3: reserved */
+
+#define	MDR1INIT	(FM_MINIT | FM_MDAMA)
+
+/*
+ * Mode Register 2 (MDREG2)
+ */
+#define	FM_AFULL	0x000f		/* 4-bit value (empty loc.in txqueue)*/
+#define	FM_RCVERR	0x0010		/* rec.-errored-frames bit */
+#define	FM_SYMCTL	0x0020		/* sysmbol-control bit */
+					/* SN3: reserved */
+#define	FM_SYNPRQ	0x0040		/* synchron.-NP-DMA-request bit */
+#define	FM_ENNPRQ	0x0080		/* enable-NP-DMA-request bit */
+#define	FM_ENHSRQ	0x0100		/* enable-host-request bit */
+#define	FM_RXFBB01	0x0600		/* rec. frame byte boundary bit0 & 1 */
+#define	FM_LSB		0x0800		/* determ. ordering of bytes in buffer*/
+#define	FM_PARITY	0x1000		/* 1 = even, 0 = odd */
+#define	FM_CHKPAR	0x2000		/* 1 = parity of 32-bit buffer BD-bus*/
+#define	FM_STRPFCS	0x4000		/* 1 = strips FCS field of rec.frame */
+#define	FM_BMMODE	0x8000		/* Buffer-Memory-Mode (1 = tag mode) */
+					/* SN3: 1 = tag, 0 = modified tag */
+
+/*
+ * Status Register 1, Upper 16 Bits (ST1U)
+ */
+#define FM_STEFRMS	0x0001		/* transmit end of frame: synchr. qu.*/
+#define FM_STEFRMA0	0x0002		/* transmit end of frame: asyn. qu.0 */
+#define FM_STEFRMA1	0x0004		/* transmit end of frame: asyn. qu.1 */
+#define FM_STEFRMA2	0x0008		/* transmit end of frame: asyn. qu.2 */
+					/* SN3: reserved */
+#define FM_STECFRMS	0x0010		/* transmit end of chain of syn. qu. */
+					/* SN3: reserved */
+#define FM_STECFRMA0	0x0020		/* transmit end of chain of asyn. q0 */
+					/* SN3: reserved */
+#define FM_STECFRMA1	0x0040		/* transmit end of chain of asyn. q1 */
+					/* SN3: STECMDA1 */
+#define FM_STECMDA1	0x0040		/* SN3: 'no description' */
+#define FM_STECFRMA2	0x0080		/* transmit end of chain of asyn. q2 */
+					/* SN3: reserved */
+#define	FM_STEXDONS	0x0100		/* transmit until XDONE in syn. qu. */
+#define	FM_STBFLA	0x0200		/* asynchr.-queue trans. buffer full */
+#define	FM_STBFLS	0x0400		/* synchr.-queue transm. buffer full */
+#define	FM_STXABRS	0x0800		/* synchr. queue transmit-abort */
+#define	FM_STXABRA0	0x1000		/* asynchr. queue 0 transmit-abort */
+#define	FM_STXABRA1	0x2000		/* asynchr. queue 1 transmit-abort */
+#define	FM_STXABRA2	0x4000		/* asynchr. queue 2 transmit-abort */
+					/* SN3: reserved */
+#define	FM_SXMTABT	0x8000		/* transmit abort */
+
+/*
+ * Status Register 1, Lower 16 Bits (ST1L)
+ */
+#define FM_SQLCKS	0x0001		/* queue lock for synchr. queue */
+#define FM_SQLCKA0	0x0002		/* queue lock for asynchr. queue 0 */
+#define FM_SQLCKA1	0x0004		/* queue lock for asynchr. queue 1 */
+#define FM_SQLCKA2	0x0008		/* queue lock for asynchr. queue 2 */
+					/* SN3: reserved */
+#define FM_STXINFLS	0x0010		/* transmit instruction full: syn. */
+					/* SN3: reserved */
+#define FM_STXINFLA0	0x0020		/* transmit instruction full: asyn.0 */
+					/* SN3: reserved */
+#define FM_STXINFLA1	0x0040		/* transmit instruction full: asyn.1 */
+					/* SN3: reserved */
+#define FM_STXINFLA2	0x0080		/* transmit instruction full: asyn.2 */
+					/* SN3: reserved */
+#define FM_SPCEPDS	0x0100		/* parity/coding error: syn. queue */
+#define FM_SPCEPDA0	0x0200		/* parity/coding error: asyn. queue0 */
+#define FM_SPCEPDA1	0x0400		/* parity/coding error: asyn. queue1 */
+#define FM_SPCEPDA2	0x0800		/* parity/coding error: asyn. queue2 */
+					/* SN3: reserved */
+#define FM_STBURS	0x1000		/* transmit buffer underrun: syn. q. */
+#define FM_STBURA0	0x2000		/* transmit buffer underrun: asyn.0 */
+#define FM_STBURA1	0x4000		/* transmit buffer underrun: asyn.1 */
+#define FM_STBURA2	0x8000		/* transmit buffer underrun: asyn.2 */
+					/* SN3: reserved */
+
+/*
+ * Status Register 2, Upper 16 Bits (ST2U)
+ */
+#define FM_SOTRBEC	0x0001		/* other beacon received */
+#define FM_SMYBEC	0x0002		/* my beacon received */
+#define FM_SBEC		0x0004		/* beacon state entered */
+#define FM_SLOCLM	0x0008		/* low claim received */
+#define FM_SHICLM	0x0010		/* high claim received */
+#define FM_SMYCLM	0x0020		/* my claim received */
+#define FM_SCLM		0x0040		/* claim state entered */
+#define FM_SERRSF	0x0080		/* error in special frame */
+#define FM_SNFSLD	0x0100		/* NP and FORMAC+ simultaneous load */
+#define FM_SRFRCTOV	0x0200		/* receive frame counter overflow */
+					/* SN3: reserved */
+#define FM_SRCVFRM	0x0400		/* receive frame */
+					/* SN3: reserved */
+#define FM_SRCVOVR	0x0800		/* receive FIFO overflow */
+#define FM_SRBFL	0x1000		/* receive buffer full */
+#define FM_SRABT	0x2000		/* receive abort */
+#define FM_SRBMT	0x4000		/* receive buffer empty */
+#define FM_SRCOMP	0x8000		/* receive complete. Nontag mode */
+
+/*
+ * Status Register 2, Lower 16 Bits (ST2L)
+ * Attention: SN3 docu shows these bits the other way around
+ */
+#define FM_SRES0	0x0001		/* reserved */
+#define FM_SESTRIPTK	0x0001		/* SN3: 'no description' */
+#define FM_STRTEXR	0x0002		/* TRT expired in claim | beacon st. */
+#define FM_SDUPCLM	0x0004		/* duplicate claim received */
+#define FM_SSIFG	0x0008		/* short interframe gap */
+#define FM_SFRMCTR	0x0010		/* frame counter overflow */
+#define FM_SERRCTR	0x0020		/* error counter overflow */
+#define FM_SLSTCTR	0x0040		/* lost counter overflow */
+#define FM_SPHINV	0x0080		/* PHY invalid */
+#define FM_SADET	0x0100		/* address detect */
+#define FM_SMISFRM	0x0200		/* missed frame */
+#define FM_STRTEXP	0x0400		/* TRT expired and late count > 0 */
+#define FM_STVXEXP	0x0800		/* TVX expired */
+#define FM_STKISS	0x1000		/* token issued */
+#define FM_STKERR	0x2000		/* token error */
+#define FM_SMULTDA	0x4000		/* multiple destination address */
+#define FM_SRNGOP	0x8000		/* ring operational */
+
+/*
+ * Supernet 3:
+ * Status Register 3, Upper 16 Bits (ST3U)
+ */
+#define	FM_SRQUNLCK1	0x0001		/* receive queue unlocked queue 1 */
+#define	FM_SRQUNLCK2	0x0002		/* receive queue unlocked queue 2 */
+#define	FM_SRPERRQ1	0x0004		/* receive parity error rx queue 1 */
+#define	FM_SRPERRQ2	0x0008		/* receive parity error rx queue 2 */
+					/* Bit 4-10: reserved */
+#define	FM_SRCVOVR2	0x0800		/* receive FIFO overfull rx queue 2 */
+#define	FM_SRBFL2	0x1000		/* receive buffer full rx queue 2 */
+#define	FM_SRABT2	0x2000		/* receive abort rx queue 2 */
+#define	FM_SRBMT2	0x4000		/* receive buf empty rx queue 2 */
+#define	FM_SRCOMP2	0x8000		/* receive comp rx queue 2 */
+
+/*
+ * Supernet 3:
+ * Status Register 3, Lower 16 Bits (ST3L)
+ */
+#define	FM_AF_BIST_DONE		0x0001	/* Address Filter BIST is done */
+#define	FM_PLC_BIST_DONE	0x0002	/* internal PLC Bist is done */
+#define	FM_PDX_BIST_DONE	0x0004	/* PDX BIST is done */
+					/* Bit  3: reserved */
+#define	FM_SICAMDAMAT		0x0010	/* Status internal CAM DA match */
+#define	FM_SICAMDAXACT		0x0020	/* Status internal CAM DA exact match */
+#define	FM_SICAMSAMAT		0x0040	/* Status internal CAM SA match */
+#define	FM_SICAMSAXACT		0x0080	/* Status internal CAM SA exact match */
+
+/*
+ * MAC State-Machine Register FM_STMCHN
+ */
+#define	FM_MDRTAG	0x0004		/* tag bit of long word read */
+#define	FM_SNPPND	0x0008		/* r/w from buffer mem. is pending */
+#define	FM_TXSTAT	0x0070		/* transmitter state machine state */
+#define	FM_RCSTAT	0x0380		/* receiver state machine state */
+#define	FM_TM01		0x0c00		/* indicate token mode */
+#define	FM_SIM		0x1000		/* indicate send immediate-mode */
+#define	FM_REV		0xe000		/* FORMAC Plus revision number */
+
+/*
+ * Supernet 3
+ * Mode Register 3
+ */
+#define	FM_MENRS	0x0001		/* Ena enhanced rec status encoding */
+#define	FM_MENXS	0x0002		/* Ena enhanced xmit status encoding */
+#define	FM_MENXCT	0x0004		/* Ena EXACT/INEXACT matching */
+#define	FM_MENAFULL	0x0008		/* Ena enh QCTRL encoding for AFULL */
+#define	FM_MEIND	0x0030		/* Ena enh A,C indicator settings */
+#define	FM_MENQCTRL	0x0040		/* Ena enh QCTRL encoding */
+#define	FM_MENRQAUNLCK	0x0080		/* Ena rec q auto unlock */
+#define	FM_MENDAS	0x0100		/* Ena DAS connections by cntr MUX */
+#define	FM_MENPLCCST	0x0200		/* Ena Counter Segm test in PLC blck */
+#define	FM_MENSGLINT	0x0400		/* Ena Vectored Interrupt reading */
+#define	FM_MENDRCV	0x0800		/* Ena dual receive queue operation */
+#define	FM_MENFCLOC	0x3000		/* Ena FC location within frm data */
+#define	FM_MENTRCMD	0x4000		/* Ena ASYNC1 xmit only after command */
+#define	FM_MENTDLPBK	0x8000		/* Ena TDAT to RDAT lkoopback */
+
+/*
+ * Supernet 3
+ * Frame Selection Register
+ */
+#define	FM_RECV1	0x000f		/* options for receive queue 1 */
+#define	FM_RCV1_ALL	(0<<0)		/* receive all frames */
+#define	FM_RCV1_LLC	(1<<0)		/* rec all LLC frames */
+#define	FM_RCV1_SMT	(2<<0)		/* rec all SMT frames */
+#define	FM_RCV1_NSMT	(3<<0)		/* rec non-SMT frames */
+#define	FM_RCV1_IMP	(4<<0)		/* rec Implementor frames */
+#define	FM_RCV1_MAC	(5<<0)		/* rec all MAC frames */
+#define	FM_RCV1_SLLC	(6<<0)		/* rec all sync LLC frames */
+#define	FM_RCV1_ALLC	(7<<0)		/* rec all async LLC frames */
+#define	FM_RCV1_VOID	(8<<0)		/* rec all void frames */
+#define	FM_RCV1_ALSMT	(9<<0)		/* rec all async LLC & SMT frames */
+#define	FM_RECV2	0x00f0		/* options for receive queue 2 */
+#define	FM_RCV2_ALL	(0<<4)		/* receive all other frames */
+#define	FM_RCV2_LLC	(1<<4)		/* rec all LLC frames */
+#define	FM_RCV2_SMT	(2<<4)		/* rec all SMT frames */
+#define	FM_RCV2_NSMT	(3<<4)		/* rec non-SMT frames */
+#define	FM_RCV2_IMP	(4<<4)		/* rec Implementor frames */
+#define	FM_RCV2_MAC	(5<<4)		/* rec all MAC frames */
+#define	FM_RCV2_SLLC	(6<<4)		/* rec all sync LLC frames */
+#define	FM_RCV2_ALLC	(7<<4)		/* rec all async LLC frames */
+#define	FM_RCV2_VOID	(8<<4)		/* rec all void frames */
+#define	FM_RCV2_ALSMT	(9<<4)		/* rec all async LLC & SMT frames */
+#define	FM_ENXMTADSWAP	0x4000		/* enh rec addr swap (phys -> can) */
+#define	FM_ENRCVADSWAP	0x8000		/* enh tx addr swap (can -> phys) */
+
+/*
+ * Supernet 3:
+ * Address Filter Command Register (AFCMD)
+ */
+#define	FM_INST		0x0007		/* Address Filter Operation */
+#define FM_IINV_CAM	(0<<0)		/* Invalidate CAM */
+#define FM_IWRITE_CAM	(1<<0)		/* Write CAM */
+#define FM_IREAD_CAM	(2<<0)		/* Read CAM */
+#define FM_IRUN_BIST	(3<<0)		/* Run BIST */
+#define FM_IFIND	(4<<0)		/* Find */
+#define FM_IINV		(5<<0)		/* Invalidate */
+#define FM_ISKIP	(6<<0)		/* Skip */
+#define FM_ICL_SKIP	(7<<0)		/* Clear all SKIP bits */
+
+/*
+ * Supernet 3:
+ * Address Filter Status Register (AFSTAT)
+ */
+					/* Bit  0-4: reserved */
+#define	FM_REV_NO	0x00e0		/* Revision Number of Address Filter */
+#define	FM_BIST_DONE	0x0100		/* BIST complete */
+#define	FM_EMPTY	0x0200		/* CAM empty */
+#define	FM_ERROR	0x0400		/* Error (improper operation) */
+#define	FM_MULT		0x0800		/* Multiple Match */
+#define	FM_EXACT	0x1000		/* Exact Match */
+#define	FM_FOUND	0x2000		/* Comparand found in CAM */
+#define	FM_FULL		0x4000		/* CAM full */
+#define	FM_DONE		0x8000		/* DONE indicator */
+
+/*
+ * Supernet 3:
+ * BIST Signature Register (AFBIST)
+ */
+#define	AF_BIST_SIGNAT	0x0553		/* Address Filter BIST Signature */
+
+/*
+ * Supernet 3:
+ * Personality Register (AFPERS)
+ */
+#define	FM_VALID	0x0001		/* CAM Entry Valid */
+#define	FM_DA		0x0002		/* Destination Address */
+#define	FM_DAX		0x0004		/* Destination Address Exact */
+#define	FM_SA		0x0008		/* Source Address */
+#define	FM_SAX		0x0010		/* Source Address Exact */
+#define	FM_SKIP		0x0020		/* Skip this entry */
+
+/*
+ * instruction set for command register 1 (NPADDR6-0 = 0x00)
+ */
+#define FM_IRESET	0x01		/* software reset */
+#define FM_IRMEMWI	0x02		/* load Memory Data Reg., inc MARR */
+#define FM_IRMEMWO	0x03		/* load MDR from buffer memory, n.i. */
+#define FM_IIL		0x04		/* idle/listen */
+#define FM_ICL		0x05		/* claim/listen */
+#define FM_IBL		0x06		/* beacon/listen */
+#define FM_ILTVX	0x07		/* load TVX timer from TVX reg */
+#define FM_INRTM	0x08		/* nonrestricted token mode */
+#define FM_IENTM	0x09		/* enter nonrestricted token mode */
+#define FM_IERTM	0x0a		/* enter restricted token mode */
+#define FM_IRTM		0x0b		/* restricted token mode */
+#define FM_ISURT	0x0c		/* send unrestricted token */
+#define FM_ISRT		0x0d		/* send restricted token */
+#define FM_ISIM		0x0e		/* enter send-immediate mode */
+#define FM_IESIM	0x0f		/* exit send-immediate mode */
+#define FM_ICLLS	0x11		/* clear synchronous queue lock */
+#define FM_ICLLA0	0x12		/* clear asynchronous queue 0 lock */
+#define FM_ICLLA1	0x14		/* clear asynchronous queue 1 lock */
+#define FM_ICLLA2	0x18		/* clear asynchronous queue 2 lock */
+					/* SN3: reserved */
+#define FM_ICLLR	0x20		/* clear receive queue (SN3:1) lock */
+#define FM_ICLLR2	0x21		/* SN3: clear receive queue 2 lock */
+#define FM_ITRXBUS	0x22		/* SN3: Tristate X-Bus (SAS only) */
+#define FM_IDRXBUS	0x23		/* SN3: drive X-Bus */
+#define FM_ICLLAL	0x3f		/* clear all queue locks */
+
+/*
+ * instruction set for command register 2 (NPADDR6-0 = 0x01)
+ */
+#define FM_ITRS		0x01		/* transmit synchronous queue */
+					/* SN3: reserved */
+#define FM_ITRA0	0x02		/* transmit asynchronous queue 0 */
+					/* SN3: reserved */
+#define FM_ITRA1	0x04		/* transmit asynchronous queue 1 */
+					/* SN3: reserved */
+#define FM_ITRA2	0x08		/* transmit asynchronous queue 2 */
+					/* SN3: reserved */
+#define FM_IACTR	0x10		/* abort current transmit activity */
+#define FM_IRSTQ	0x20		/* reset transmit queues */
+#define FM_ISTTB	0x30		/* set tag bit */
+#define FM_IERSF	0x40		/* enable receive single frame */
+					/* SN3: reserved */
+#define	FM_ITR		0x50		/* SN3: Transmit Command */
+
+
+/*
+ *	defines for PLC (Am79C864)
+ */
+
+/*
+ *  PLC read/write (r/w) registers
+ */
+#define PL_CNTRL_A	0x00		/* control register A (r/w) */
+#define PL_CNTRL_B	0x01		/* control register B (r/w) */
+#define PL_INTR_MASK	0x02		/* interrupt mask (r/w) */
+#define PL_XMIT_VECTOR	0x03		/* transmit vector register (r/w) */
+#define PL_VECTOR_LEN	0x04		/* transmit vector length (r/w) */
+#define PL_LE_THRESHOLD	0x05		/* link error event threshold (r/w) */
+#define PL_C_MIN	0x06		/* minimum connect state time (r/w) */
+#define PL_TL_MIN	0x07		/* min. line state transmit t. (r/w) */
+#define PL_TB_MIN	0x08		/* minimum break time (r/w) */
+#define PL_T_OUT	0x09		/* signal timeout (r/w) */
+#define PL_CNTRL_C	0x0a		/* control register C (r/w) */
+#define PL_LC_LENGTH	0x0b		/* link confidence test time (r/w) */
+#define PL_T_SCRUB	0x0c		/* scrub time = MAC TVX (r/w) */
+#define PL_NS_MAX	0x0d		/* max. noise time before break (r/w)*/
+#define PL_TPC_LOAD_V	0x0e		/* TPC timer load value (write only) */
+#define PL_TNE_LOAD_V	0x0f		/* TNE timer load value (write only) */
+#define PL_STATUS_A	0x10		/* status register A (read only) */
+#define PL_STATUS_B	0x11		/* status register B (read only) */
+#define PL_TPC		0x12		/* timer for PCM (ro) [20.48 us] */
+#define PL_TNE		0x13		/* time of noise event [0.32 us] */
+#define PL_CLK_DIV	0x14		/* TNE clock divider (read only) */
+#define PL_BIST_SIGNAT	0x15		/* built in self test signature (ro)*/
+#define PL_RCV_VECTOR	0x16		/* receive vector reg. (read only) */
+#define PL_INTR_EVENT	0x17		/* interrupt event reg. (read only) */
+#define PL_VIOL_SYM_CTR	0x18		/* violation symbol count. (read o) */
+#define PL_MIN_IDLE_CTR	0x19		/* minimum idle counter (read only) */
+#define PL_LINK_ERR_CTR	0x1a		/* link error event ctr.(read only) */
+#ifdef	MOT_ELM
+#define	PL_T_FOT_ASS	0x1e		/* FOTOFF Assert Timer */
+#define	PL_T_FOT_DEASS	0x1f		/* FOTOFF Deassert Timer */
+#endif	/* MOT_ELM */
+
+#ifdef	MOT_ELM
+/*
+ * Special Quad-Elm Registers.
+ * A Quad-ELM consists of for ELMs and these additional registers.
+ */
+#define	QELM_XBAR_W	0x80		/* Crossbar Control ELM W */
+#define	QELM_XBAR_X	0x81		/* Crossbar Control ELM X */
+#define	QELM_XBAR_Y	0x82		/* Crossbar Control ELM Y */
+#define	QELM_XBAR_Z	0x83		/* Crossbar Control ELM Z */
+#define	QELM_XBAR_P	0x84		/* Crossbar Control Bus P */
+#define	QELM_XBAR_S	0x85		/* Crossbar Control Bus S */
+#define	QELM_XBAR_R	0x86		/* Crossbar Control Bus R */
+#define	QELM_WR_XBAR	0x87		/* Write the Crossbar now (write) */
+#define	QELM_CTR_W	0x88		/* Counter W */
+#define	QELM_CTR_X	0x89		/* Counter X */
+#define	QELM_CTR_Y	0x8a		/* Counter Y */
+#define	QELM_CTR_Z	0x8b		/* Counter Z */
+#define	QELM_INT_MASK	0x8c		/* Interrupt mask register */
+#define	QELM_INT_DATA	0x8d		/* Interrupt data (event) register */
+#define	QELM_ELMB	0x00		/* Elm base */
+#define	QELM_ELM_SIZE	0x20		/* ELM size */
+#endif	/* MOT_ELM */
+/*
+ * PLC control register A (PL_CNTRL_A: log. addr. 0x00)
+ * It is used for timer configuration, specification of PCM MAINT state option,
+ * counter interrupt frequency, PLC data path config. and Built In Self Test.
+ */
+#define	PL_RUN_BIST	0x0001		/* begin running its Built In Self T.*/
+#define	PL_RF_DISABLE	0x0002		/* disable the Repeat Filter state m.*/
+#define	PL_SC_REM_LOOP	0x0004		/* remote loopback path */
+#define	PL_SC_BYPASS	0x0008		/* by providing a physical bypass */
+#define	PL_LM_LOC_LOOP	0x0010		/* loop path just after elastic buff.*/
+#define	PL_EB_LOC_LOOP	0x0020		/* loop path just prior to PDT/PDR IF*/
+#define	PL_FOT_OFF	0x0040		/* assertion of /FOTOFF pin of PLC */
+#define	PL_LOOPBACK	0x0080		/* it cause the /LPBCK pin ass. low */
+#define	PL_MINI_CTR_INT 0x0100		/* partially contr. when bit is ass. */
+#define	PL_VSYM_CTR_INT	0x0200		/* controls when int bit is asserted */
+#define	PL_ENA_PAR_CHK	0x0400		/* enable parity check */
+#define	PL_REQ_SCRUB	0x0800		/* limited access to scrub capability*/
+#define	PL_TPC_16BIT	0x1000		/* causes the TPC as a 16 bit timer */
+#define	PL_TNE_16BIT	0x2000		/* causes the TNE as a 16 bit timer */
+#define	PL_NOISE_TIMER	0x4000		/* allows the noise timing function */
+
+/*
+ * PLC control register B (PL_CNTRL_B: log. addr. 0x01)
+ * It contains signals and requeste to direct the process of PCM and it is also
+ * used to control the Line State Match interrupt.
+ */
+#define	PL_PCM_CNTRL	0x0003		/* control PCM state machine */
+#define	PL_PCM_NAF	(0)		/* state is not affected */
+#define	PL_PCM_START	(1)		/* goes to the BREAK state */
+#define	PL_PCM_TRACE	(2)		/* goes to the TRACE state */
+#define	PL_PCM_STOP	(3)		/* goes to the OFF state */
+
+#define	PL_MAINT	0x0004		/* if OFF state --> MAINT state */
+#define	PL_LONG		0x0008		/* perf. a long Link Confid.Test(LCT)*/
+#define	PL_PC_JOIN	0x0010		/* if NEXT state --> JOIN state */
+
+#define	PL_PC_LOOP	0x0060		/* loopback used in the LCT */
+#define	PL_NOLCT	(0<<5)		/* no LCT is performed */
+#define	PL_TPDR		(1<<5)		/* PCM asserts transmit PDR */
+#define	PL_TIDLE	(2<<5)		/* PCM asserts transmit idle */
+#define	PL_RLBP		(3<<5)		/* trans. PDR & remote loopb. path */
+
+#define	PL_CLASS_S	0x0080		/* signif. that single att. station */
+
+#define	PL_MAINT_LS	0x0700		/* line state while in the MAINT st. */
+#define	PL_M_QUI0	(0<<8)		/* transmit QUIET line state */
+#define	PL_M_IDLE	(1<<8)		/* transmit IDLE line state */
+#define	PL_M_HALT	(2<<8)		/* transmit HALT line state */
+#define	PL_M_MASTR	(3<<8)		/* transmit MASTER line state */
+#define	PL_M_QUI1	(4<<8)		/* transmit QUIET line state */
+#define	PL_M_QUI2	(5<<8)		/* transmit QUIET line state */
+#define	PL_M_TPDR	(6<<8)		/* tr. PHY_DATA requ.-symbol is tr.ed*/
+#define	PL_M_QUI3	(7<<8)		/* transmit QUIET line state */
+
+#define	PL_MATCH_LS	0x7800		/* line state to be comp. with curr.*/
+#define	PL_I_ANY	(0<<11)		/* Int. on any change in *_LINE_ST */
+#define	PL_I_IDLE	(1<<11)		/* Interrupt on IDLE line state */
+#define	PL_I_HALT	(2<<11)		/* Interrupt on HALT line state */
+#define	PL_I_MASTR	(4<<11)		/* Interrupt on MASTER line state */
+#define	PL_I_QUIET	(8<<11)		/* Interrupt on QUIET line state */
+
+#define	PL_CONFIG_CNTRL	0x8000		/* control over scrub, byp. & loopb.*/
+
+/*
+ * PLC control register C (PL_CNTRL_C: log. addr. 0x0a)
+ * It contains the scrambling control registers (PLC-S only)
+ */
+#define PL_C_CIPHER_ENABLE	(1<<0)	/* enable scrambler */
+#define PL_C_CIPHER_LPBCK	(1<<1)	/* loopback scrambler */
+#define PL_C_SDOFF_ENABLE	(1<<6)	/* enable SDOFF timer */
+#define PL_C_SDON_ENABLE	(1<<7)	/* enable SDON timer */
+#ifdef	MOT_ELM
+#define PL_C_FOTOFF_CTRL	(3<<2)	/* FOTOFF timer control */
+#define PL_C_FOTOFF_TIM		(0<<2)	/* FOTOFF use timer for (de)-assert */
+#define PL_C_FOTOFF_INA		(2<<2)	/* FOTOFF forced inactive */
+#define PL_C_FOTOFF_ACT		(3<<2)	/* FOTOFF forced active */
+#define PL_C_FOTOFF_SRCE	(1<<4)	/* FOTOFF source is PCM state != OFF */
+#define	PL_C_RXDATA_EN		(1<<5)	/* Rec scr data forced to 0 */
+#define	PL_C_SDNRZEN		(1<<8)	/* Monitor rec descr. data for act */
+#else	/* nMOT_ELM */
+#define PL_C_FOTOFF_CTRL	(3<<8)	/* FOTOFF timer control */
+#define PL_C_FOTOFF_0		(0<<8)	/* timer off */
+#define PL_C_FOTOFF_30		(1<<8)	/* 30uS */
+#define PL_C_FOTOFF_50		(2<<8)	/* 50uS */
+#define PL_C_FOTOFF_NEVER	(3<<8)	/* never */
+#define PL_C_SDON_TIMER		(3<<10)	/* SDON timer control */
+#define PL_C_SDON_084		(0<<10)	/* 0.84 uS */
+#define PL_C_SDON_132		(1<<10)	/* 1.32 uS */
+#define PL_C_SDON_252		(2<<10)	/* 2.52 uS */
+#define PL_C_SDON_512		(3<<10)	/* 5.12 uS */
+#define PL_C_SOFF_TIMER		(3<<12)	/* SDOFF timer control */
+#define PL_C_SOFF_076		(0<<12)	/* 0.76 uS */
+#define PL_C_SOFF_132		(1<<12)	/* 1.32 uS */
+#define PL_C_SOFF_252		(2<<12)	/* 2.52 uS */
+#define PL_C_SOFF_512		(3<<12)	/* 5.12 uS */
+#define PL_C_TSEL		(3<<14)	/* scrambler path select */
+#endif	/* nMOT_ELM */
+
+/*
+ * PLC status register A (PL_STATUS_A: log. addr. 0x10)
+ * It is used to report status information to the Node Processor about the 
+ * Line State Machine (LSM).
+ */
+#ifdef	MOT_ELM
+#define PLC_INT_MASK	0xc000		/* ELM integration bits in status A */
+#define PLC_INT_C	0x0000		/* ELM Revision Band C */
+#define PLC_INT_CAMEL	0x4000		/* ELM integrated into CAMEL */
+#define PLC_INT_QE	0x8000		/* ELM integrated into Quad ELM */
+#define PLC_REV_MASK	0x3800		/* revision bits in status A */
+#define PLC_REVISION_B	0x0000		/* rev bits for ELM Rev B */
+#define PLC_REVISION_QA	0x0800		/* rev bits for ELM core in QELM-A */
+#else	/* nMOT_ELM */
+#define PLC_REV_MASK	0xf800		/* revision bits in status A */
+#define PLC_REVISION_A	0x0000		/* revision bits for PLC */
+#define PLC_REVISION_S	0xf800		/* revision bits for PLC-S */
+#define PLC_REV_SN3	0x7800		/* revision bits for PLC-S in IFCP */
+#endif	/* nMOT_ELM */
+#define	PL_SYM_PR_CTR	0x0007		/* contains the LSM symbol pair Ctr. */
+#define	PL_UNKN_LINE_ST	0x0008		/* unknown line state bit from LSM */
+#define	PL_LSM_STATE	0x0010		/* state bit of LSM */
+
+#define	PL_LINE_ST	0x00e0		/* contains recogn. line state of LSM*/
+#define	PL_L_NLS	(0<<5)		/* noise line state */
+#define	PL_L_ALS	(1<<5)		/* activ line state */
+#define	PL_L_UND	(2<<5)		/* undefined */
+#define	PL_L_ILS4	(3<<5)		/* idle l. s. (after 4 idle symbols) */
+#define	PL_L_QLS	(4<<5)		/* quiet line state */
+#define	PL_L_MLS	(5<<5)		/* master line state */
+#define	PL_L_HLS	(6<<5)		/* halt line state */
+#define	PL_L_ILS16	(7<<5)		/* idle line state (after 16 idle s.)*/
+
+#define	PL_PREV_LINE_ST	0x0300		/* value of previous line state */
+#define	PL_P_QLS	(0<<8)		/* quiet line state */
+#define	PL_P_MLS	(1<<8)		/* master line state */
+#define	PL_P_HLS	(2<<8)		/* halt line state */
+#define	PL_P_ILS16	(3<<8)		/* idle line state (after 16 idle s.)*/
+
+#define	PL_SIGNAL_DET	0x0400		/* 1=that signal detect is deasserted*/
+
+
+/*
+ * PLC status register B (PL_STATUS_B: log. addr. 0x11)
+ * It contains signals and status from the repeat filter and PCM state machine.
+ */
+#define	PL_BREAK_REASON	0x0007		/* reason for PCM state mach.s to br.*/
+#define	PL_B_NOT	(0)		/* PCM SM has not gone to BREAK state*/
+#define	PL_B_PCS	(1)		/* PC_Start issued */
+#define	PL_B_TPC	(2)		/* TPC timer expired after T_OUT */
+#define	PL_B_TNE	(3)		/* TNE timer expired after NS_MAX */
+#define	PL_B_QLS	(4)		/* quit line state detected */
+#define	PL_B_ILS	(5)		/* idle line state detected */
+#define	PL_B_HLS	(6)		/* halt line state detected */
+
+#define	PL_TCF		0x0008		/* transmit code flag (start exec.) */
+#define	PL_RCF		0x0010		/* receive code flag (start exec.) */
+#define	PL_LSF		0x0020		/* line state flag (l.s. has been r.)*/
+#define	PL_PCM_SIGNAL	0x0040		/* indic. that XMIT_VECTOR hb.written*/
+
+#define	PL_PCM_STATE	0x0780		/* state bits of PCM state machine */
+#define	PL_PC0		(0<<7)		/* OFF	   - when /RST or PCM_CNTRL */
+#define	PL_PC1		(1<<7)		/* BREAK   - entry point in start PCM*/
+#define	PL_PC2		(2<<7)		/* TRACE   - to localize stuck Beacon*/
+#define	PL_PC3		(3<<7)		/* CONNECT - synchronize ends of conn*/
+#define	PL_PC4		(4<<7)		/* NEXT	   - to seperate the signalng*/
+#define	PL_PC5		(5<<7)		/* SIGNAL  - PCM trans/rec. bit infos*/
+#define	PL_PC6		(6<<7)		/* JOIN	   - 1. state to activ conn. */
+#define	PL_PC7		(7<<7)		/* VERIFY  - 2. - " - (3. ACTIVE) */
+#define	PL_PC8		(8<<7)		/* ACTIVE  - PHY has been incorporated*/
+#define	PL_PC9		(9<<7)		/* MAINT   - for test purposes or so 
+					   that PCM op. completely in softw. */
+
+#define	PL_PCI_SCRUB	0x0800		/* scrubbing function is being exec. */
+
+#define	PL_PCI_STATE	0x3000		/* Physical Connect. Insertion SM */
+#define	PL_CI_REMV	(0<<12)		/* REMOVED */
+#define	PL_CI_ISCR	(1<<12)		/* INSERT_SCRUB */
+#define	PL_CI_RSCR	(2<<12)		/* REMOVE_SCRUB */
+#define	PL_CI_INS	(3<<12)		/* INSERTED */
+
+#define	PL_RF_STATE	0xc000		/* state bit of repeate filter SM */
+#define	PL_RF_REPT	(0<<14)		/* REPEAT */
+#define	PL_RF_IDLE	(1<<14)		/* IDLE */
+#define	PL_RF_HALT1	(2<<14)		/* HALT1 */
+#define	PL_RF_HALT2	(3<<14)		/* HALT2 */
+
+
+/*
+ * PLC interrupt event register (PL_INTR_EVENT: log. addr. 0x17)
+ * It is read only and is clearde whenever it is read!
+ * It is used by the PLC to report events to the node processor.
+ */
+#define	PL_PARITY_ERR	0x0001		/* p. error h.b.detected on TX9-0 inp*/
+#define	PL_LS_MATCH	0x0002		/* l.s.== l.s. PLC_CNTRL_B's MATCH_LS*/
+#define	PL_PCM_CODE	0x0004		/* transmit&receive | LCT complete */
+#define	PL_TRACE_PROP	0x0008		/* master l.s. while PCM ACTIV|TRACE */
+#define	PL_SELF_TEST	0x0010		/* QUIET|HALT while PCM in TRACE st. */
+#define	PL_PCM_BREAK	0x0020		/* PCM has entered the BREAK state */
+#define	PL_PCM_ENABLED	0x0040		/* asserted SC_JOIN, scrub. & ACTIV */
+#define	PL_TPC_EXPIRED	0x0080		/* TPC timer reached zero */
+#define	PL_TNE_EXPIRED	0x0100		/* TNE timer reached zero */
+#define	PL_EBUF_ERR	0x0200		/* elastic buff. det. over-|underflow*/
+#define	PL_PHYINV	0x0400		/* physical layer invalid signal */
+#define	PL_VSYM_CTR	0x0800		/* violation symbol counter has incr.*/
+#define	PL_MINI_CTR	0x1000		/* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
+#define	PL_LE_CTR	0x2000		/* link error event counter */
+#define	PL_LSDO		0x4000		/* SDO input pin changed to a 1 */
+#define	PL_NP_ERR	0x8000		/* NP has requested to r/w an inv. r.*/
+
+/*
+ * The PLC interrupt mask register (PL_INTR_MASK: log. addr. 0x02) constr. is
+ * equal PL_INTR_EVENT register.
+ * For each set bit, the setting of corresponding bit generate an int to NP. 
+ */
+
+#ifdef	MOT_ELM
+/*
+ * Quad ELM Crosbar Control register values (QELM_XBAR_?)
+ */
+#define	QELM_XOUT_IDLE	0x0000		/* Idles/Passthrough */
+#define	QELM_XOUT_P	0x0001		/* Output to: Bus P */
+#define	QELM_XOUT_S	0x0002		/* Output to: Bus S */
+#define	QELM_XOUT_R	0x0003		/* Output to: Bus R */
+#define	QELM_XOUT_W	0x0004		/* Output to: ELM W */
+#define	QELM_XOUT_X	0x0005		/* Output to: ELM X */
+#define	QELM_XOUT_Y	0x0006		/* Output to: ELM Y */
+#define	QELM_XOUT_Z	0x0007		/* Output to: ELM Z */
+
+/*
+ * Quad ELM Interrupt data and event registers.
+ */
+#define	QELM_NP_ERR	(1<<15)		/* Node Processor Error */
+#define	QELM_COUNT_Z	(1<<7)		/* Counter Z Interrupt */
+#define	QELM_COUNT_Y	(1<<6)		/* Counter Y Interrupt */
+#define	QELM_COUNT_X	(1<<5)		/* Counter X Interrupt */
+#define	QELM_COUNT_W	(1<<4)		/* Counter W Interrupt */
+#define	QELM_ELM_Z	(1<<3)		/* ELM Z Interrupt */
+#define	QELM_ELM_Y	(1<<2)		/* ELM Y Interrupt */
+#define	QELM_ELM_X	(1<<1)		/* ELM X Interrupt */
+#define	QELM_ELM_W	(1<<0)		/* ELM W Interrupt */
+#endif	/* MOT_ELM */
+/*
+ * PLC Timing Parameters
+ */
+#define	TP_C_MIN	0xff9c	/*   2    ms */
+#define	TP_TL_MIN	0xfff0	/*   0.3  ms */
+#define	TP_TB_MIN	0xff10	/*   5    ms */
+#define	TP_T_OUT	0xd9db	/* 200    ms */
+#define	TP_LC_LENGTH	0xf676	/*  50    ms */
+#define	TP_LC_LONGLN	0xa0a2	/* 500    ms */
+#define	TP_T_SCRUB	0xff6d	/*   3.5  ms */
+#define	TP_NS_MAX	0xf021	/*   1.3   ms */
+
+/*
+ * BIST values
+ */
+#define PLC_BIST	0x6ecd		/* BIST signature for PLC */
+#define PLCS_BIST	0x5b6b 		/* BIST signature for PLC-S */
+#define	PLC_ELM_B_BIST	0x6ecd		/* BIST signature of ELM Rev. B */
+#define	PLC_ELM_D_BIST	0x5b6b		/* BIST signature of ELM Rev. D */
+#define	PLC_CAM_A_BIST	0x9e75		/* BIST signature of CAMEL Rev. A */
+#define	PLC_CAM_B_BIST	0x5b6b		/* BIST signature of CAMEL Rev. B */
+#define	PLC_IFD_A_BIST	0x9e75		/* BIST signature of IFDDI Rev. A */
+#define	PLC_IFD_B_BIST	0x5b6b		/* BIST signature of IFDDI Rev. B */
+#define	PLC_QELM_A_BIST	0x5b6b		/* BIST signature of QELM Rev. A */
+
+/*
+ 	FDDI board recources	
+ */
+
+/*
+ * request register array (log. addr: RQA_A + a<<1 {a=0..7}) write only.
+ * It specifies to FORMAC+ the type of buffer memory access the host requires.
+ */
+#define	RQ_NOT		0		/* not request */
+#define	RQ_RES		1		/* reserved */
+#define	RQ_SFW		2		/* special frame write */
+#define	RQ_RRQ		3		/* read request: receive queue */
+#define	RQ_WSQ		4		/* write request: synchronous queue */
+#define	RQ_WA0		5		/* write requ.: asynchronous queue 0 */
+#define	RQ_WA1		6		/* write requ.: asynchronous queue 1 */
+#define	RQ_WA2		7		/* write requ.: asynchronous queue 2 */
+
+#define	SZ_LONG		(sizeof(long))
+
+/*
+ * FDDI defaults
+ * NOTE : In the ANSI docs, times are specified in units of "symbol time".
+ * 	  AMD chips use BCLK as unit. 1 BCKL == 2 symbols
+ */
+#define	COMPLREF	((u_long)32*256*256)	/* two's complement 21 bit */
+#define MSTOBCLK(x)	((u_long)(x)*12500L)
+#define MSTOTVX(x)	(((u_long)(x)*1000L)/80/255)
+
+#endif	/* _SUPERNET_ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/targethw.h linux.18p8/drivers/net/skfp/h/targethw.h
--- linux.vanilla/drivers/net/skfp/h/targethw.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/targethw.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	_TARGETHW_
+#define _TARGETHW_
+
+	/*
+	 *  PCI Watermark definition
+	 */
+#ifdef	PCI
+#define	RX_WATERMARK	24
+#define TX_WATERMARK	24
+#define SK_ML_ID_1	0x20
+#define SK_ML_ID_2	0x30
+#endif
+
+#include	"h/skfbi.h"
+#ifndef TAG_MODE	
+#include	"h/fplus.h"
+#else
+#include	"h/fplustm.h"
+#endif
+
+#ifndef	HW_PTR
+#ifdef  MEM_MAPPED_IO
+#define HW_PTR  u_long
+#else
+#define HW_PTR  u_short
+#endif
+#endif
+
+#ifdef MULT_OEM
+#define	OI_STAT_LAST		0	/* end of OEM data base */
+#define	OI_STAT_PRESENT		1	/* entry present but not empty */
+#define	OI_STAT_VALID		2	/* holds valid ID, but is not active */ 
+#define	OI_STAT_ACTIVE		3	/* holds valid ID, entry is active */
+					/* active = adapter is supported */
+
+/* Memory representation of IDs must match representation in adapter. */
+struct	s_oem_ids {
+	u_char	oi_status ;		/* Stat: last, present, valid, active */
+	u_char	oi_mark[5] ;		/* "PID00" .. "PID07" ..	*/
+	u_char 	oi_id[4] ;		/* id bytes, representation as	*/
+					/* defined by hardware,		*/	
+#ifdef PCI
+	u_char 	oi_sub_id[4] ;		/* sub id bytes, representation as */
+					/* defined by hardware,		*/
+#endif
+#ifdef ISA
+	u_char	oi_logo_len ;		/* the length of the adapter logo */	
+	u_char	oi_logo[6] ;		/* the adapter logo		*/
+	u_char	oi_reserved1 ;
+#endif	/* ISA */
+} ;
+#endif	/* MULT_OEM */
+
+
+struct s_smt_hw {
+	/*
+	 * global
+	 */
+	HW_PTR	iop ;			/* IO base address */
+	short	dma ;			/* DMA channel */
+	short	irq ;			/* IRQ level */
+	short	eprom ;			/* FLASH prom */
+#ifndef	PCI
+	short	DmaWriteExtraBytes ;	/* add bytes for DMA write */
+#endif
+
+#ifndef SYNC
+	u_short	n_a_send ;		/* pending send requests */
+#endif
+
+#if	(defined(EISA) || defined(MCA) || defined(PCI))
+	short	slot ;			/* slot number */
+	short   max_slots ;		/* maximum number of slots */
+#endif
+
+#if	(defined(PCI) || defined(MCA))
+	short	wdog_used ;		/* TRUE if the watch dog is used */
+#endif
+
+#ifdef	MCA
+	short	slot_32 ;		/* 32bit slot (1) or 16bit slot (0) */
+	short	rev ;			/* Board revision (FMx_REV). */
+	short	VFullRead ;		/* V_full value for DMA read */
+	short	VFullWrite ;		/* V_full value for DMA write */
+#endif
+
+#ifdef	EISA
+	short	led ;			/* LED for FE card */
+
+	short	dma_rmode ;		/* read mode */
+	short	dma_wmode ;		/* write mode */
+	short	dma_emode ;		/* extend mode */
+
+	/* DMA controller channel dependent io addresses */
+	u_short dma_base_word_count ;
+	u_short dma_base_address ;
+	u_short dma_base_address_page ;
+#endif
+
+#ifdef	PCI
+	u_short	pci_handle ;		/* handle to access the BIOS func */
+	u_long	is_imask ;		/* int maske for the int source reg */
+	u_long	phys_mem_addr ;		/* physical memory address */
+	u_short	mc_dummy ;		/* work around for MC compiler bug */	
+	/*
+	 * state of the hardware
+	 */
+	u_short hw_state ;		/* started or stopped */
+
+#define	STARTED		1
+#define	STOPPED		0
+
+	int	hw_is_64bit ;		/* does we have a 64 bit adapter */
+#endif
+
+#ifdef	TAG_MODE
+	u_long	pci_fix_value ;		/* value parsed by PCIFIX */
+#endif
+
+	/*
+	 * hwt.c
+	 */
+	u_long	t_start ;		/* HWT start */
+	u_long	t_stop ;		/* HWT stop */
+	u_short	timer_activ ;		/* HWT timer active */
+
+	/*
+	 * PIC
+	 */
+	u_char	pic_a1 ;
+	u_char	pic_21 ;
+
+	/*
+	 * GENERIC ; do not modify beyond this line
+	 */
+
+	/*
+	 * physical and canonical address
+	 */
+	struct fddi_addr fddi_home_addr ;
+	struct fddi_addr fddi_canon_addr ;
+	struct fddi_addr fddi_phys_addr ;
+
+	/*
+	 * mac variables
+	 */
+	struct mac_parameter mac_pa ;	/* tmin, tmax, tvx, treq .. */
+	struct mac_counter mac_ct ;	/* recv., lost, error  */
+	u_short	mac_ring_is_up ;	/* ring is up flag */
+
+	struct s_smt_fp	fp ;		/* formac+ */
+
+#ifdef MULT_OEM
+	struct s_oem_ids *oem_id ;	/* pointer to selected id */
+	int oem_min_status ;		/* IDs to take care of */
+#endif	/* MULT_OEM */
+
+} ;
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/targetos.h linux.18p8/drivers/net/skfp/h/targetos.h
--- linux.vanilla/drivers/net/skfp/h/targetos.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/targetos.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,164 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ *	Operating system specific definitions for driver and
+ *	hardware module.
+ */
+
+#ifndef	TARGETOS_H
+#define TARGETOS_H
+
+
+//-------- those should go into include/linux/pci.h
+#define PCI_VENDOR_ID_SK		0x1148
+#define PCI_DEVICE_ID_SK_FP		0x4000
+//--------
+
+
+
+//-------- those should go into include/linux/if_fddi.h
+#define FDDI_MAC_HDR_LEN 13
+
+#define FDDI_RII	0x01 /* routing information bit */
+#define FDDI_RCF_DIR_BIT 0x80
+#define FDDI_RCF_LEN_MASK 0x1f
+#define FDDI_RCF_BROADCAST 0x8000
+#define FDDI_RCF_LIMITED_BROADCAST 0xA000
+#define FDDI_RCF_FRAME2K 0x20
+#define FDDI_RCF_FRAME4K 0x30
+//--------
+
+
+#undef ADDR
+
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+// is redefined by linux, but we need our definition
+#undef ADDR
+#ifdef MEM_MAPPED_IO
+#define	ADDR(a) (char far *) smc->hw.iop+(a)
+#else
+#define	ADDR(a) (((a)>>7) ? (outp(smc->hw.iop+B0_RAP,(a)>>7), (smc->hw.iop+( ((a)&0x7F) | ((a)>>7 ? 0x80:0)) )) : (smc->hw.iop+(((a)&0x7F)|((a)>>7 ? 0x80:0))))
+#endif
+
+#include "h/hwmtm.h"
+
+#define TRUE  1
+#define FALSE 0
+
+// HWM Definitions
+// -----------------------
+#define FDDI_TRACE(string, arg1, arg2, arg3)	// Performance analysis.
+#ifdef PCI
+#define NDD_TRACE(string, arg1, arg2, arg3)	// Performance analysis.
+#endif	// PCI
+#define SMT_PAGESIZE	PAGE_SIZE	// Size of a memory page (power of 2).
+// -----------------------
+
+
+// SMT Definitions
+// -----------------------
+#define	TICKS_PER_SECOND	HZ
+#define SMC_VERSION    		1
+// -----------------------
+
+
+// OS-Driver Definitions
+// -----------------------
+#define NO_ADDRESS 0xffe0	/* No Device (I/O) Address */
+#define SKFP_MAX_NUM_BOARDS 8	/* maximum number of PCI boards */
+
+#define SK_BUS_TYPE_PCI		0
+#define SK_BUS_TYPE_EISA	1
+
+#define FP_IO_LEN		256	/* length of IO area used */
+
+#define u8	unsigned char
+#define u16	unsigned short
+#define u32	unsigned int
+
+#define MAX_TX_QUEUE_LEN	20 // number of packets queued by driver
+#define MAX_FRAME_SIZE		4550
+
+#define	RX_LOW_WATERMARK	NUM_RECEIVE_BUFFERS  / 2
+#define TX_LOW_WATERMARK	NUM_TRANSMIT_BUFFERS - 2
+
+/*
+** Include the IOCTL stuff
+*/
+#include <linux/sockios.h>
+
+#define	SKFPIOCTL	SIOCDEVPRIVATE
+
+struct s_skfp_ioctl {
+	unsigned short cmd;                /* Command to run */
+	unsigned short len;                /* Length of the data buffer */
+	unsigned char  *data;              /* Pointer to the data buffer */
+};
+
+/* 
+** Recognised ioctl commands for the driver 
+*/
+#define SKFP_GET_STATS		0x05 /* Get the driver statistics */
+#define SKFP_CLR_STATS		0x06 /* Zero out the driver statistics */
+
+// The per-adapter driver structure
+struct s_smt_os {
+	struct device	*dev;
+	struct device	*next_module;
+	u32		bus_type;/* bus type (0 == PCI, 1 == EISA) */
+	struct pci_dev	pdev;	/* PCI device structure */
+	
+	unsigned long base_addr;
+	unsigned char factory_mac_addr[8];
+	ulong	SharedMemSize;
+	ulong	SharedMemHeap;
+	void*	SharedMemAddr;
+
+	ulong	QueueSkb;
+	struct	sk_buff_head SendSkbQueue;
+
+	ulong	MaxFrameSize;
+	u8	ResetRequested;
+
+	// MAC statistics structure
+	struct fddi_statistics MacStat;
+
+	// receive into this local buffer if no skb available
+	// data will be not valid, because multiple RxDs can
+	// point here at the same time, it must be at least
+	// MAX_FRAME_SIZE bytes in size
+	unsigned char *LocalRxBuffer;
+	
+	// Version (required by SMT module).
+	u_long smc_version ;
+
+	// Required by Hardware Module (HWM).
+	struct hw_modul hwm ;
+	
+	// For SMP-savety
+	spinlock_t DriverLock;
+	
+};
+
+typedef struct s_smt_os skfddi_priv;
+
+#endif	 // _TARGETOS_
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/h/types.h linux.18p8/drivers/net/skfp/h/types.h
--- linux.vanilla/drivers/net/skfp/h/types.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/h/types.h	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,48 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include	<linux/types.h>
+/*
+	----------------------
+	Basic SMT system types
+	----------------------
+*/
+#ifndef _TYPES_
+#define	_TYPES_
+
+#define _packed
+#ifndef far
+#define far
+#endif
+#ifndef _far
+#define _far
+#endif
+
+#ifndef MEM_MAPPED_IO // "normal" IO
+#define inp(p)  inb(p)
+#define inpw(p)	inw(p)
+#define inpd(p) inl(p)
+#define outp(p,c)  outb(c,p)
+#define outpw(p,s) outw(s,p)
+#define outpd(p,l) outl(l,p)
+#else // memory mapped io
+#define inp(a)		readb(a)
+#define inpw(a)		readw(a)
+#define inpd(a)		readl(a)
+#define outp(a,v)	writeb(v, a)	
+#define outpw(a,v)	writew(v, a)	
+#define outpd(a,v)	writel(v, a)	
+#endif
+
+#endif	/* _TYPES_ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/hwmtm.c linux.18p8/drivers/net/skfp/hwmtm.c
--- linux.vanilla/drivers/net/skfp/hwmtm.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/hwmtm.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,2241 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#ifndef	lint
+static char const ID_sccs[] = "@(#)hwmtm.c	1.40 99/05/31 (C) SK" ;
+#endif
+
+#define	HWMTM
+
+#ifndef FDDI
+#define	FDDI
+#endif
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#include "h/skfbiinc.h"
+
+/*
+	-------------------------------------------------------------
+	DOCUMENTATION
+	-------------------------------------------------------------
+	BEGIN_MANUAL_ENTRY(DOCUMENTATION)
+
+			T B D
+
+	END_MANUAL_ENTRY
+*/
+/*
+	-------------------------------------------------------------
+	LOCAL VARIABLES:
+	-------------------------------------------------------------
+*/
+#ifdef COMMON_MB_POOL
+static	SMbuf *mb_start = 0 ;
+static	SMbuf *mb_free = 0 ;
+static	int mb_init = FALSE ;
+static	int call_count = 0 ;
+#endif
+
+/*
+	-------------------------------------------------------------
+	EXTERNE VARIABLES:
+	-------------------------------------------------------------
+*/
+
+#ifdef	DEBUG
+#ifndef	DEBUG_BRD
+extern	struct smt_debug	debug ;
+#endif
+#endif
+
+#ifdef	NDIS_OS2
+extern	u_char	offDepth ;
+extern	u_char	force_irq_pending ;
+#endif
+
+/*
+	-------------------------------------------------------------
+	LOCAL FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+static	void	queue_llc_rx(),		smt_to_llc(),
+		init_txd_ring(),	init_rxd_ring(),
+		queue_txd_mb() ;
+
+static	u_long	init_descr_ring(),	repair_txd_ring(),
+		repair_rxd_ring() ;
+
+static	SMbuf	*get_llc_rx(),		*get_txd_mb() ;
+
+
+/*
+	-------------------------------------------------------------
+	EXTERNAL FUNCTIONS:
+	-------------------------------------------------------------
+*/
+/*	The external SMT functions are listed in cmtdef.h */
+
+extern	void	*mac_drv_get_space(),	*mac_drv_get_desc_mem(),
+		init_board(),		mac_drv_fill_rxd(),
+		plc1_irq(),		mac_drv_tx_complete(),
+		plc2_irq(),		mac1_irq(),
+		mac2_irq(),		mac3_irq(),
+		timer_irq(),		mac_drv_rx_complete(),
+		mac_drv_requeue_rxd(),	init_plc(),
+		mac_drv_clear_rxd(),	llc_restart_tx(),
+		ev_dispatcher(),	smt_force_irq() ;
+
+#ifdef	USE_OS_CPY
+extern	void	hwm_cpy_rxd2mb(),	hwm_cpy_txd2mb() ;
+#endif
+#ifdef	ALL_RX_COMPLETE
+extern	void	mac_drv_all_receives_complete() ;
+#endif
+
+extern	u_long	mac_drv_virt2phys(),	dma_master() ;
+
+#ifdef	NDIS_OS2
+extern	void	post_proc() ;
+#else
+extern	void	dma_complete() ;
+#endif
+
+extern	int	init_fplus(),		mac_drv_rx_init() ;
+
+/*
+	-------------------------------------------------------------
+	PUBLIC FUNCTIONS:
+	-------------------------------------------------------------
+*/
+	void	process_receive(),	smt_send_mbuf(),
+		fddi_isr(),		mac_drv_clear_txd(),
+		smt_free_mbuf(),	init_driver_fplus(),
+		mac_drv_rx_mode(),	init_fddi_driver(),
+		mac_drv_clear_tx_queue(),
+		mac_drv_clear_rx_queue(),
+		hwm_tx_frag(),		hwm_rx_frag() ;
+
+	int	mac_drv_rx_frag(),	mac_drv_init(),
+		hwm_tx_init() ;
+
+	u_int	mac_drv_check_space() ;
+
+	SMbuf 	*smt_get_mbuf() ;
+
+#ifdef DEBUG
+	void	mac_drv_debug_lev() ;
+#endif
+
+/*
+	-------------------------------------------------------------
+	MACROS:
+	-------------------------------------------------------------
+*/
+#ifndef	UNUSED
+#ifdef	lint
+#define UNUSED(x)	(x) = (x)
+#else
+#define UNUSED(x)
+#endif
+#endif
+
+#ifdef	USE_CAN_ADDR
+#define MA		smc->hw.fddi_canon_addr.a
+#define	GROUP_ADDR_BIT	0x01
+#else
+#define	MA		smc->hw.fddi_home_addr.a
+#define	GROUP_ADDR_BIT	0x80
+#endif
+
+#define RXD_TXD_COUNT	(HWM_ASYNC_TXD_COUNT+HWM_SYNC_TXD_COUNT+\
+			SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT)
+
+#ifdef	MB_OUTSIDE_SMC
+#define	EXT_VIRT_MEM	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd) +\
+			MAX_MBUF*sizeof(SMbuf))
+#define	EXT_VIRT_MEM_2	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
+#else
+#define	EXT_VIRT_MEM	((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd))
+#endif
+
+	/*
+	 * define critical read for 16 Bit drivers
+	 */
+#if	defined(NDIS_OS2) || defined(ODI2)
+#define CR_READ(var)	((var) & 0xffff0000 | ((var) & 0xffff))
+#else
+#define CR_READ(var)	(u_long)(var)
+#endif
+
+#define IMASK_SLOW	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
+			 IS_MINTR1 | IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
+			 IS_R1_C | IS_XA_C | IS_XS_C)
+
+/*
+	-------------------------------------------------------------
+	INIT- AND SMT FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_check_space)
+ *	u_int mac_drv_check_space()
+ *
+ *	function	DOWNCALL	(drvsr.c)
+ *			This function calculates the needed non virtual
+ *			memory for MBufs, RxD and TxD descriptors etc.
+ *			needed by the driver.
+ *
+ *	return		u_int	memory in bytes
+ *
+ *	END_MANUAL_ENTRY
+ */
+u_int mac_drv_check_space()
+{
+#ifdef	MB_OUTSIDE_SMC
+#ifdef	COMMON_MB_POOL
+	call_count++ ;
+	if (call_count == 1) {
+		return(EXT_VIRT_MEM) ;
+	}
+	else {
+		return(EXT_VIRT_MEM_2) ;
+	}
+#else
+	return (EXT_VIRT_MEM) ;
+#endif
+#else
+	return (0) ;
+#endif
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_init)
+ *	void mac_drv_init(smc)
+ *
+ *	function	DOWNCALL	(drvsr.c)
+ *			In this function the hardware module allocates it's
+ *			memory.
+ *			The operating system dependent module should call
+ *			mac_drv_init once, after the adatper is detected.
+ *	END_MANUAL_ENTRY
+ */
+int mac_drv_init(smc)
+struct s_smc *smc ;
+{
+	if (sizeof(struct s_smt_fp_rxd) % 16) {
+		SMT_PANIC(smc,HWM_E0001,HWM_E0001_MSG) ;
+	}
+	if (sizeof(struct s_smt_fp_txd) % 16) {
+		SMT_PANIC(smc,HWM_E0002,HWM_E0002_MSG) ;
+	}
+
+	/*
+	 * get the required memory for the RxDs and TxDs
+	 */
+	if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *)
+		mac_drv_get_desc_mem(smc,(u_int)
+		(RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) {
+		return(1) ;	/* no space the hwm modul can't work */
+	}
+
+	/*
+	 * get the memory for the SMT MBufs
+	 */
+#ifndef	MB_OUTSIDE_SMC
+	smc->os.hwm.mbuf_pool.mb_start=(SMbuf *)(&smc->os.hwm.mbuf_pool.mb[0]) ;
+#else
+#ifndef	COMMON_MB_POOL
+	if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc,
+		MAX_MBUF*sizeof(SMbuf)))) {
+		return(1) ;	/* no space the hwm modul can't work */
+	}
+#else
+	if (!mb_start) {
+		if (!(mb_start = (SMbuf *) mac_drv_get_space(smc,
+			MAX_MBUF*sizeof(SMbuf)))) {
+			return(1) ;	/* no space the hwm modul can't work */
+		}
+	}
+#endif
+#endif
+	return (0) ;
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(init_driver_fplus)
+ *	init_driver_fplus(smc)
+ *
+ * Sets hardware modul specific values for the mode register 2
+ * (e.g. the byte alignment for the received frames, the position of the
+ *	 least significant byte etc.)
+ *	END_MANUAL_ENTRY
+ */
+void init_driver_fplus(smc)
+struct s_smc *smc ;
+{
+	smc->hw.fp.mdr2init = FM_LSB | FM_BMMODE | FM_ENNPRQ | FM_ENHSRQ | 3 ;
+
+#ifdef	PCI
+	smc->hw.fp.mdr2init |= FM_CHKPAR | FM_PARITY ;
+#endif
+	smc->hw.fp.mdr3init = FM_MENRQAUNLCK | FM_MENRS ;
+
+#ifdef	USE_CAN_ADDR
+	/* enable address bit swapping */
+	smc->hw.fp.frselreg_init = FM_ENXMTADSWAP | FM_ENRCVADSWAP ;
+#endif
+}
+
+static u_long init_descr_ring(smc,start,count)
+struct s_smc *smc ;
+union s_fp_descr volatile *start;
+int count ;
+{
+	int i ;
+	union s_fp_descr volatile *d1 ;
+	union s_fp_descr volatile *d2 ;
+	u_long	phys ;
+
+	DB_GEN("descr ring starts at = %x ",(void *)start,0,3) ;
+	for (i=count-1, d1=start; i ; i--) {
+		d2 = d1 ;
+		d1++ ;		/* descr is owned by the host */
+		d2->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ;
+		d2->r.rxd_next = &d1->r ;
+		phys = mac_drv_virt2phys(smc,(void *)d1) ;
+		d2->r.rxd_nrdadr = AIX_REVERSE(phys) ;
+	}
+	DB_GEN("descr ring ends at = %x ",(void *)d1,0,3) ;
+	d1->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ;
+	d1->r.rxd_next = &start->r ;
+	phys = mac_drv_virt2phys(smc,(void *)start) ;
+	d1->r.rxd_nrdadr = AIX_REVERSE(phys) ;
+
+	for (i=count, d1=start; i ; i--) {
+		DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ;
+		d1++;
+	}
+	return(phys) ;
+}
+
+static void init_txd_ring(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_fp_txd volatile *ds ;
+	struct s_smt_tx_queue *queue ;
+	u_long	phys ;
+
+	/*
+	 * initialize the transmit descriptors
+	 */
+	ds = (struct s_smt_fp_txd volatile *) ((char *)smc->os.hwm.descr_p +
+		SMT_R1_RXD_COUNT*sizeof(struct s_smt_fp_rxd)) ;
+	queue = smc->hw.fp.tx[QUEUE_A0] ;
+	DB_GEN("Init async TxD ring, %d TxDs ",HWM_ASYNC_TXD_COUNT,0,3) ;
+	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
+		HWM_ASYNC_TXD_COUNT) ;
+	phys = AIX_REVERSE(ds->txd_ntdadr) ;
+	ds++ ;
+	queue->tx_curr_put = queue->tx_curr_get = ds ;
+	ds-- ;
+	queue->tx_free = HWM_ASYNC_TXD_COUNT ;
+	queue->tx_used = 0 ;
+	outpd(ADDR(B5_XA_DA),phys) ;
+
+	ds = (struct s_smt_fp_txd volatile *) ((char *)ds +
+		HWM_ASYNC_TXD_COUNT*sizeof(struct s_smt_fp_txd)) ;
+	queue = smc->hw.fp.tx[QUEUE_S] ;
+	DB_GEN("Init sync TxD ring, %d TxDs ",HWM_SYNC_TXD_COUNT,0,3) ;
+	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
+		HWM_SYNC_TXD_COUNT) ;
+	phys = AIX_REVERSE(ds->txd_ntdadr) ;
+	ds++ ;
+	queue->tx_curr_put = queue->tx_curr_get = ds ;
+	queue->tx_free = HWM_SYNC_TXD_COUNT ;
+	queue->tx_used = 0 ;
+	outpd(ADDR(B5_XS_DA),phys) ;
+}
+
+static void init_rxd_ring(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_fp_rxd volatile *ds ;
+	struct s_smt_rx_queue *queue ;
+	u_long	phys ;
+
+	/*
+	 * initialize the receive descriptors
+	 */
+	ds = (struct s_smt_fp_rxd volatile *) smc->os.hwm.descr_p ;
+	queue = smc->hw.fp.rx[QUEUE_R1] ;
+	DB_GEN("Init RxD ring, %d RxDs ",SMT_R1_RXD_COUNT,0,3) ;
+	(void)init_descr_ring(smc,(union s_fp_descr volatile *)ds,
+		SMT_R1_RXD_COUNT) ;
+	phys = AIX_REVERSE(ds->rxd_nrdadr) ;
+	ds++ ;
+	queue->rx_curr_put = queue->rx_curr_get = ds ;
+	queue->rx_free = SMT_R1_RXD_COUNT ;
+	queue->rx_used = 0 ;
+	outpd(ADDR(B4_R1_DA),phys) ;
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(init_fddi_driver)
+ *	void init_fddi_driver(smc,mac_addr)
+ *
+ * initializes the driver and it's variables
+ *
+ *	END_MANUAL_ENTRY
+ */
+void init_fddi_driver(smc,mac_addr)
+struct	s_smc	*smc ;
+u_char		*mac_addr ;	/* canonical address */
+{
+	SMbuf	*mb ;
+	int	i ;
+
+	init_board(smc,mac_addr) ;
+	(void)init_fplus(smc) ;
+
+	/*
+	 * initialize the SMbufs for the SMT
+	 */
+#ifndef	COMMON_MB_POOL
+	mb = smc->os.hwm.mbuf_pool.mb_start ;
+	smc->os.hwm.mbuf_pool.mb_free = (SMbuf *)NULL ;
+	for (i = 0; i < MAX_MBUF; i++) {
+		mb->sm_use_count = 1 ;
+		smt_free_mbuf(smc,mb)	;
+		mb++ ;
+	}
+#else
+	mb = mb_start ;
+	if (!mb_init) {
+		mb_free = 0 ;
+		for (i = 0; i < MAX_MBUF; i++) {
+			mb->sm_use_count = 1 ;
+			smt_free_mbuf(smc,mb)	;
+			mb++ ;
+		}
+		mb_init = TRUE ;
+	}
+#endif
+
+	/*
+	 * initialize the other variables
+	 */
+	smc->os.hwm.llc_rx_pipe = smc->os.hwm.llc_rx_tail = (SMbuf *)NULL ;
+	smc->os.hwm.txd_tx_pipe = smc->os.hwm.txd_tx_tail = NULL ;
+	smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = smc->os.hwm.pass_DB = 0 ;
+	smc->os.hwm.pass_llc_promisc = TRUE ;
+	smc->os.hwm.queued_rx_frames = smc->os.hwm.queued_txd_mb = 0 ;
+	smc->os.hwm.detec_count = 0 ;
+	smc->os.hwm.rx_break = 0 ;
+	smc->os.hwm.rx_len_error = 0 ;
+	smc->os.hwm.isr_flag = FALSE ;
+
+	/*
+	 * make sure that the start pointer is 16 byte aligned
+	 */
+	i = 16 - ((long)smc->os.hwm.descr_p & 0xf) ;
+	if (i != 16) {
+		DB_GEN("i = %d",i,0,3) ;
+		smc->os.hwm.descr_p = (union s_fp_descr volatile *)
+			((char *)smc->os.hwm.descr_p+i) ;
+	}
+	DB_GEN("pt to descr area = %x",(void *)smc->os.hwm.descr_p,0,3) ;
+
+	init_txd_ring(smc) ;
+	init_rxd_ring(smc) ;
+	mac_drv_fill_rxd(smc) ;
+
+	init_plc(smc) ;
+}
+
+
+SMbuf *smt_get_mbuf(smc)
+struct s_smc *smc ;
+{
+	register SMbuf	*mb ;
+
+#ifndef	COMMON_MB_POOL
+	mb = smc->os.hwm.mbuf_pool.mb_free ;
+#else
+	mb = mb_free ;
+#endif
+	if (mb) {
+#ifndef	COMMON_MB_POOL
+		smc->os.hwm.mbuf_pool.mb_free = mb->sm_next ;
+#else
+		mb_free = mb->sm_next ;
+#endif
+		mb->sm_off = 8 ;
+		mb->sm_use_count = 1 ;
+	}
+	DB_GEN("get SMbuf: mb = %x",(void *)mb,0,3) ;
+	return (mb) ;	/* May be NULL */
+}
+
+void smt_free_mbuf(smc, mb)
+struct s_smc	*smc ;
+SMbuf		*mb;
+{
+
+	if (mb) {
+		mb->sm_use_count-- ;
+		DB_GEN("free_mbuf: sm_use_count = %d",mb->sm_use_count,0,3) ;
+		/*
+		 * If the use_count is != zero the MBuf is queued
+		 * more than once and must not queued into the
+		 * free MBuf queue
+		 */
+		if (!mb->sm_use_count) {
+			DB_GEN("free SMbuf: mb = %x",(void *)mb,0,3) ;
+#ifndef	COMMON_MB_POOL
+			mb->sm_next = smc->os.hwm.mbuf_pool.mb_free ;
+			smc->os.hwm.mbuf_pool.mb_free = mb ;
+#else
+			mb->sm_next = mb_free ;
+			mb_free = mb ;
+#endif
+		}
+	}
+	else
+		SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ;
+}
+
+
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_repair_descr)
+ *	void mac_drv_repair_descr(smc)
+ *
+ * function	called from SMT	(HWM / hwmtm.c)
+ *		The BMU is idle when this function is called.
+ *		Mac_drv_repair_descr sets up the physical address
+ *		for all receive and transmit queues where the BMU
+ *		should continue.
+ *		It may be that the BMU was reseted during a fragmented
+ *		transfer. In this case there are some fragments which will
+ *		never completed by the BMU. The OWN bit of this fragments
+ *		must be switched to be owned by the host.
+ *
+ *		Give a start command to the receive BMU.
+ *		Start the transmit BMUs if transmit frames pending.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_repair_descr(smc)
+struct s_smc *smc ;
+{
+	u_long	phys ;
+
+	if (smc->hw.hw_state != STOPPED) {
+		SK_BREAK() ;
+		SMT_PANIC(smc,HWM_E0013,HWM_E0013_MSG) ;
+		return ;
+	}
+
+	/*
+	 * repair tx queues: don't start
+	 */
+	phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_A0]) ;
+	outpd(ADDR(B5_XA_DA),phys) ;
+	if (smc->hw.fp.tx_q[QUEUE_A0].tx_used) {
+		outpd(ADDR(B0_XA_CSR),CSR_START) ;
+	}
+	phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_S]) ;
+	outpd(ADDR(B5_XS_DA),phys) ;
+	if (smc->hw.fp.tx_q[QUEUE_S].tx_used) {
+		outpd(ADDR(B0_XS_CSR),CSR_START) ;
+	}
+
+	/*
+	 * repair rx queues
+	 */
+	phys = repair_rxd_ring(smc,smc->hw.fp.rx[QUEUE_R1]) ;
+	outpd(ADDR(B4_R1_DA),phys) ;
+	outpd(ADDR(B0_R1_CSR),CSR_START) ;
+}
+
+static u_long repair_txd_ring(smc,queue)
+struct s_smc *smc ;
+struct s_smt_tx_queue *queue ;
+{
+	int i ;
+	int tx_used ;
+	u_long phys ;
+	u_long tbctrl ;
+	struct s_smt_fp_txd volatile *t ;
+
+	SK_UNUSED(smc) ;
+
+	t = queue->tx_curr_get ;
+	tx_used = queue->tx_used ;
+	for (i = tx_used+queue->tx_free-1 ; i ; i-- ) {
+		t = t->txd_next ;
+	}
+	phys = AIX_REVERSE(t->txd_ntdadr) ;
+
+	t = queue->tx_curr_get ;
+	while (tx_used) {
+		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
+		tbctrl = AIX_REVERSE(t->txd_tbctrl) ;
+
+		if (tbctrl & BMU_OWN) {
+			if (tbctrl & BMU_STF) {
+				break ;		/* exit the loop */
+			}
+			else {
+				/*
+				 * repair the descriptor
+				 */
+				t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ;
+			}
+		}
+		phys = AIX_REVERSE(t->txd_ntdadr) ;
+		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+		t = t->txd_next ;
+		tx_used-- ;
+	}
+	return(phys) ;
+}
+
+/*
+ * Repairs the receive descriptor ring and returns the physical address
+ * where the BMU should continue working.
+ *
+ *	o The physical address where the BMU was stopped has to be
+ *	  determined. This is the next RxD after rx_curr_get with an OWN
+ *	  bit set.
+ *	o The BMU should start working at beginning of the next frame.
+ *	  RxDs with an OWN bit set but with a reset STF bit should be
+ *	  skipped and owned by the driver (OWN = 0). 
+ */
+static u_long repair_rxd_ring(smc,queue)
+struct s_smc *smc ;
+struct s_smt_rx_queue *queue ;
+{
+	int i ;
+	int rx_used ;
+	u_long phys ;
+	u_long rbctrl ;
+	struct s_smt_fp_rxd volatile *r ;
+
+	SK_UNUSED(smc) ;
+
+	r = queue->rx_curr_get ;
+	rx_used = queue->rx_used ;
+	for (i = SMT_R1_RXD_COUNT-1 ; i ; i-- ) {
+		r = r->rxd_next ;
+	}
+	phys = AIX_REVERSE(r->rxd_nrdadr) ;
+
+	r = queue->rx_curr_get ;
+	while (rx_used) {
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+		rbctrl = AIX_REVERSE(r->rxd_rbctrl) ;
+
+		if (rbctrl & BMU_OWN) {
+			if (rbctrl & BMU_STF) {
+				break ;		/* exit the loop */
+			}
+			else {
+				/*
+				 * repair the descriptor
+				 */
+				r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ;
+			}
+		}
+		phys = AIX_REVERSE(r->rxd_nrdadr) ;
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+		r = r->rxd_next ;
+		rx_used-- ;
+	}
+	return(phys) ;
+}
+
+
+/*
+	-------------------------------------------------------------
+	INTERRUPT SERVICE ROUTINE:
+	-------------------------------------------------------------
+*/
+
+/*
+ *	BEGIN_MANUAL_ENTRY(fddi_isr)
+ *	void fddi_isr(smc)
+ *
+ * function	DOWNCALL	(drvsr.c)
+ *		interrupt service routine, handles the interrupt requests
+ *		generated by the FDDI adapter.
+ *
+ * NOTE:	The operating system dependent module must garantee that the
+ *		interrupts of the adapter are disabled when it calls fddi_isr.
+ *
+ *	About the USE_BREAK_ISR mechanismn:
+ *
+ *	The main requirement of this mechanismn is to force an timer IRQ when
+ *	leaving process_receive() with leave_isr set. process_receive() may
+ *	be called at any time from anywhere!
+ *	To be sure we don't miss such event we set 'force_irq' per default.
+ *	We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND
+ *	'force_irq' are set. 'force_irq' may be reset if a receive complete
+ *	IRQ is pending.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void fddi_isr(smc)
+struct s_smc *smc ;
+{
+	u_long		is ;		/* ISR source */
+	u_short		stu, stl ;
+	SMbuf		*mb ;
+
+#ifdef	USE_BREAK_ISR
+	int	force_irq ;
+#endif
+
+#ifdef	ODI2
+	if (smc->os.hwm.rx_break) {
+		mac_drv_fill_rxd(smc) ;
+		if (smc->hw.fp.rx_q[QUEUE_R1].rx_used > 0) {
+			smc->os.hwm.rx_break = 0 ;
+			process_receive(smc) ;
+		}
+		else {
+			smc->os.hwm.detec_count = 0 ;
+			smt_force_irq(smc) ;
+		}
+	}
+#endif
+	smc->os.hwm.isr_flag = TRUE ;
+
+#ifdef	USE_BREAK_ISR
+	force_irq = TRUE ;
+	if (smc->os.hwm.leave_isr) {
+		smc->os.hwm.leave_isr = FALSE ;
+		process_receive(smc) ;
+	}
+#endif
+
+	while ((is = GET_ISR() & ISR_MASK)) {
+		NDD_TRACE("CH0B",is,0,0) ;
+		DB_GEN("ISA = 0x%x",is,0,7) ;
+
+		if (is & IMASK_SLOW) {
+			NDD_TRACE("CH1b",is,0,0) ;
+			if (is & IS_PLINT1) {	/* PLC1 */
+				plc1_irq(smc) ;
+			}
+			if (is & IS_PLINT2) {	/* PLC2 */
+				plc2_irq(smc) ;
+			}
+			if (is & IS_MINTR1) {	/* FORMAC+ STU1(U/L) */
+				stu = inpw(FM_A(FM_ST1U)) ;
+				stl = inpw(FM_A(FM_ST1L)) ;
+				DB_GEN("Slow transmit complete",0,0,6) ;
+				mac1_irq(smc,stu,stl) ;
+			}
+			if (is & IS_MINTR2) {	/* FORMAC+ STU2(U/L) */
+				stu= inpw(FM_A(FM_ST2U)) ;
+				stl= inpw(FM_A(FM_ST2L)) ;
+				DB_GEN("Slow receive complete",0,0,6) ;
+				DB_GEN("stl = %x : stu = %x",stl,stu,7) ;
+				mac2_irq(smc,stu,stl) ;
+			}
+			if (is & IS_MINTR3) {	/* FORMAC+ STU3(U/L) */
+				stu= inpw(FM_A(FM_ST3U)) ;
+				stl= inpw(FM_A(FM_ST3L)) ;
+				DB_GEN("FORMAC Mode Register 3",0,0,6) ;
+				mac3_irq(smc,stu,stl) ;
+			}
+			if (is & IS_TIMINT) {	/* Timer 82C54-2 */
+				timer_irq(smc) ;
+#ifdef	NDIS_OS2
+				force_irq_pending = 0 ;
+#endif
+				/*
+				 * out of RxD detection
+				 */
+				if (++smc->os.hwm.detec_count > 4) {
+					/*
+					 * check out of RxD condition
+					 */
+					 process_receive(smc) ;
+				}
+			}
+			if (is & IS_TOKEN) {	/* Restricted Token Monitor */
+				rtm_irq(smc) ;
+			}
+			if (is & IS_R1_P) {	/* Parity error rx queue 1 */
+				/* clear IRQ */
+				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_P) ;
+				SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ;
+			}
+			if (is & IS_R1_C) {	/* Encoding error rx queue 1 */
+				/* clear IRQ */
+				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_C) ;
+				SMT_PANIC(smc,HWM_E0005,HWM_E0005_MSG) ;
+			}
+			if (is & IS_XA_C) {	/* Encoding error async tx q */
+				/* clear IRQ */
+				outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_C) ;
+				SMT_PANIC(smc,HWM_E0006,HWM_E0006_MSG) ;
+			}
+			if (is & IS_XS_C) {	/* Encoding error sync tx q */
+				/* clear IRQ */
+				outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_C) ;
+				SMT_PANIC(smc,HWM_E0007,HWM_E0007_MSG) ;
+			}
+		}
+
+		/*
+		 *	Fast Tx complete Async/Sync Queue (BMU service)
+		 */
+		if (is & (IS_XS_F|IS_XA_F)) {
+			DB_GEN("Fast tx complete queue",0,0,6) ;
+			/*
+			 * clear IRQ, Note: no IRQ is lost, because
+			 * 	we always service both queues
+			 */
+			outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_F) ;
+			outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_F) ;
+			mac_drv_clear_txd(smc) ;
+			llc_restart_tx(smc) ;
+		}
+
+		/*
+		 *	Fast Rx Complete (BMU service)
+		 */
+		if (is & IS_R1_F) {
+			DB_GEN("Fast receive complete",0,0,6) ;
+			/* clear IRQ */
+#ifndef USE_BREAK_ISR
+			outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
+			process_receive(smc) ;
+#else
+			process_receive(smc) ;
+			if (smc->os.hwm.leave_isr) {
+				force_irq = FALSE ;
+			} else {
+				outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ;
+				process_receive(smc) ;
+			}
+#endif
+		}
+
+#ifndef	NDIS_OS2
+		while ((mb = get_llc_rx(smc))) {
+			smt_to_llc(smc,mb) ;
+		}
+#else
+		if (offDepth)
+			post_proc() ;
+
+		while (!offDepth && (mb = get_llc_rx(smc))) {
+			smt_to_llc(smc,mb) ;
+		}
+
+		if (!offDepth && smc->os.hwm.rx_break) {
+			process_receive(smc) ;
+		}
+#endif
+		if (smc->q.ev_get != smc->q.ev_put) {
+			NDD_TRACE("CH2a",0,0,0) ;
+			ev_dispatcher(smc) ;
+		}
+#ifdef	NDIS_OS2
+		post_proc() ;
+		if (offDepth) {		/* leave fddi_isr because */
+			break ;		/* indications not allowed */
+		}
+#endif
+#ifdef	USE_BREAK_ISR
+		if (smc->os.hwm.leave_isr) {
+			break ;		/* leave fddi_isr */
+		}
+#endif
+
+		/* NOTE: when the isr is left, no rx is pending */
+	}	/* end of interrupt source polling loop */
+
+#ifdef	USE_BREAK_ISR
+	if (smc->os.hwm.leave_isr && force_irq) {
+		smt_force_irq(smc) ;
+	}
+#endif
+	smc->os.hwm.isr_flag = FALSE ;
+	NDD_TRACE("CH0E",0,0,0) ;
+}
+
+
+/*
+	-------------------------------------------------------------
+	RECEIVE FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+#ifndef	NDIS_OS2
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_rx_mode)
+ *	void mac_drv_rx_mode(smc,mode)
+ *
+ * function	DOWNCALL	(fplus.c)
+ *		Corresponding to the parameter mode, the operating system
+ *		dependent module can activate several receive modes.
+ *
+ * para	mode	= 1:	RX_ENABLE_ALLMULTI	enable all multicasts
+ *		= 2:	RX_DISABLE_ALLMULTI	disable "enable all multicasts"
+ *		= 3:	RX_ENABLE_PROMISC	enable promiscuous
+ *		= 4:	RX_DISABLE_PROMISC	disable promiscuous
+ *		= 5:	RX_ENABLE_NSA		enable rec. of all NSA frames
+ *			(disabled after 'driver reset' & 'set station address')
+ *		= 6:	RX_DISABLE_NSA		disable rec. of all NSA frames
+ *
+ *		= 21:	RX_ENABLE_PASS_SMT	( see description )
+ *		= 22:	RX_DISABLE_PASS_SMT	(  "	   "	  )
+ *		= 23:	RX_ENABLE_PASS_NSA	(  "	   "	  )
+ *		= 24:	RX_DISABLE_PASS_NSA	(  "	   "	  )
+ *		= 25:	RX_ENABLE_PASS_DB	(  "	   "	  )
+ *		= 26:	RX_DISABLE_PASS_DB	(  "	   "	  )
+ *		= 27:	RX_DISABLE_PASS_ALL	(  "	   "	  )
+ *		= 28:	RX_DISABLE_LLC_PROMISC	(  "	   "	  )
+ *		= 29:	RX_ENABLE_LLC_PROMISC	(  "	   "	  )
+ *
+ *
+ *		RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT
+ *
+ *		If the operating system dependent module activates the
+ *		mode RX_ENABLE_PASS_SMT, the hardware module
+ *		duplicates all SMT frames with the frame control
+ *		FC_SMT_INFO and passes them to the LLC receive channel
+ *		by calling mac_drv_rx_init.
+ *		The SMT Frames which are sent by the local SMT and the NSA
+ *		frames whose A- and C-Indicator is not set are also duplicated
+ *		and passed.
+ *		The receive mode RX_DISABLE_PASS_SMT disables the passing
+ *		of SMT frames.
+ *
+ *		RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA
+ *
+ *		If the operating system dependent module activates the
+ *		mode RX_ENABLE_PASS_NSA, the hardware module
+ *		duplicates all NSA frames with frame control FC_SMT_NSA
+ *		and a set A-Indicator and passed them to the LLC
+ *		receive channel by calling mac_drv_rx_init.
+ *		All NSA Frames which are sent by the local SMT
+ *		are also duplicated and passed.
+ *		The receive mode RX_DISABLE_PASS_NSA disables the passing
+ *		of NSA frames with the A- or C-Indicator set.
+ *
+ * NOTE:	For fear that the hardware module receives NSA frames with
+ *		a reset A-Indicator, the operating system dependent module
+ *		has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA
+ *		before activate the RX_ENABLE_PASS_NSA mode and after every
+ *		'driver reset' and 'set station address'.
+ *
+ *		RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB
+ *
+ *		If the operating system dependent module activates the
+ *		mode RX_ENABLE_PASS_DB, direct BEACON frames
+ *		(FC_BEACON frame control) are passed to the LLC receive
+ *		channel by mac_drv_rx_init.
+ *		The receive mode RX_DISABLE_PASS_DB disables the passing
+ *		of direct BEACON frames.
+ *
+ *		RX_DISABLE_PASS_ALL
+ *
+ *		Disables all special receives modes. It is equal to
+ *		call mac_drv_set_rx_mode successively with the
+ *		parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT,
+ *		RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB.
+ *
+ *		RX_ENABLE_LLC_PROMISC
+ *
+ *		(default) all received LLC frames and all SMT/NSA/DBEACON
+ *		frames depending on the attitude of the flags
+ *		PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the
+ *		LLC layer
+ *
+ *		RX_DISABLE_LLC_PROMISC
+ *
+ *		all received SMT/NSA/DBEACON frames depending on the
+ *		attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON
+ *		will be delivered to the LLC layer.
+ *		all received LLC frames with a directed address, Multicast
+ *		or Broadcast address will be delivered to the LLC
+ *		layer too.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_rx_mode(smc,mode)
+struct s_smc *smc ;
+int mode ;
+{
+	switch(mode) {
+	case RX_ENABLE_PASS_SMT:
+		smc->os.hwm.pass_SMT = TRUE ;
+		break ;
+	case RX_DISABLE_PASS_SMT:
+		smc->os.hwm.pass_SMT = FALSE ;
+		break ;
+	case RX_ENABLE_PASS_NSA:
+		smc->os.hwm.pass_NSA = TRUE ;
+		break ;
+	case RX_DISABLE_PASS_NSA:
+		smc->os.hwm.pass_NSA = FALSE ;
+		break ;
+	case RX_ENABLE_PASS_DB:
+		smc->os.hwm.pass_DB = TRUE ;
+		break ;
+	case RX_DISABLE_PASS_DB:
+		smc->os.hwm.pass_DB = FALSE ;
+		break ;
+	case RX_DISABLE_PASS_ALL:
+		smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = FALSE ;
+		smc->os.hwm.pass_DB = FALSE ;
+		smc->os.hwm.pass_llc_promisc = TRUE ;
+		mac_set_rx_mode(smc,RX_DISABLE_NSA) ;
+		break ;
+	case RX_DISABLE_LLC_PROMISC:
+		smc->os.hwm.pass_llc_promisc = FALSE ;
+		break ;
+	case RX_ENABLE_LLC_PROMISC:
+		smc->os.hwm.pass_llc_promisc = TRUE ;
+		break ;
+	case RX_ENABLE_ALLMULTI:
+	case RX_DISABLE_ALLMULTI:
+	case RX_ENABLE_PROMISC:
+	case RX_DISABLE_PROMISC:
+	case RX_ENABLE_NSA:
+	case RX_DISABLE_NSA:
+	default:
+		mac_set_rx_mode(smc,mode) ;
+		break ;
+	}
+}
+#endif	/* ifndef NDIS_OS2 */
+
+/*
+ * process receive queue
+ */
+void process_receive(smc)
+struct s_smc *smc ;
+{
+	int i ;
+	int n ;
+	int frag_count ;		/* number of RxDs of the curr rx buf */
+	int used_frags ;		/* number of RxDs of the curr frame */
+	struct s_smt_rx_queue *queue ;	/* points to the queue ctl struct */
+	struct s_smt_fp_rxd volatile *r ;	/* rxd pointer */
+	struct s_smt_fp_rxd volatile *rxd ;	/* first rxd of rx frame */
+	u_long rbctrl ;			/* receive buffer control word */
+	u_long rfsw ;			/* receive frame status word */
+	u_short rx_used ;
+	u_char far *virt ;
+	char far *data ;
+	SMbuf *mb ;
+	u_char fc ;			/* Frame control */
+	int len ;			/* Frame length */
+
+	smc->os.hwm.detec_count = 0 ;
+	queue = smc->hw.fp.rx[QUEUE_R1] ;
+	NDD_TRACE("RHxB",0,0,0) ;
+	for ( ; ; ) {
+		r = queue->rx_curr_get ;
+		rx_used = queue->rx_used ;
+		frag_count = 0 ;
+
+#ifdef	USE_BREAK_ISR
+		if (smc->os.hwm.leave_isr) {
+			goto rx_end ;
+		}
+#endif
+#ifdef	NDIS_OS2
+		if (offDepth) {
+			smc->os.hwm.rx_break = 1 ;
+			goto rx_end ;
+		}
+		smc->os.hwm.rx_break = 0 ;
+#endif
+#ifdef	ODI2
+		if (smc->os.hwm.rx_break) {
+			goto rx_end ;
+		}
+#endif
+		n = 0 ;
+		do {
+			DB_RX("Check RxD %x for OWN and EOF",(void *)r,0,5) ;
+			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+			rbctrl = CR_READ(r->rxd_rbctrl) ;
+			rbctrl = AIX_REVERSE(rbctrl) ;
+
+			if (rbctrl & BMU_OWN) {
+				NDD_TRACE("RHxE",r,rfsw,rbctrl) ;
+				DB_RX("End of RxDs",0,0,4) ;
+				goto rx_end ;
+			}
+			/*
+			 * out of RxD detection
+			 */
+			if (!rx_used) {
+				SK_BREAK() ;
+				SMT_PANIC(smc,HWM_E0009,HWM_E0009_MSG) ;
+				/* Either we don't have an RxD or all
+				 * RxDs are filled. Therefore it's allowed
+				 * for to set the STOPPED flag */
+				smc->hw.hw_state = STOPPED ;
+				mac_drv_clear_rx_queue(smc) ;
+				smc->hw.hw_state = STARTED ;
+				mac_drv_fill_rxd(smc) ;
+				smc->os.hwm.detec_count = 0 ;
+				goto rx_end ;
+			}
+			rfsw = AIX_REVERSE(r->rxd_rfsw) ;
+			if ((rbctrl & BMU_STF) != ((rbctrl & BMU_ST_BUF) <<5)) {
+				/*
+				 * The BMU_STF bit is deleted, 1 frame is
+				 * placed into more than 1 rx buffer
+				 *
+				 * skip frame by setting the rx len to 0
+				 *
+				 * if fragment count == 0
+				 *	The missing STF bit belongs to the
+				 *	current frame, search for the
+				 *	EOF bit to complete the frame
+				 * else
+				 *	the fragment belongs to the next frame,
+				 *	exit the loop and process the frame
+				 */
+				SK_BREAK() ;
+				rfsw = 0 ;
+				if (frag_count) {
+					break ;
+				}
+			}
+			n += rbctrl & 0xffff ;
+			r = r->rxd_next ;
+			frag_count++ ;
+			rx_used-- ;
+		} while (!(rbctrl & BMU_EOF)) ;
+		used_frags = frag_count ;
+		DB_RX("EOF set in RxD, used_frags = %d ",used_frags,0,5) ;
+
+		/* may be next 2 DRV_BUF_FLUSH() can be skipped, because */
+		/* BMU_ST_BUF will not be changed by the ASIC */
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+		while (rx_used && !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) {
+			DB_RX("Check STF bit in %x",(void *)r,0,5) ;
+			r = r->rxd_next ;
+			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+			frag_count++ ;
+			rx_used-- ;
+		}
+		DB_RX("STF bit found",0,0,5) ;
+
+		/*
+		 * The received frame is finished for the process receive
+		 */
+		rxd = queue->rx_curr_get ;
+		queue->rx_curr_get = r ;
+		queue->rx_free += frag_count ;
+		queue->rx_used = rx_used ;
+
+		/*
+		 * ASIC Errata no. 7 (STF - Bit Bug)
+		 */
+		rxd->rxd_rbctrl &= AIX_REVERSE(~BMU_STF) ;
+
+		for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){
+			DB_RX("dma_complete for RxD %x",(void *)r,0,5) ;
+			dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
+		}
+		smc->hw.fp.err_stats.err_valid++ ;
+		smc->mib.m[MAC0].fddiMACCopied_Ct++ ;
+
+		/* the length of the data including the FC */
+		len = (rfsw & RD_LENGTH) - 4 ;
+
+		DB_RX("frame length = %d",len,0,4) ;
+		/*
+		 * check the frame_lenght and all error flags
+		 */
+		if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){
+			if (rfsw & RD_S_MSRABT) {
+				DB_RX("Frame aborted by the FORMAC",0,0,2) ;
+				smc->hw.fp.err_stats.err_abort++ ;
+			}
+			/*
+			 * check frame status
+			 */
+			if (rfsw & RD_S_SEAC2) {
+				DB_RX("E-Indicator set",0,0,2) ;
+				smc->hw.fp.err_stats.err_e_indicator++ ;
+			}
+			if (rfsw & RD_S_SFRMERR) {
+				DB_RX("CRC error",0,0,2) ;
+				smc->hw.fp.err_stats.err_crc++ ;
+			}
+			if (rfsw & RX_FS_IMPL) {
+				DB_RX("Implementer frame",0,0,2) ;
+				smc->hw.fp.err_stats.err_imp_frame++ ;
+			}
+			goto abort_frame ;
+		}
+		if (len > FDDI_RAW_MTU-4) {
+			DB_RX("Frame to long error",0,0,2) ;
+			smc->hw.fp.err_stats.err_too_long++ ;
+			goto abort_frame ;
+		}
+		/*
+		 * SUPERNET 3 Bug: FORMAC delivers status words
+		 * of aborded frames to the BMU
+		 */
+		if (len <= 4) {
+			DB_RX("Frame length = 0",0,0,2) ;
+			goto abort_frame ;
+		}
+
+		if (len != (n-4)) {
+			DB_RX("BMU: rx len differs: [%d:%d]",len,n,4);
+			smc->os.hwm.rx_len_error++ ;
+			goto abort_frame ;
+		}
+
+		/*
+		 * Check SA == MA
+		 */
+		virt = (u_char far *) rxd->rxd_virt ;
+		DB_RX("FC = %x",*virt,0,2) ;
+		if (virt[12] == MA[5] &&
+		    virt[11] == MA[4] &&
+		    virt[10] == MA[3] &&
+		    virt[9] == MA[2] &&
+		    virt[8] == MA[1] &&
+		    (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) {
+			goto abort_frame ;
+		}
+
+		/*
+		 * test if LLC frame
+		 */
+		if (rfsw & RX_FS_LLC) {
+			/*
+			 * if pass_llc_promisc is disable
+			 *	if DA != Multicast or Broadcast or DA!=MA
+			 *		abort the frame
+			 */
+			if (!smc->os.hwm.pass_llc_promisc) {
+				if(!(virt[1] & GROUP_ADDR_BIT)) {
+					if (virt[6] != MA[5] ||
+					    virt[5] != MA[4] ||
+					    virt[4] != MA[3] ||
+					    virt[3] != MA[2] ||
+					    virt[2] != MA[1] ||
+					    virt[1] != MA[0]) {
+						DB_RX("DA != MA and not multi- or broadcast",0,0,2) ;
+						goto abort_frame ;
+					}
+				}
+			}
+
+			/*
+			 * LLC frame received
+			 */
+			DB_RX("LLC - receive",0,0,4) ;
+			mac_drv_rx_complete(smc,rxd,frag_count,len) ;
+		}
+		else {
+			if (!(mb = smt_get_mbuf(smc))) {
+				smc->hw.fp.err_stats.err_no_buf++ ;
+				DB_RX("No SMbuf; receive terminated",0,0,4) ;
+				goto abort_frame ;
+			}
+			data = smtod(mb,char *) - 1 ;
+
+			/*
+			 * copy the frame into a SMT_MBuf
+			 */
+#ifdef USE_OS_CPY
+			hwm_cpy_rxd2mb(rxd,data,len) ;
+#else
+			for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){
+				n = AIX_REVERSE(r->rxd_rbctrl) & RD_LENGTH ;
+				DB_RX("cp SMT frame to mb: len = %d",n,0,6) ;
+				memcpy(data,r->rxd_virt,n) ;
+				data += n ;
+			}
+			data = smtod(mb,char *) - 1 ;
+#endif
+			fc = *(char *)mb->sm_data = *data ;
+			mb->sm_len = len - 1 ;		/* len - fc */
+			data++ ;
+
+			/*
+			 * SMT frame received
+			 */
+			switch(fc) {
+			case FC_SMT_INFO :
+				smc->hw.fp.err_stats.err_smt_frame++ ;
+				DB_RX("SMT frame received ",0,0,5) ;
+
+				if (smc->os.hwm.pass_SMT) {
+					DB_RX("pass SMT frame ",0,0,5) ;
+					mac_drv_rx_complete(smc, rxd,
+						frag_count,len) ;
+				}
+				else {
+					DB_RX("requeue RxD",0,0,5) ;
+					mac_drv_requeue_rxd(smc,rxd,frag_count);
+				}
+
+				smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
+				break ;
+			case FC_SMT_NSA :
+				smc->hw.fp.err_stats.err_smt_frame++ ;
+				DB_RX("SMT frame received ",0,0,5) ;
+
+				/* if pass_NSA set pass the NSA frame or */
+				/* pass_SMT set and the A-Indicator */
+				/* is not set, pass the NSA frame */
+				if (smc->os.hwm.pass_NSA ||
+					(smc->os.hwm.pass_SMT &&
+					!(rfsw & A_INDIC))) {
+					DB_RX("pass SMT frame ",0,0,5) ;
+					mac_drv_rx_complete(smc, rxd,
+						frag_count,len) ;
+				}
+				else {
+					DB_RX("requeue RxD",0,0,5) ;
+					mac_drv_requeue_rxd(smc,rxd,frag_count);
+				}
+
+				smt_received_pack(smc,mb,(int)(rfsw>>25)) ;
+				break ;
+			case FC_BEACON :
+				if (smc->os.hwm.pass_DB) {
+					DB_RX("pass DB frame ",0,0,5) ;
+					mac_drv_rx_complete(smc, rxd,
+						frag_count,len) ;
+				}
+				else {
+					DB_RX("requeue RxD",0,0,5) ;
+					mac_drv_requeue_rxd(smc,rxd,frag_count);
+				}
+				smt_free_mbuf(smc,mb) ;
+				break ;
+			default :
+				/*
+				 * unknown FC abord the frame
+				 */
+				DB_RX("unknown FC error",0,0,2) ;
+				smt_free_mbuf(smc,mb) ;
+				DB_RX("requeue RxD",0,0,5) ;
+				mac_drv_requeue_rxd(smc,rxd,frag_count) ;
+				if ((fc & 0xf0) == FC_MAC)
+					smc->hw.fp.err_stats.err_mac_frame++ ;
+				else
+					smc->hw.fp.err_stats.err_imp_frame++ ;
+
+				break ;
+			}
+		}
+
+		DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ;
+		NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ;
+
+		continue ;
+	/*--------------------------------------------------------------------*/
+abort_frame:
+		DB_RX("requeue RxD",0,0,5) ;
+		mac_drv_requeue_rxd(smc,rxd,frag_count) ;
+
+		DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ;
+		NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ;
+	}
+rx_end:
+#ifdef	ALL_RX_COMPLETE
+	mac_drv_all_receives_complete(smc) ;
+#endif
+	return ;	/* lint bug: needs return detect end of function */
+}
+
+static void smt_to_llc(smc,mb)
+struct s_smc *smc ;
+SMbuf *mb ;
+{
+	u_char	fc ;
+
+	DB_RX("send a queued frame to the llc layer",0,0,4) ;
+	smc->os.hwm.r.len = mb->sm_len ;
+	smc->os.hwm.r.mb_pos = smtod(mb,char *) ;
+	fc = *smc->os.hwm.r.mb_pos ;
+	(void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc,
+		smc->os.hwm.r.mb_pos,(int)mb->sm_len) ;
+	smt_free_mbuf(smc,mb) ;
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(hwm_rx_frag)
+ *	void hwm_rx_frag(smc,virt,phys,len,frame_status)
+ *
+ * function	MACRO		(hardware module, hwmtm.h)
+ *		This function calls dma_master for preparing the
+ *		system hardware for the DMA transfer and initializes
+ *		the current RxD with the length and the physical and
+ *		virtual address of the fragment. Furthermore, it sets the
+ *		STF and EOF bits depending on the frame status byte,
+ *		switches the OWN flag of the RxD, so that it is owned by the
+ *		adapter and issues an rx_start.
+ *
+ * para	virt	virtual pointer to the fragment
+ *	len	the length of the fragment
+ *	frame_status	status of the frame, see design description
+ *
+ * NOTE:	It is possible to call this function with a fragment length
+ *		of zero.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void hwm_rx_frag(smc,virt,phys,len,frame_status)
+struct s_smc *smc ;
+char far *virt ;
+u_long phys ;
+int len ;
+int frame_status ;
+{
+	struct s_smt_fp_rxd volatile *r ;
+	u_int	rbctrl ;
+
+	NDD_TRACE("RHfB",virt,len,frame_status) ;
+	DB_RX("hwm_rx_frag: len = %d, frame_status = %x\n",len,frame_status,2) ;
+	r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ;
+	r->rxd_virt = virt ;
+	r->rxd_rbadr = AIX_REVERSE(phys) ;
+	rbctrl = AIX_REVERSE( (((u_long)frame_status &
+		(FIRST_FRAG|LAST_FRAG))<<26) |
+		(((u_long) frame_status & FIRST_FRAG) << 21) |
+		BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ;
+	r->rxd_rbctrl = rbctrl ;
+
+	DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+	outpd(ADDR(B0_R1_CSR),CSR_START) ;
+	smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ;
+	smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ;
+	smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ;
+	NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ;
+}
+
+#ifndef	NDIS_OS2
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_rx_frag)
+ *	int mac_drv_rx_frag(smc,virt,len)
+ *
+ * function	DOWNCALL	(hwmtm.c)
+ *		mac_drv_rx_frag fills the fragment with a part of the frame.
+ *
+ * para	virt	the virtual address of the fragment
+ *	len	the length in bytes of the fragment
+ *
+ * return 0:	success code, no errors possible
+ *
+ *	END_MANUAL_ENTRY
+ */
+int mac_drv_rx_frag(smc,virt,len)
+struct s_smc *smc ;
+void far *virt ;
+int len ;
+{
+	NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ;
+
+	DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ;
+	memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ;
+	smc->os.hwm.r.mb_pos += len ;
+
+	NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ;
+	return(0) ;
+}
+#endif
+
+
+/*
+ *	BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
+ *
+ * void mac_drv_clear_rx_queue(smc)
+ * struct s_smc *smc ;
+ *
+ * function	DOWNCALL	(hardware module, hwmtm.c)
+ *		mac_drv_clear_rx_queue is called by the OS-specific module
+ *		after it has issued a card_stop.
+ *		In this case, the frames in the receive queue are obsolete and
+ *		should be removed. For removing mac_drv_clear_rx_queue
+ *		calls dma_master for each RxD and mac_drv_clear_rxd for each
+ *		receive buffer.
+ *
+ * NOTE:	calling sequence card_stop:
+ *		CLI_FBI(), card_stop(),
+ *		mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
+ *
+ * NOTE:	The caller is responsible that the BMUs are idle
+ *		when this function is called.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_clear_rx_queue(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_fp_rxd volatile *r ;
+	struct s_smt_fp_rxd volatile *next_rxd ;
+	struct s_smt_rx_queue *queue ;
+	int frag_count ;
+	int i ;
+
+	if (smc->hw.hw_state != STOPPED) {
+		SK_BREAK() ;
+		SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ;
+		return ;
+	}
+
+	queue = smc->hw.fp.rx[QUEUE_R1] ;
+	DB_RX("clear_rx_queue",0,0,5) ;
+
+	/*
+	 * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers
+	 */
+	r = queue->rx_curr_get ;
+	while (queue->rx_used) {
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+		DB_RX("switch OWN bit of RxD 0x%x ",r,0,5) ;
+		r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ;
+		frag_count = 1 ;
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+		r = r->rxd_next ;
+		DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+		while (r != queue->rx_curr_put &&
+			!(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) {
+			DB_RX("Check STF bit in %x",(void *)r,0,5) ;
+			r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ;
+			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ;
+			r = r->rxd_next ;
+			DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ;
+			frag_count++ ;
+		}
+		DB_RX("STF bit found",0,0,5) ;
+		next_rxd = r ;
+
+		for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){
+			DB_RX("dma_complete for RxD %x",(void *)r,0,5) ;
+			dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR);
+		}
+
+		DB_RX("mac_drv_clear_rxd: RxD %x frag_count %d ",
+			(void *)queue->rx_curr_get,frag_count,5) ;
+		mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ;
+
+		queue->rx_curr_get = next_rxd ;
+		queue->rx_used -= frag_count ;
+		queue->rx_free += frag_count ;
+	}
+}
+
+
+/*
+	-------------------------------------------------------------
+	SEND FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+/*
+ *	BEGIN_MANUAL_ENTRY(hwm_tx_init)
+ *	int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status)
+ *
+ * function	DOWN_CALL	(hardware module, hwmtm.c)
+ *		hwm_tx_init checks if the frame can be sent through the
+ *		corresponding send queue.
+ *
+ * para	fc	the frame control. To determine through which
+ *		send queue the frame should be transmitted.
+ *		0x50 - 0x57:	asynchronous LLC frame
+ *		0xD0 - 0xD7:	synchronous LLC frame
+ *		0x41, 0x4F:	SMT frame to the network
+ *		0x42:		SMT frame to the network and to the local SMT
+ *		0x43:		SMT frame to the local SMT
+ *	frag_count	count of the fragments for this frame
+ *	frame_len	length of the frame
+ *	frame_status	status of the frame, the send queue bit is already
+ *			specified
+ *
+ * return		frame_status
+ *
+ *	END_MANUAL_ENTRY
+ */
+int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status)
+struct	s_smc *smc ;
+u_char fc ;
+int frag_count ;
+int frame_len ;
+int frame_status ;
+{
+	NDD_TRACE("THiB",fc,frag_count,frame_len) ;
+	smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ;
+	smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ;
+	smc->os.hwm.tx_len = frame_len ;
+	DB_TX("hwm_tx_init: fc = %x, len = %d",fc,frame_len,3) ;
+	if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) {
+		frame_status |= LAN_TX ;
+	}
+	else {
+		switch (fc) {
+		case FC_SMT_INFO :
+		case FC_SMT_NSA :
+			frame_status |= LAN_TX ;
+			break ;
+		case FC_SMT_LOC :
+			frame_status |= LOC_TX ;
+			break ;
+		case FC_SMT_LAN_LOC :
+			frame_status |= LAN_TX | LOC_TX ;
+			break ;
+		default :
+			SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ;
+		}
+	}
+	if (!smc->hw.mac_ring_is_up) {
+		frame_status &= ~LAN_TX ;
+		frame_status |= RING_DOWN ;
+		DB_TX("Ring is down: terminate LAN_TX",0,0,2) ;
+	}
+	if (frag_count > smc->os.hwm.tx_p->tx_free) {
+#ifndef	NDIS_OS2
+		mac_drv_clear_txd(smc) ;
+		if (frag_count > smc->os.hwm.tx_p->tx_free) {
+			DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ;
+			frame_status &= ~LAN_TX ;
+			frame_status |= OUT_OF_TXD ;
+		}
+#else
+		DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ;
+		frame_status &= ~LAN_TX ;
+		frame_status |= OUT_OF_TXD ;
+#endif
+	}
+	DB_TX("frame_status = %x",frame_status,0,3) ;
+	NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ;
+	return(frame_status) ;
+}
+
+/*
+ *	BEGIN_MANUAL_ENTRY(hwm_tx_frag)
+ *	void hwm_tx_frag(smc,virt,phys,len,frame_status)
+ *
+ * function	DOWNCALL	(hardware module, hwmtm.c)
+ *		If the frame should be sent to the LAN, this function calls
+ *		dma_master, fills the current TxD with the virtual and the
+ *		physical address, sets the STF and EOF bits dependent on
+ *		the frame status, and requests the BMU to start the
+ *		transmit.
+ *		If the frame should be sent to the local SMT, an SMT_MBuf
+ *		is allocated if the FIRST_FRAG bit is set in the frame_status.
+ *		The fragment of the frame is copied into the SMT MBuf.
+ *		The function smt_received_pack is called if the LAST_FRAG
+ *		bit is set in the frame_status word.
+ *
+ * para	virt	virtual pointer to the fragment
+ *	len	the length of the fragment
+ *	frame_status	status of the frame, see design description
+ *
+ * return	nothing returned, no parameter is modified
+ *
+ * NOTE:	It is possible to invoke this macro with a fragment length
+ *		of zero.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void hwm_tx_frag(smc,virt,phys,len,frame_status)
+struct	s_smc *smc ;
+char far *virt ;
+u_long phys ;
+int len ;
+int frame_status ;
+{
+	struct s_smt_fp_txd volatile *t ;
+	struct s_smt_tx_queue *queue ;
+	u_int	tbctrl ;
+
+	queue = smc->os.hwm.tx_p ;
+
+	NDD_TRACE("THfB",virt,len,frame_status) ;
+	/* Bug fix: AF / May 31 1999 (#missing)
+	 * snmpinfo problem reported by IBM is caused by invalid
+	 * t-pointer (txd) if LAN_TX is not set but LOC_TX only.
+	 * Set: t = queue->tx_curr_put  here !
+	 */
+	t = queue->tx_curr_put ;
+
+	DB_TX("hwm_tx_frag: len = %d, frame_status = %x ",len,frame_status,2) ;
+	if (frame_status & LAN_TX) {
+		/* '*t' is already defined */
+		DB_TX("LAN_TX: TxD = %x, virt = %x ",t,virt,3) ;
+		t->txd_virt = virt ;
+		t->txd_txdscr = AIX_REVERSE(smc->os.hwm.tx_descr) ;
+		t->txd_tbadr = AIX_REVERSE(phys) ;
+		tbctrl = AIX_REVERSE((((u_long)frame_status &
+			(FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) |
+			BMU_OWN|BMU_CHECK |len) ;
+		t->txd_tbctrl = tbctrl ;
+
+#ifndef	AIX
+		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+		outpd(queue->tx_bmu_ctl,CSR_START) ;
+#else	/* ifndef AIX */
+		DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+		if (frame_status & QUEUE_A0) {
+			outpd(ADDR(B0_XA_CSR),CSR_START) ;
+		}
+		else {
+			outpd(ADDR(B0_XS_CSR),CSR_START) ;
+		}
+#endif
+		queue->tx_free-- ;
+		queue->tx_used++ ;
+		queue->tx_curr_put = t->txd_next ;
+		if (frame_status & LAST_FRAG) {
+			smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
+		}
+	}
+	if (frame_status & LOC_TX) {
+		DB_TX("LOC_TX: ",0,0,3) ;
+		if (frame_status & FIRST_FRAG) {
+			if(!(smc->os.hwm.tx_mb = smt_get_mbuf(smc))) {
+				smc->hw.fp.err_stats.err_no_buf++ ;
+				DB_TX("No SMbuf; transmit terminated",0,0,4) ;
+			}
+			else {
+				smc->os.hwm.tx_data =
+					smtod(smc->os.hwm.tx_mb,char *) - 1 ;
+#ifdef USE_OS_CPY
+#ifdef PASS_1ST_TXD_2_TX_COMP
+				hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
+					smc->os.hwm.tx_len) ;
+#endif
+#endif
+			}
+		}
+		if (smc->os.hwm.tx_mb) {
+#ifndef	USE_OS_CPY
+			DB_TX("copy fragment into MBuf ",0,0,3) ;
+			memcpy(smc->os.hwm.tx_data,virt,len) ;
+			smc->os.hwm.tx_data += len ;
+#endif
+			if (frame_status & LAST_FRAG) {
+#ifdef	USE_OS_CPY
+#ifndef PASS_1ST_TXD_2_TX_COMP
+				/*
+				 * hwm_cpy_txd2mb(txd,data,len) copies 'len' 
+				 * bytes from the virtual pointer in 'rxd'
+				 * to 'data'. The virtual pointer of the 
+				 * os-specific tx-buffer should be written
+				 * in the LAST txd.
+				 */ 
+				hwm_cpy_txd2mb(t,smc->os.hwm.tx_data,
+					smc->os.hwm.tx_len) ;
+#endif	/* nPASS_1ST_TXD_2_TX_COMP */
+#endif	/* USE_OS_CPY */
+				smc->os.hwm.tx_data =
+					smtod(smc->os.hwm.tx_mb,char *) - 1 ;
+				*(char *)smc->os.hwm.tx_mb->sm_data =
+					*smc->os.hwm.tx_data ;
+				smc->os.hwm.tx_data++ ;
+				smc->os.hwm.tx_mb->sm_len =
+					smc->os.hwm.tx_len - 1 ;
+				DB_TX("pass LLC frame to SMT ",0,0,3) ;
+				smt_received_pack(smc,smc->os.hwm.tx_mb,
+						RD_FS_LOCAL) ;
+			}
+		}
+	}
+	NDD_TRACE("THfE",t,queue->tx_free,0) ;
+}
+
+
+/*
+ * queues a receive for later send
+ */
+static void queue_llc_rx(smc,mb)
+struct	s_smc *smc ;
+SMbuf	*mb ;
+{
+	DB_GEN("queue_llc_rx: mb = %x",(void *)mb,0,4) ;
+	smc->os.hwm.queued_rx_frames++ ;
+	mb->sm_next = (SMbuf *)NULL ;
+	if (smc->os.hwm.llc_rx_pipe == 0) {
+		smc->os.hwm.llc_rx_pipe = mb ;
+	}
+	else {
+		smc->os.hwm.llc_rx_tail->sm_next = mb ;
+	}
+	smc->os.hwm.llc_rx_tail = mb ;
+
+	/*
+	 * force an timer IRQ to receive the data
+	 */
+	if (!smc->os.hwm.isr_flag) {
+		smt_force_irq(smc) ;
+	}
+}
+
+/*
+ * get a SMbuf from the llc_rx_queue
+ */
+static SMbuf *get_llc_rx(smc)
+struct	s_smc *smc ;
+{
+	SMbuf	*mb ;
+
+	if ((mb = smc->os.hwm.llc_rx_pipe)) {
+		smc->os.hwm.queued_rx_frames-- ;
+		smc->os.hwm.llc_rx_pipe = mb->sm_next ;
+	}
+	DB_GEN("get_llc_rx: mb = 0x%x",(void *)mb,0,4) ;
+	return(mb) ;
+}
+
+/*
+ * queues a transmit SMT MBuf during the time were the MBuf is
+ * queued the TxD ring
+ */
+static void queue_txd_mb(smc,mb)
+struct	s_smc *smc ;
+SMbuf	*mb ;
+{
+	DB_GEN("_rx: queue_txd_mb = %x",(void *)mb,0,4) ;
+	smc->os.hwm.queued_txd_mb++ ;
+	mb->sm_next = (SMbuf *)NULL ;
+	if (smc->os.hwm.txd_tx_pipe == 0) {
+		smc->os.hwm.txd_tx_pipe = mb ;
+	}
+	else {
+		smc->os.hwm.txd_tx_tail->sm_next = mb ;
+	}
+	smc->os.hwm.txd_tx_tail = mb ;
+}
+
+/*
+ * get a SMbuf from the txd_tx_queue
+ */
+static SMbuf *get_txd_mb(smc)
+struct	s_smc *smc ;
+{
+	SMbuf *mb ;
+
+	if ((mb = smc->os.hwm.txd_tx_pipe)) {
+		smc->os.hwm.queued_txd_mb-- ;
+		smc->os.hwm.txd_tx_pipe = mb->sm_next ;
+	}
+	DB_GEN("get_txd_mb: mb = 0x%x",(void *)mb,0,4) ;
+	return(mb) ;
+}
+
+/*
+ *	SMT Send function
+ */
+void smt_send_mbuf(smc,mb,fc)
+struct s_smc	*smc;
+SMbuf		*mb;
+int		fc;
+{
+	char far *data ;
+	int	len ;
+	int	n ;
+	int	i ;
+	int	frag_count ;
+	int	frame_status ;
+	SK_LOC_DECL(char far,*virt[3]) ;
+	int	frag_len[3] ;
+	struct s_smt_tx_queue *queue ;
+	struct s_smt_fp_txd volatile *t ;
+	u_long	phys ;
+	u_int	tbctrl ;
+
+	NDD_TRACE("THSB",mb,fc,0) ;
+	DB_TX("smt_send_mbuf: mb = 0x%x, fc = 0x%x",mb,fc,4) ;
+
+	mb->sm_off-- ;	/* set to fc */
+	mb->sm_len++ ;	/* + fc */
+	data = smtod(mb,char *) ;
+	*data = fc ;
+	if (fc == FC_SMT_LOC)
+		*data = FC_SMT_INFO ;
+
+	/*
+	 * determine the frag count and the virt addresses of the frags
+	 */
+	frag_count = 0 ;
+	len = mb->sm_len ;
+	while (len) {
+		n = SMT_PAGESIZE - ((long)data & (SMT_PAGESIZE-1)) ;
+		if (n >= len) {
+			n = len ;
+		}
+		DB_TX("frag: virt/len = 0x%x/%d ",(void *)data,n,5) ;
+		virt[frag_count] = data ;
+		frag_len[frag_count] = n ;
+		frag_count++ ;
+		len -= n ;
+		data += n ;
+	}
+
+	/*
+	 * determine the frame status
+	 */
+	queue = smc->hw.fp.tx[QUEUE_A0] ;
+	if (fc == FC_BEACON || fc == FC_SMT_LOC) {
+		frame_status = LOC_TX ;
+	}
+	else {
+		frame_status = LAN_TX ;
+		if ((smc->os.hwm.pass_NSA &&(fc == FC_SMT_NSA)) ||
+		   (smc->os.hwm.pass_SMT &&(fc == FC_SMT_INFO)))
+			frame_status |= LOC_TX ;
+	}
+
+	if (!smc->hw.mac_ring_is_up || frag_count > queue->tx_free) {
+		if (frame_status &= ~LAN_TX) {
+			DB_TX("Ring is down: terminate LAN_TX",0,0,2) ;
+		}
+		else {
+			DB_TX("Ring is down: terminate transmission",0,0,2) ;
+			smt_free_mbuf(smc,mb) ;
+			return ;
+		}
+	}
+	DB_TX("frame_status = 0x%x ",frame_status,0,5) ;
+
+	if ((frame_status & LAN_TX) && (frame_status & LOC_TX)) {
+		mb->sm_use_count = 2 ;
+	}
+
+	if (frame_status & LAN_TX) {
+		t = queue->tx_curr_put ;
+		frame_status |= FIRST_FRAG ;
+		for (i = 0; i < frag_count; i++) {
+			DB_TX("init TxD = 0x%x",(void *)t,0,5) ;
+			if (i == frag_count-1) {
+				frame_status |= LAST_FRAG ;
+				t->txd_txdscr = AIX_REVERSE(TX_DESCRIPTOR |
+					(((u_long)(mb->sm_len-1)&3) << 27)) ;
+			}
+			t->txd_virt = virt[i] ;
+			phys = dma_master(smc, (void far *)virt[i],
+				frag_len[i], DMA_RD|SMT_BUF) ;
+			t->txd_tbadr = AIX_REVERSE(phys) ;
+			tbctrl = AIX_REVERSE((((u_long) frame_status &
+				(FIRST_FRAG|LAST_FRAG)) << 26) |
+				BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i]) ;
+			t->txd_tbctrl = tbctrl ;
+#ifndef	AIX
+			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+			outpd(queue->tx_bmu_ctl,CSR_START) ;
+#else
+			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+			outpd(ADDR(B0_XA_CSR),CSR_START) ;
+#endif
+			frame_status &= ~FIRST_FRAG ;
+			queue->tx_curr_put = t = t->txd_next ;
+			queue->tx_free-- ;
+			queue->tx_used++ ;
+		}
+		smc->mib.m[MAC0].fddiMACTransmit_Ct++ ;
+		queue_txd_mb(smc,mb) ;
+	}
+
+	if (frame_status & LOC_TX) {
+		DB_TX("pass Mbuf to LLC queue",0,0,5) ;
+		queue_llc_rx(smc,mb) ;
+	}
+
+	/*
+	 * We need to unqueue the free SMT_MBUFs here, because it may
+	 * be that the SMT want's to send more than 1 frame for one down call
+	 */
+	mac_drv_clear_txd(smc) ;
+	NDD_TRACE("THSE",t,queue->tx_free,frag_count) ;
+}
+
+/*	BEGIN_MANUAL_ENTRY(mac_drv_clear_txd)
+ *	void mac_drv_clear_txd(smc)
+ *
+ * function	DOWNCALL	(hardware module, hwmtm.c)
+ *		mac_drv_clear_txd searches in both send queues for TxD's
+ *		which were finished by the adapter. It calls dma_complete
+ *		for each TxD. If the last fragment of an LLC frame is
+ *		reached, it calls mac_drv_tx_complete to release the
+ *		send buffer.
+ *
+ * return	nothing
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_clear_txd(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_tx_queue *queue ;
+	struct s_smt_fp_txd volatile *t1 ;
+	struct s_smt_fp_txd volatile *t2=0 ;
+	SMbuf *mb ;
+	u_long	tbctrl ;
+	int i ;
+	int frag_count ;
+	int n ;
+
+	NDD_TRACE("THcB",0,0,0) ;
+	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
+		queue = smc->hw.fp.tx[i] ;
+		t1 = queue->tx_curr_get ;
+		DB_TX("clear_txd: QUEUE = %d (0=sync/1=async)",i,0,5) ;
+
+		for ( ; ; ) {
+			frag_count = 0 ;
+
+			do {
+				DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ;
+				DB_TX("check OWN/EOF bit of TxD 0x%x",t1,0,5) ;
+				tbctrl = CR_READ(t1->txd_tbctrl) ;
+				tbctrl = AIX_REVERSE(tbctrl) ;
+
+				if (tbctrl & BMU_OWN || !queue->tx_used){
+					DB_TX("End of TxDs queue %d",i,0,4) ;
+					goto free_next_queue ;	/* next queue */
+				}
+				t1 = t1->txd_next ;
+				frag_count++ ;
+			} while (!(tbctrl & BMU_EOF)) ;
+
+			t1 = queue->tx_curr_get ;
+			for (n = frag_count; n; n--) {
+				tbctrl = AIX_REVERSE(t1->txd_tbctrl) ;
+				dma_complete(smc,
+					(union s_fp_descr volatile *) t1,
+					(int) (DMA_RD |
+					((tbctrl & BMU_SMT_TX) >> 18))) ;
+				t2 = t1 ;
+				t1 = t1->txd_next ;
+			}
+
+			if (tbctrl & BMU_SMT_TX) {
+				mb = get_txd_mb(smc) ;
+				smt_free_mbuf(smc,mb) ;
+			}
+			else {
+#ifndef PASS_1ST_TXD_2_TX_COMP
+				DB_TX("mac_drv_tx_comp for TxD 0x%x",t2,0,4) ;
+				mac_drv_tx_complete(smc,t2) ;
+#else
+				DB_TX("mac_drv_tx_comp for TxD 0x%x",
+					queue->tx_curr_get,0,4) ;
+				mac_drv_tx_complete(smc,queue->tx_curr_get) ;
+#endif
+			}
+			queue->tx_curr_get = t1 ;
+			queue->tx_free += frag_count ;
+			queue->tx_used -= frag_count ;
+		}
+free_next_queue: ;
+	}
+	NDD_TRACE("THcE",0,0,0) ;
+}
+
+/*
+ *	BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue)
+ *
+ * void mac_drv_clear_tx_queue(smc)
+ * struct s_smc *smc ;
+ *
+ * function	DOWNCALL	(hardware module, hwmtm.c)
+ *		mac_drv_clear_tx_queue is called from the SMT when
+ *		the RMT state machine has entered the ISOLATE state.
+ *		This function is also called by the os-specific module
+ *		after it has called the function card_stop().
+ *		In this case, the frames in the send queues are obsolete and
+ *		should be removed.
+ *
+ * note		calling sequence:
+ *		CLI_FBI(), card_stop(),
+ *		mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(),
+ *
+ * NOTE:	The caller is responsible that the BMUs are idle
+ *		when this function is called.
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_clear_tx_queue(smc)
+struct s_smc *smc ;
+{
+	struct s_smt_fp_txd volatile *t ;
+	struct s_smt_tx_queue *queue ;
+	int tx_used ;
+	int i ;
+
+	if (smc->hw.hw_state != STOPPED) {
+		SK_BREAK() ;
+		SMT_PANIC(smc,HWM_E0011,HWM_E0011_MSG) ;
+		return ;
+	}
+
+	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
+		queue = smc->hw.fp.tx[i] ;
+		DB_TX("clear_tx_queue: QUEUE = %d (0=sync/1=async)",i,0,5) ;
+
+		/*
+		 * switch the OWN bit of all pending frames to the host
+		 */
+		t = queue->tx_curr_get ;
+		tx_used = queue->tx_used ;
+		while (tx_used) {
+			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ;
+			DB_TX("switch OWN bit of TxD 0x%x ",t,0,5) ;
+			t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ;
+			DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ;
+			t = t->txd_next ;
+			tx_used-- ;
+		}
+	}
+
+	/*
+	 * release all TxD's for both send queues
+	 */
+	mac_drv_clear_txd(smc) ;
+
+	for (i = QUEUE_S; i <= QUEUE_A0; i++) {
+		queue = smc->hw.fp.tx[i] ;
+		t = queue->tx_curr_get ;
+
+		/*
+		 * write the phys pointer of the NEXT descriptor into the
+		 * BMU's current address descriptor pointer and set
+		 * tx_curr_get and tx_curr_put to this position
+		 */
+		if (i == QUEUE_S) {
+			outpd(ADDR(B5_XS_DA),AIX_REVERSE(t->txd_ntdadr)) ;
+		}
+		else {
+			outpd(ADDR(B5_XA_DA),AIX_REVERSE(t->txd_ntdadr)) ;
+		}
+
+		queue->tx_curr_put = queue->tx_curr_get->txd_next ;
+		queue->tx_curr_get = queue->tx_curr_put ;
+	}
+}
+
+
+/*
+	-------------------------------------------------------------
+	TEST FUNCTIONS:
+	-------------------------------------------------------------
+*/
+
+#ifdef	DEBUG
+/*
+ *	BEGIN_MANUAL_ENTRY(mac_drv_debug_lev)
+ *	void mac_drv_debug_lev(smc,flag,lev)
+ *
+ * function	DOWNCALL	(drvsr.c)
+ *		To get a special debug info the user can assign a debug level
+ *		to any debug flag.
+ *
+ * para	flag	debug flag, possible values are:
+ *			= 0:	reset all debug flags (the defined level is
+ *				ignored)
+ *			= 1:	debug.d_smtf
+ *			= 2:	debug.d_smt
+ *			= 3:	debug.d_ecm
+ *			= 4:	debug.d_rmt
+ *			= 5:	debug.d_cfm
+ *			= 6:	debug.d_pcm
+ *
+ *			= 10:	debug.d_os.hwm_rx (hardware module receive path)
+ *			= 11:	debug.d_os.hwm_tx(hardware module transmit path)
+ *			= 12:	debug.d_os.hwm_gen(hardware module general flag)
+ *
+ *	lev	debug level
+ *
+ *	END_MANUAL_ENTRY
+ */
+void mac_drv_debug_lev(smc,flag,lev)
+struct s_smc *smc ;
+int flag ;
+int lev ;
+{
+	switch(flag) {
+	case (int)NULL:
+		DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ;
+		DB_P.d_cfm = 0 ;
+		DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ;
+#ifdef	SBA
+		DB_P.d_sba = 0 ;
+#endif
+#ifdef	ESS
+		DB_P.d_ess = 0 ;
+#endif
+		break ;
+	case DEBUG_SMTF:
+		DB_P.d_smtf = lev ;
+		break ;
+	case DEBUG_SMT:
+		DB_P.d_smt = lev ;
+		break ;
+	case DEBUG_ECM:
+		DB_P.d_ecm = lev ;
+		break ;
+	case DEBUG_RMT:
+		DB_P.d_rmt = lev ;
+		break ;
+	case DEBUG_CFM:
+		DB_P.d_cfm = lev ;
+		break ;
+	case DEBUG_PCM:
+		DB_P.d_pcm = lev ;
+		break ;
+	case DEBUG_SBA:
+#ifdef	SBA
+		DB_P.d_sba = lev ;
+#endif
+		break ;
+	case DEBUG_ESS:
+#ifdef	ESS
+		DB_P.d_ess = lev ;
+#endif
+		break ;
+	case DB_HWM_RX:
+		DB_P.d_os.hwm_rx = lev ;
+		break ;
+	case DB_HWM_TX:
+		DB_P.d_os.hwm_tx = lev ;
+		break ;
+	case DB_HWM_GEN:
+		DB_P.d_os.hwm_gen = lev ;
+		break ;
+	default:
+		break ;
+	}
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/hwt.c linux.18p8/drivers/net/skfp/hwt.c
--- linux.vanilla/drivers/net/skfp/hwt.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/hwt.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,314 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+ * Timer Driver for FBI board (timer chip 82C54)
+ */
+
+/*
+ * Modifications:
+ *
+ *	28-Jun-1994 sw	Edit v1.6.
+ *			MCA: Added support for the SK-NET FDDI-FM2 adapter. The
+ *			 following functions have been added(+) or modified(*):
+ *			 hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*)
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)hwt.c	1.13 97/04/23 (C) SK " ;
+#endif
+
+/*
+ * Prototypes of local functions.
+ */
+/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
+/*static*/ void hwt_restart() ;
+
+/************************
+ *
+ *	hwt_start
+ *
+ *	Start hardware timer (clock ticks are 16us).
+ *
+ *	void hwt_start(
+ *		struct s_smc *smc,
+ *		u_long time) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ *
+ *	time - The time in units of 16us to load the timer with.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+#define	HWT_MAX	(65000)
+
+void hwt_start(smc, time)
+struct s_smc *smc ;
+u_long time ;
+{
+	u_short	cnt ;
+
+	if (time > HWT_MAX)
+		time = HWT_MAX ;
+
+	smc->hw.t_start = time ;
+	smc->hw.t_stop = 0L ;
+
+	cnt = (u_short)time ;
+	/*
+	 * if time < 16 us
+	 *	time = 16 us
+	 */
+	if (!cnt)
+		cnt++ ;
+#ifndef	PCI
+	/*
+	 * 6.25MHz -> CLK0 : T0 (cnt0 = 16us)	-> OUT0
+	 *    OUT0 -> CLK1 : T1 (cnt1)	OUT1	-> ISRA(IS_TIMINT)
+	 */
+	OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ;	/* counter 1, mode 0 */
+	OUT_82c54_TIMER(1,cnt & 0xff) ;		/* LSB */
+	OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ;	/* MSB */
+	/*
+	 * start timer by switching counter 0 to mode 3
+	 *	T0 resolution 16 us (CLK0=0.16us)
+	 */
+	OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ;	/* counter 0, mode 3 */
+	OUT_82c54_TIMER(0,100) ;		/* LSB */
+	OUT_82c54_TIMER(0,0) ;			/* MSB */
+#else	/* PCI */
+	outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;	/* Load timer value. */
+	outpw(ADDR(B2_TI_CRTL), TIM_START) ;		/* Start timer. */
+#endif	/* PCI */
+	smc->hw.timer_activ = TRUE ;
+}
+
+/************************
+ *
+ *	hwt_stop
+ *
+ *	Stop hardware timer.
+ *
+ *	void hwt_stop(
+ *		struct s_smc *smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void hwt_stop(smc)
+struct s_smc *smc ;
+{
+#ifndef PCI
+	/* stop counter 0 by switching to mode 0 */
+	OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ;	/* counter 0, mode 0 */
+	OUT_82c54_TIMER(0,0) ;			/* LSB */
+	OUT_82c54_TIMER(0,0) ;			/* MSB */
+#else	/* PCI */
+	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
+	outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
+#endif	/* PCI */
+
+	smc->hw.timer_activ = FALSE ;
+}
+
+/************************
+ *
+ *	hwt_init
+ *
+ *	Initialize hardware timer.
+ *
+ *	void hwt_init(
+ *		struct s_smc *smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void hwt_init(smc)
+struct s_smc *smc ;
+{
+	smc->hw.t_start = 0 ;
+	smc->hw.t_stop	= 0 ;
+	smc->hw.timer_activ = FALSE ;
+
+	hwt_restart(smc) ;
+}
+
+/************************
+ *
+ *	hwt_restart
+ *
+ *	Clear timer interrupt.
+ *
+ *	void hwt_restart(
+ *		struct s_smc *smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void hwt_restart(smc)
+struct s_smc *smc ;
+{
+	hwt_stop(smc) ;
+#ifndef	PCI
+	OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ;	/* counter 1, mode 0 */
+	OUT_82c54_TIMER(1,1 ) ;			/* LSB */
+	OUT_82c54_TIMER(1,0 ) ;			/* MSB */
+#endif
+}
+
+/************************
+ *
+ *	hwt_read
+ *
+ *	Stop hardware timer and read time elapsed since last start.
+ *
+ *	u_long hwt_read(smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	The elapsed time since last start in units of 16us.
+ *
+ ************************/
+u_long hwt_read(smc)
+struct s_smc *smc ;
+{
+	u_short	tr ;
+#ifndef	PCI
+	u_short	is ;
+#else
+	u_long	is ;
+#endif
+
+	if (smc->hw.timer_activ) {
+		hwt_stop(smc) ;
+#ifndef	PCI
+		OUT_82c54_TIMER(3,1<<6) ;	/* latch command */
+		tr = IN_82c54_TIMER(1) & 0xff ;
+		tr += (IN_82c54_TIMER(1) & 0xff)<<8 ;
+#else	/* PCI */
+		tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
+#endif	/* PCI */
+		is = GET_ISR() ;
+		/* Check if timer expired (or wraparound). */
+		if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
+			hwt_restart(smc) ;
+			smc->hw.t_stop = smc->hw.t_start ;
+		}
+		else
+			smc->hw.t_stop = smc->hw.t_start - tr ;
+	}
+	return (smc->hw.t_stop) ;
+}
+
+#ifdef	PCI
+/************************
+ *
+ *	hwt_quick_read
+ *
+ *	Stop hardware timer and read timer value and start the timer again.
+ *
+ *	u_long hwt_read(smc) ;
+ * In
+ *	smc - A pointer to the SMT Context structure.
+ * Out
+ *	current timer value in units of 80ns.
+ *
+ ************************/
+u_long hwt_quick_read(smc)
+struct s_smc *smc ;
+{
+	u_long interval ;
+	u_long time ;
+
+	interval = inpd(ADDR(B2_TI_INI)) ;
+	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
+	time = inpd(ADDR(B2_TI_VAL)) ;
+	outpd(ADDR(B2_TI_INI),time) ;
+	outpw(ADDR(B2_TI_CRTL), TIM_START) ;
+	outpd(ADDR(B2_TI_INI),interval) ;
+
+	return(time) ;
+}
+
+/************************
+ *
+ *	hwt_wait_time(smc,start,duration)
+ *
+ *	This function returnes after the amount of time is elapsed
+ *	since the start time.
+ * 
+ * para	start		start time
+ *	duration	time to wait
+ *
+ * NOTE: The fuction will return immediatly, if the timer is not 
+ *	 started
+ ************************/
+void hwt_wait_time(smc,start,duration)
+struct s_smc *smc ;
+u_long	start ;
+long	duration ;
+{
+	long	diff ;
+	long	interval ;
+	int	wrapped ;
+
+	/*
+	 * check if timer is running
+	 */
+	if (smc->hw.timer_activ == FALSE ||
+		hwt_quick_read(smc) == hwt_quick_read(smc)) {
+		return ;
+	}
+
+	interval = inpd(ADDR(B2_TI_INI)) ;
+	if (interval > duration) {
+		do {
+			diff = (long)(start - hwt_quick_read(smc)) ;
+			if (diff < 0) {
+				diff += interval ;
+			}
+		} while (diff <= duration) ;
+	}
+	else {
+		diff = interval ;
+		wrapped = 0 ;
+		do {
+			if (!wrapped) {
+				if (hwt_quick_read(smc) >= start) {
+					diff += interval ;
+					wrapped = 1 ;
+				}
+			}
+			else {
+				if (hwt_quick_read(smc) < start) {
+					wrapped = 0 ;
+				}
+			}
+		} while (diff <= duration) ;
+	}
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/lnkstat.c linux.18p8/drivers/net/skfp/lnkstat.c
--- linux.vanilla/drivers/net/skfp/lnkstat.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/lnkstat.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,209 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	IBM FDDI read error log function
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/lnkstat.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)lnkstat.c	1.8 97/04/11 (C) SK " ;
+#endif
+
+#ifdef	sun
+#define _far
+#endif
+
+#define EL_IS_OK(x,l)	((((int)&(((struct s_error_log *)0)->x)) + \
+			sizeof(er->x)) <= l)
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+	u_long smt_get_error_word(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, lnkstat.c)
+		This functions returns the SMT error work for AIX events.
+
+Return	smt_error_word	These bits are supported:
+
+		SMT_ERL_ALC	== 	[PS/PA].fddiPORTLerFlag
+		SMT_ERL_BLC	==	[PB].fddiPORTLerFlag
+		SMT_ERL_NCC	==	fddiMACNotCopiedFlag
+		SMT_ERL_FEC	==	fddiMACFrameErrorFlag
+
+	END_MANUAL_ENTRY()
+ */
+u_long smt_get_error_word(smc)
+struct s_smc *smc ;
+{
+	u_long	st;
+
+	/*
+	 * smt error word low
+	 */
+	st = 0 ;
+	if (smc->s.sas == SMT_SAS) {
+		if (smc->mib.p[PS].fddiPORTLerFlag)
+			st |= SMT_ERL_ALC ;
+	}
+	else {
+		if (smc->mib.p[PA].fddiPORTLerFlag)
+			st |= SMT_ERL_ALC ;
+		if (smc->mib.p[PB].fddiPORTLerFlag)
+			st |= SMT_ERL_BLC ;
+	}
+	if (smc->mib.m[MAC0].fddiMACNotCopiedFlag)
+		st |= SMT_ERL_NCC ;		/* not copied condition */
+	if (smc->mib.m[MAC0].fddiMACFrameErrorFlag)
+		st |= SMT_ERL_FEC ;		/* frame error condition */
+
+	return st;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+	u_long smt_get_event_word(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, lnkstat.c)
+		This functions returns the SMT event work for AIX events.
+
+Return	smt_event_word	always 0
+
+	END_MANUAL_ENTRY()
+ */
+u_long smt_get_event_word(smc)
+struct s_smc *smc ;
+{
+	return (u_long) 0;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+	u_long smt_get_port_event_word(smc)
+	struct s_smc *smc ;
+
+Function	DOWNCALL	(SMT, lnkstat.c)
+		This functions returns the SMT port event work for AIX events.
+
+Return	smt_port_event_word	always 0
+
+	END_MANUAL_ENTRY()
+ */
+u_long smt_get_port_event_word(smc)
+struct s_smc *smc ;
+{
+	return (u_long) 0;
+}
+
+/*
+	BEGIN_MANUAL_ENTRY(if,func;others;11)
+
+	u_long smt_read_errorlog(smc,p,len)
+	struct s_smc *smc ;
+	char _far *p ;
+	int len ;
+
+Function	DOWNCALL	(SMT, lnkstat.c)
+		This functions returns the SMT error log field for AIX events.
+
+Para	p	pointer to the error log field
+	len	len of the error log field
+
+Return	len	used len of the error log field
+
+	END_MANUAL_ENTRY()
+ */
+int smt_read_errorlog(smc,p,len)
+struct s_smc *smc ;
+char _far *p ;
+int len ;
+{
+	int			i ;
+	int			st ;
+	struct s_error_log _far	*er ;
+
+	er = (struct s_error_log _far *) p ;
+	if (len > sizeof(struct s_error_log))
+		len = sizeof(struct s_error_log) ;
+	for (i = 0 ; i < len ; i++)
+		*p++ = 0 ;
+	/*
+	 * set count
+	 */
+	if (EL_IS_OK(set_count_high,len)) {
+		er->set_count_low = (u_short)smc->mib.fddiSMTSetCount.count ;
+		er->set_count_high =
+			(u_short)(smc->mib.fddiSMTSetCount.count >> 16L) ;
+	}
+	/*
+	 * aci
+	 */
+	if (EL_IS_OK(aci_id_code,len)) {
+		er->aci_id_code = 0 ;
+	}
+	/*
+	 * purge counter is missed frames; 16 bits only
+	 */
+	if (EL_IS_OK(purge_frame_counter,len)) {
+		if (smc->mib.m[MAC0].fddiMACCopied_Ct > 0xffff)
+			er->purge_frame_counter = 0xffff ;
+		else
+			er->purge_frame_counter =
+				(u_short)smc->mib.m[MAC0].fddiMACCopied_Ct ;
+	}
+	/*
+	 * CMT and RMT state machines
+	 */
+	if (EL_IS_OK(ecm_state,len))
+		er->ecm_state = smc->mib.fddiSMTECMState ;
+
+	if (EL_IS_OK(pcm_b_state,len)) {
+		if (smc->s.sas == SMT_SAS) {
+			er->pcm_a_state = smc->y[PS].mib->fddiPORTPCMState ;
+			er->pcm_b_state = 0 ;
+		}
+		else {
+			er->pcm_a_state = smc->y[PA].mib->fddiPORTPCMState ;
+			er->pcm_b_state = smc->y[PB].mib->fddiPORTPCMState ;
+		}
+	}
+	if (EL_IS_OK(cfm_state,len))
+		er->cfm_state = smc->mib.fddiSMTCF_State ;
+	if (EL_IS_OK(rmt_state,len))
+		er->rmt_state = smc->mib.m[MAC0].fddiMACRMTState ;
+
+	/*
+	 * smt error word low (we only need the low order 16 bits.)
+	 */
+
+	st = smt_get_error_word(smc) & 0xffff ;
+
+	if (EL_IS_OK(smt_error_low,len))
+		er->smt_error_low = st ;
+
+	if (EL_IS_OK(ucode_version_level,len))
+		er->ucode_version_level = 0x0101 ;
+	return(len) ;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/pcmplc.c linux.18p8/drivers/net/skfp/pcmplc.c
--- linux.vanilla/drivers/net/skfp/pcmplc.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/pcmplc.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,2094 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	PCM
+	Physical Connection Management
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * 		queue_event()
+ * 		smt_timer_start()
+ * 		smt_timer_stop()
+ *
+ * 	The following external HW dependant functions are referenced :
+ * 		sm_pm_control()
+ *		sm_ph_linestate()
+ *		sm_pm_ls_latch()
+ *
+ * 	The following HW dependant events are required :
+ *		PC_QLS
+ *		PC_ILS
+ *		PC_HLS
+ *		PC_MLS
+ *		PC_NSE
+ *		PC_LEM
+ *
+ */
+
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/supern_2.h"
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)pcmplc.c	2.55 99/08/05 (C) SK " ;
+#endif
+
+#ifdef	FDDI_MIB
+extern int snmp_fddi_trap(
+#ifdef	ANSIC
+struct s_smc	* smc, int  type, int  index
+#endif
+);
+#endif
+#ifdef	CONCENTRATOR
+extern int plc_is_installed(
+#ifdef	ANSIC
+struct s_smc *smc ,
+int p
+#endif
+) ;
+#endif
+/*
+ * FSM Macros
+ */
+#define AFLAG		(0x20)
+#define GO_STATE(x)	(mib->fddiPORTPCMState = (x)|AFLAG)
+#define ACTIONS_DONE()	(mib->fddiPORTPCMState &= ~AFLAG)
+#define ACTIONS(x)	(x|AFLAG)
+
+/*
+ * PCM states
+ */
+#define PC0_OFF			0
+#define PC1_BREAK		1
+#define PC2_TRACE		2
+#define PC3_CONNECT		3
+#define PC4_NEXT		4
+#define PC5_SIGNAL		5
+#define PC6_JOIN		6
+#define PC7_VERIFY		7
+#define PC8_ACTIVE		8
+#define PC9_MAINT		9
+
+#ifdef	DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const pcm_states[] =  {
+	"PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT",
+	"PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const pcm_events[] = {
+	"NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL",
+	"PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR",
+	"PC_ENABLE","PC_DISABLE",
+	"PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE",
+	"PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN",
+	"PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT",
+	"PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT",
+	"PC_NSE","PC_LEM"
+} ;
+#endif
+
+#ifdef	MOT_ELM
+/*
+ * PCL-S control register
+ * this register in the PLC-S controls the scrambling parameters
+ */
+#define PLCS_CONTROL_C_U	0
+#define PLCS_CONTROL_C_S	(PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \
+				 PL_C_CIPHER_ENABLE)
+#define	PLCS_FASSERT_U		0
+#define	PLCS_FASSERT_S		0xFd76	/* 52.0 us */
+#define	PLCS_FDEASSERT_U	0
+#define	PLCS_FDEASSERT_S	0
+#else	/* nMOT_ELM */
+/*
+ * PCL-S control register
+ * this register in the PLC-S controls the scrambling parameters
+ * can be patched for ANSI compliance if standard changes
+ */
+static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ;
+static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ;
+
+#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8))
+#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8))
+#endif	/* nMOT_ELM */
+
+/*
+ * external vars
+ */
+/* struct definition see 'cmtdef.h' (also used by CFM) */
+
+#define PS_OFF		0
+#define PS_BIT3		1
+#define PS_BIT4		2
+#define PS_BIT7		3
+#define PS_LCT		4
+#define PS_BIT8		5
+#define PS_JOIN		6
+#define PS_ACTIVE	7
+
+#define LCT_LEM_MAX	255
+
+/*
+ * PLC timing parameter
+ */
+
+#define PLC_MS(m)	((int)((0x10000L-(m*100000L/2048))))
+#define SLOW_TL_MIN	PLC_MS(6)
+#define SLOW_C_MIN	PLC_MS(10)
+
+static	const struct plt {
+	int	timer ;			/* relative plc timer address */
+	int	para ;			/* default timing parameters */
+} pltm[] = {
+	{ PL_C_MIN, SLOW_C_MIN },	/* min t. to remain Connect State */
+	{ PL_TL_MIN, SLOW_TL_MIN },	/* min t. to transmit a Line State */
+	{ PL_TB_MIN, TP_TB_MIN },	/* min break time */
+	{ PL_T_OUT, TP_T_OUT },		/* Signaling timeout */
+	{ PL_LC_LENGTH, TP_LC_LENGTH },	/* Link Confidence Test Time */
+	{ PL_T_SCRUB, TP_T_SCRUB },	/* Scrub Time == MAC TVX time ! */
+	{ PL_NS_MAX, TP_NS_MAX },	/* max t. that noise is tolerated */
+	{ 0,0 }
+} ;
+
+/*
+ * interrupt mask
+ */
+#ifdef	SUPERNET_3
+/*
+ * Do we need the EBUF error during signaling, too, to detect SUPERNET_3
+ * PLL bug?
+ */
+static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
+			PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
+#else	/* SUPERNET_3 */
+/*
+ * We do NOT need the elasticity buffer error during signaling.
+ */
+static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
+			PL_PCM_ENABLED | PL_SELF_TEST ;
+#endif	/* SUPERNET_3 */
+static int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
+			PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
+
+/* external functions */
+void	all_selection_criteria ();
+
+/* internal functions */
+static void pcm_fsm() ;
+static void pc_rcode_actions() ;
+static void pc_tcode_actions() ;
+static void reset_lem_struct() ;
+static void plc_init() ;
+static void sm_ph_lem_start() ;
+static void sm_ph_lem_stop() ;
+static void sm_ph_linestate() ;
+static void real_init_plc() ;
+
+/*
+ * SMT timer interface
+ *      start PCM timer 0
+ */
+static void start_pcm_timer0(smc,value,event,phy)
+struct s_smc *smc ;
+u_long value;
+int event;
+struct s_phy *phy;
+{
+	phy->timer0_exp = FALSE ;       /* clear timer event flag */
+	smt_timer_start(smc,&phy->pcm_timer0,value,
+		EV_TOKEN(EVENT_PCM+phy->np,event)) ;
+}
+/*
+ * SMT timer interface
+ *      stop PCM timer 0
+ */
+static void stop_pcm_timer0(smc,phy)
+struct s_smc *smc ;
+struct s_phy *phy;
+{
+	if (phy->pcm_timer0.tm_active)
+		smt_timer_stop(smc,&phy->pcm_timer0) ;
+}
+
+/*
+	init PCM state machine (called by driver)
+	clear all PCM vars and flags
+*/
+void pcm_init(smc)
+struct s_smc *smc ;
+{
+	int		i ;
+	int		np ;
+	struct s_phy	*phy ;
+	struct fddi_mib_p	*mib ;
+
+	for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) {
+		/* Indicates the type of PHY being used */
+		mib = phy->mib ;
+		mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ;
+		phy->np = np ;
+		switch (smc->s.sas) {
+#ifdef	CONCENTRATOR
+		case SMT_SAS :
+			mib->fddiPORTMy_Type = (np == PS) ? TS : TM ;
+			break ;
+		case SMT_DAS :
+			mib->fddiPORTMy_Type = (np == PA) ? TA :
+					(np == PB) ? TB : TM ;
+			break ;
+		case SMT_NAC :
+			mib->fddiPORTMy_Type = TM ;
+			break;
+#else
+		case SMT_SAS :
+			mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ;
+			mib->fddiPORTHardwarePresent = (np == PS) ? TRUE :
+					FALSE ;
+#ifndef	SUPERNET_3
+			smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ;
+#else
+			smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ;
+#endif
+			break ;
+		case SMT_DAS :
+			mib->fddiPORTMy_Type = (np == PB) ? TB : TA ;
+			break ;
+#endif
+		}
+		/*
+		 * set PMD-type
+		 */
+		phy->pmd_scramble = 0 ;
+		switch (phy->pmd_type[PMD_SK_PMD]) {
+		case 'P' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
+			break ;
+		case 'L' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ;
+			break ;
+		case 'D' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			break ;
+		case 'S' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			phy->pmd_scramble = TRUE ;
+			break ;
+		case 'U' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			phy->pmd_scramble = TRUE ;
+			break ;
+		case '1' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
+			break ;
+		case '2' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
+			break ;
+		case '3' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ;
+			break ;
+		case '4' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ;
+			break ;
+		case 'H' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
+			break ;
+		case 'I' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			break ;
+		case 'G' :
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ;
+			break ;
+		default:
+			mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ;
+			break ;
+		}
+		/*
+		 * A and B port can be on primary and secondary path
+		 */
+		switch (mib->fddiPORTMy_Type) {
+		case TA :
+			mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
+			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+			mib->fddiPORTRequestedPaths[2] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_CON_ALTER |
+				MIB_P_PATH_SEC_PREFER ;
+			mib->fddiPORTRequestedPaths[3] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_CON_ALTER |
+				MIB_P_PATH_SEC_PREFER |
+				MIB_P_PATH_THRU ;
+			break ;
+		case TB :
+			mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
+			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+			mib->fddiPORTRequestedPaths[2] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_PRIM_PREFER ;
+			mib->fddiPORTRequestedPaths[3] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_PRIM_PREFER |
+				MIB_P_PATH_CON_PREFER |
+				MIB_P_PATH_THRU ;
+			break ;
+		case TS :
+			mib->fddiPORTAvailablePaths |= MIB_PATH_S ;
+			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+			mib->fddiPORTRequestedPaths[2] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_CON_ALTER |
+				MIB_P_PATH_PRIM_PREFER ;
+			mib->fddiPORTRequestedPaths[3] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_CON_ALTER |
+				MIB_P_PATH_PRIM_PREFER ;
+			break ;
+		case TM :
+			mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ;
+			mib->fddiPORTRequestedPaths[2] =
+				MIB_P_PATH_LOCAL |
+				MIB_P_PATH_SEC_ALTER |
+				MIB_P_PATH_PRIM_ALTER ;
+			mib->fddiPORTRequestedPaths[3] = 0 ;
+			break ;
+		}
+
+		phy->pc_lem_fail = FALSE ;
+		mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ;
+		mib->fddiPORTLCTFail_Ct = 0 ;
+		mib->fddiPORTBS_Flag = 0 ;
+		mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ;
+		mib->fddiPORTNeighborType = TNONE ;
+		phy->ls_flag = 0 ;
+		phy->rc_flag = 0 ;
+		phy->tc_flag = 0 ;
+		phy->td_flag = 0 ;
+		if (np >= PM)
+			phy->phy_name = '0' + np - PM ;
+		else
+			phy->phy_name = 'A' + np ;
+		phy->wc_flag = FALSE ;		/* set by SMT */
+		memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ;
+		reset_lem_struct(phy) ;
+		memset((char *)&phy->plc,0,sizeof(struct s_plc)) ;
+		phy->plc.p_state = PS_OFF ;
+		for (i = 0 ; i < NUMBITS ; i++) {
+			phy->t_next[i] = 0 ;
+		}
+	}
+	real_init_plc(smc) ;
+}
+
+void init_plc(smc)
+struct s_smc *smc ;
+{
+	SK_UNUSED(smc) ;
+
+	/*
+	 * dummy
+	 * this is an obsolete public entry point that has to remain
+	 * for compat. It is used by various drivers.
+	 * the work is now done in real_init_plc()
+	 * which is called from pcm_init() ;
+	 */
+}
+
+static void real_init_plc(smc)
+struct s_smc *smc ;
+{
+	int	p ;
+
+	for (p = 0 ; p < NUMPHYS ; p++)
+		plc_init(smc,p) ;
+}
+
+static void plc_init(smc,p)
+struct s_smc *smc ;
+int p;
+{
+	int	i ;
+#ifndef	MOT_ELM
+	int	rev ;	/* Revision of PLC-x */
+#endif	/* MOT_ELM */
+
+	/* transit PCM state machine to MAINT state */
+	outpw(PLC(p,PL_CNTRL_B),0) ;
+	outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ;
+	outpw(PLC(p,PL_CNTRL_A),0) ;
+
+	/*
+	 * if PLC-S then set control register C
+	 */
+#ifndef	MOT_ELM
+	rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ;
+	if (rev != PLC_REVISION_A)
+#endif	/* MOT_ELM */
+	{
+		if (smc->y[p].pmd_scramble) {
+			outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ;
+#ifdef	MOT_ELM
+			outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ;
+			outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ;
+#endif	/* MOT_ELM */
+		}
+		else {
+			outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ;
+#ifdef	MOT_ELM
+			outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ;
+			outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ;
+#endif	/* MOT_ELM */
+		}
+	}
+
+	/*
+	 * set timer register
+	 */
+	for ( i = 0 ; pltm[i].timer; i++)	/* set timer parameter reg */
+		outpw(PLC(p,pltm[i].timer),pltm[i].para) ;
+
+	(void)inpw(PLC(p,PL_INTR_EVENT)) ;	/* clear interrupt event reg */
+	plc_clear_irq(smc,p) ;
+	outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */
+
+	/*
+	 * if PCM is configured for class s, it will NOT go to the
+	 * REMOVE state if offline (page 3-36;)
+	 * in the concentrator, all inactive PHYS always must be in
+	 * the remove state
+	 * there's no real need to use this feature at all ..
+	 */
+#ifndef	CONCENTRATOR
+	if ((smc->s.sas == SMT_SAS) && (p == PS)) {
+		outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ;
+	}
+#endif
+}
+
+/*
+ * control PCM state machine
+ */
+static void plc_go_state(smc,p,state)
+struct s_smc *smc ;
+int p;
+int state;
+{
+	HW_PTR port ;
+	int val ;
+
+	SK_UNUSED(smc) ;
+
+	port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ;
+	val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ;
+	outpw(port,val) ;
+	outpw(port,val | state) ;
+}
+
+/*
+ * read current line state (called by ECM & PCM)
+ */
+int sm_pm_get_ls(smc,phy)
+struct s_smc *smc ;
+int phy;
+{
+	int	state ;
+
+#ifdef	CONCENTRATOR
+	if (!plc_is_installed(smc,phy))
+		return(PC_QLS) ;
+#endif
+
+	state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ;
+	switch(state) {
+	case PL_L_QLS:
+		state = PC_QLS ;
+		break ;
+	case PL_L_MLS:
+		state = PC_MLS ;
+		break ;
+	case PL_L_HLS:
+		state = PC_HLS ;
+		break ;
+	case PL_L_ILS4:
+	case PL_L_ILS16:
+		state = PC_ILS ;
+		break ;
+	case PL_L_ALS:
+		state = PC_LS_PDR ;
+		break ;
+	default :
+		state = PC_LS_NONE ;
+	}
+	return(state) ;
+}
+
+static int plc_send_bits(smc,phy,len)
+struct s_smc *smc ;
+struct s_phy *phy;
+int len;
+{
+	int np = phy->np ;		/* PHY index */
+	int	n ;
+	int	i ;
+
+	SK_UNUSED(smc) ;
+
+	/* create bit vector */
+	for (i = len-1,n = 0 ; i >= 0 ; i--) {
+		n = (n<<1) | phy->t_val[phy->bitn+i] ;
+	}
+	if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
+#if	0
+		printf("PL_PCM_SIGNAL is set\n") ;
+#endif
+		return(1) ;
+	}
+	/* write bit[n] & length = 1 to regs */
+	outpw(PLC(np,PL_VECTOR_LEN),len-1) ;	/* len=nr-1 */
+	outpw(PLC(np,PL_XMIT_VECTOR),n) ;
+#ifdef	DEBUG
+#if 1
+#ifdef	DEBUG_BRD
+	if (smc->debug.d_plc & 0x80)
+#else
+	if (debug.d_plc & 0x80)
+#endif
+		printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ;
+#endif
+#endif
+	return(0) ;
+}
+
+/*
+ * config plc muxes
+ */
+void plc_config_mux(smc,mux)
+struct s_smc *smc ;
+int mux ;
+{
+	if (smc->s.sas != SMT_DAS)
+		return ;
+	if (mux == MUX_WRAPB) {
+		SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
+		SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
+	}
+	else {
+		CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
+		CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ;
+	}
+	CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ;
+	CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ;
+}
+
+/*
+	PCM state machine
+	called by dispatcher  & fddi_init() (driver)
+	do
+		display state change
+		process event
+	until SM is stable
+*/
+void pcm(smc,np,event)
+struct s_smc *smc ;
+const int np;
+int event;
+{
+	int	state ;
+	int	oldstate ;
+	struct s_phy	*phy ;
+	struct fddi_mib_p	*mib ;
+
+#ifndef	CONCENTRATOR
+	/*
+	 * ignore 2nd PHY if SAS
+	 */
+	if ((np != PS) && (smc->s.sas == SMT_SAS))
+		return ;
+#endif
+	phy = &smc->y[np] ;
+	mib = phy->mib ;
+	oldstate = mib->fddiPORTPCMState ;
+	do {
+		DB_PCM("PCM %c: state %s",
+			phy->phy_name,
+			(mib->fddiPORTPCMState & AFLAG) ? "ACTIONS " : "") ;
+		DB_PCM("%s, event %s\n",
+			pcm_states[mib->fddiPORTPCMState & ~AFLAG],
+			pcm_events[event]) ;
+		state = mib->fddiPORTPCMState ;
+		pcm_fsm(smc,phy,event) ;
+		event = 0 ;
+	} while (state != mib->fddiPORTPCMState) ;
+	/*
+	 * because the PLC does the bit signaling for us,
+	 * we're always in SIGNAL state
+	 * the MIB want's to see CONNECT
+	 * we therefore fake an entry in the MIB
+	 */
+	if (state == PC5_SIGNAL)
+		mib->fddiPORTPCMStateX = PC3_CONNECT ;
+	else
+		mib->fddiPORTPCMStateX = state ;
+
+#ifndef	SLIM_SMT
+	/*
+	 * path change
+	 */
+	if (	mib->fddiPORTPCMState != oldstate &&
+		((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) {
+		smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE,
+			(int) (INDEX_PORT+ phy->np),0) ;
+	}
+#endif
+
+#ifdef FDDI_MIB
+	/* check whether a snmp-trap has to be sent */
+
+	if ( mib->fddiPORTPCMState != oldstate ) {
+		/* a real state change took place */
+		DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState);
+		if ( mib->fddiPORTPCMState == PC0_OFF ) {
+			/* send first trap */
+			snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex );
+		} else if ( oldstate == PC0_OFF ) {
+			/* send second trap */
+			snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex );
+		} else if ( mib->fddiPORTPCMState != PC2_TRACE &&
+			oldstate == PC8_ACTIVE ) {
+			/* send third trap */
+			snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex );
+		} else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) {
+			/* send fourth trap */
+			snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex );
+		}
+	}
+#endif
+
+	pcm_state_change(smc,np,state) ;
+}
+
+/*
+ * PCM state machine
+ */
+static void pcm_fsm(smc,phy,cmd)
+struct s_smc *smc ;
+struct s_phy *phy;
+int cmd;
+{
+	int	i ;
+	int	np = phy->np ;		/* PHY index */
+	struct s_plc	*plc ;
+	struct fddi_mib_p	*mib ;
+#ifndef	MOT_ELM
+	u_short	plc_rev ;		/* Revision of the plc */
+#endif	/* nMOT_ELM */
+
+	plc = &phy->plc ;
+	mib = phy->mib ;
+
+	/*
+	 * general transitions independant of state
+	 */
+	switch (cmd) {
+	case PC_STOP :
+		/*PC00-PC80*/
+		if (mib->fddiPORTPCMState != PC9_MAINT) {
+			GO_STATE(PC0_OFF) ;
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP,
+				smt_get_port_event_word(smc));
+		}
+		return ;
+	case PC_START :
+		/*PC01-PC81*/
+		if (mib->fddiPORTPCMState != PC9_MAINT)
+			GO_STATE(PC1_BREAK) ;
+		return ;
+	case PC_DISABLE :
+		/* PC09-PC99 */
+		GO_STATE(PC9_MAINT) ;
+		AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+			FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED,
+			smt_get_port_event_word(smc));
+		return ;
+	case PC_TIMEOUT_LCT :
+		/* if long or extended LCT */
+		stop_pcm_timer0(smc,phy) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+		/* end of LCT is indicate by PCM_CODE (initiate PCM event) */
+		return ;
+	}
+
+	switch(mib->fddiPORTPCMState) {
+	case ACTIONS(PC0_OFF) :
+		stop_pcm_timer0(smc,phy) ;
+		outpw(PLC(np,PL_CNTRL_A),0) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+		sm_ph_lem_stop(smc,np) ;		/* disable LEM */
+		phy->cf_loop = FALSE ;
+		phy->cf_join = FALSE ;
+		queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
+		plc_go_state(smc,np,PL_PCM_STOP) ;
+		mib->fddiPORTConnectState = PCM_DISABLED ;
+		ACTIONS_DONE() ;
+		break ;
+	case PC0_OFF:
+		/*PC09*/
+		if (cmd == PC_MAINT) {
+			GO_STATE(PC9_MAINT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(PC1_BREAK) :
+		/* Stop the LCT timer if we came from Signal state */
+		stop_pcm_timer0(smc,phy) ;
+		ACTIONS_DONE() ;
+		plc_go_state(smc,np,0) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+		sm_ph_lem_stop(smc,np) ;		/* disable LEM */
+		/*
+		 * if vector is already loaded, go to OFF to clear PCM_SIGNAL
+		 */
+#if	0
+		if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) {
+			plc_go_state(smc,np,PL_PCM_STOP) ;
+			/* TB_MIN ? */
+		}
+#endif
+		/*
+		 * Go to OFF state in any case.
+		 */
+		plc_go_state(smc,np,PL_PCM_STOP) ;
+
+		if (mib->fddiPORTPC_Withhold == PC_WH_NONE)
+			mib->fddiPORTConnectState = PCM_CONNECTING ;
+		phy->cf_loop = FALSE ;
+		phy->cf_join = FALSE ;
+		queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
+		phy->ls_flag = FALSE ;
+		phy->pc_mode = PM_NONE ;	/* needed by CFM */
+		phy->bitn = 0 ;			/* bit signaling start bit */
+		for (i = 0 ; i < 3 ; i++)
+			pc_tcode_actions(smc,i,phy) ;
+
+		/* Set the non-active interrupt mask register */
+		outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ;
+
+		/*
+		 * If the LCT was stopped. There might be a
+		 * PCM_CODE interrupt event present.
+		 * This must be cleared.
+		 */
+		(void)inpw(PLC(np,PL_INTR_EVENT)) ;
+#ifndef	MOT_ELM
+		/* Get the plc revision for revision dependent code */
+		plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ;
+
+		if (plc_rev != PLC_REV_SN3)
+#endif	/* MOT_ELM */
+		{
+			/*
+			 * No supernet III PLC, so set Xmit verctor and
+			 * length BEFORE starting the state machine.
+			 */
+			if (plc_send_bits(smc,phy,3)) {
+				return ;
+			}
+		}
+
+		/*
+		 * Now give the Start command.
+		 * - The start command shall be done before setting the bits
+		 *   to be signaled. (In PLC-S description and PLCS in SN3.
+		 * - The start command shall be issued AFTER setting the
+		 *   XMIT vector and the XMIT length register.
+		 *
+		 * We do it exactly according this specs for the old PLC and
+		 * the new PLCS inside the SN3.
+		 * For the usual PLCS we try it the way it is done for the
+		 * old PLC and set the XMIT registers again, if the PLC is
+		 * not in SIGNAL state. This is done according to an PLCS
+		 * errata workaround.
+		 */
+
+		plc_go_state(smc,np,PL_PCM_START) ;
+
+		/*
+		 * workaround for PLC-S eng. sample errata
+		 */
+#ifdef	MOT_ELM
+		if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
+#else	/* nMOT_ELM */
+		if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) !=
+			PLC_REVISION_A) &&
+			!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL))
+#endif	/* nMOT_ELM */
+		{
+			/*
+			 * Set register again (PLCS errata) or the first time
+			 * (new SN3 PLCS).
+			 */
+			(void) plc_send_bits(smc,phy,3) ;
+		}
+		/*
+		 * end of workaround
+		 */
+
+		GO_STATE(PC5_SIGNAL) ;
+		plc->p_state = PS_BIT3 ;
+		plc->p_bits = 3 ;
+		plc->p_start = 0 ;
+
+		break ;
+	case PC1_BREAK :
+		break ;
+	case ACTIONS(PC2_TRACE) :
+		plc_go_state(smc,np,PL_PCM_TRACE) ;
+		ACTIONS_DONE() ;
+		break ;
+	case PC2_TRACE :
+		break ;
+
+	case PC3_CONNECT :	/* these states are done by hardware */
+	case PC4_NEXT :
+		break ;
+
+	case ACTIONS(PC5_SIGNAL) :
+		ACTIONS_DONE() ;
+	case PC5_SIGNAL :
+		if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT))
+			break ;
+		switch (plc->p_state) {
+		case PS_BIT3 :
+			for (i = 0 ; i <= 2 ; i++)
+				pc_rcode_actions(smc,i,phy) ;
+			pc_tcode_actions(smc,3,phy) ;
+			plc->p_state = PS_BIT4 ;
+			plc->p_bits = 1 ;
+			plc->p_start = 3 ;
+			phy->bitn = 3 ;
+			if (plc_send_bits(smc,phy,1)) {
+				return ;
+			}
+			break ;
+		case PS_BIT4 :
+			pc_rcode_actions(smc,3,phy) ;
+			for (i = 4 ; i <= 6 ; i++)
+				pc_tcode_actions(smc,i,phy) ;
+			plc->p_state = PS_BIT7 ;
+			plc->p_bits = 3 ;
+			plc->p_start = 4 ;
+			phy->bitn = 4 ;
+			if (plc_send_bits(smc,phy,3)) {
+				return ;
+			}
+			break ;
+		case PS_BIT7 :
+			for (i = 3 ; i <= 6 ; i++)
+				pc_rcode_actions(smc,i,phy) ;
+			plc->p_state = PS_LCT ;
+			plc->p_bits = 0 ;
+			plc->p_start = 7 ;
+			phy->bitn = 7 ;
+		sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */
+			/* start LCT */
+			i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ;
+			outpw(PLC(np,PL_CNTRL_B),i) ;	/* must be cleared */
+			outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ;
+			break ;
+		case PS_LCT :
+			/* check for local LCT failure */
+			pc_tcode_actions(smc,7,phy) ;
+			/*
+			 * set tval[7]
+			 */
+			plc->p_state = PS_BIT8 ;
+			plc->p_bits = 1 ;
+			plc->p_start = 7 ;
+			phy->bitn = 7 ;
+			if (plc_send_bits(smc,phy,1)) {
+				return ;
+			}
+			break ;
+		case PS_BIT8 :
+			/* check for remote LCT failure */
+			pc_rcode_actions(smc,7,phy) ;
+			if (phy->t_val[7] || phy->r_val[7]) {
+				plc_go_state(smc,np,PL_PCM_STOP) ;
+				GO_STATE(PC1_BREAK) ;
+				break ;
+			}
+			for (i = 8 ; i <= 9 ; i++)
+				pc_tcode_actions(smc,i,phy) ;
+			plc->p_state = PS_JOIN ;
+			plc->p_bits = 2 ;
+			plc->p_start = 8 ;
+			phy->bitn = 8 ;
+			if (plc_send_bits(smc,phy,2)) {
+				return ;
+			}
+			break ;
+		case PS_JOIN :
+			for (i = 8 ; i <= 9 ; i++)
+				pc_rcode_actions(smc,i,phy) ;
+			plc->p_state = PS_ACTIVE ;
+			GO_STATE(PC6_JOIN) ;
+			break ;
+		}
+		break ;
+
+	case ACTIONS(PC6_JOIN) :
+		/*
+		 * prevent mux error when going from WRAP_A to WRAP_B
+		 */
+		if (smc->s.sas == SMT_DAS && np == PB &&
+			(smc->y[PA].pc_mode == PM_TREE ||
+			 smc->y[PB].pc_mode == PM_TREE)) {
+			SETMASK(PLC(np,PL_CNTRL_A),
+				PL_SC_REM_LOOP,PL_SC_REM_LOOP) ;
+			SETMASK(PLC(np,PL_CNTRL_B),
+				PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ;
+		}
+		SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
+		SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ;
+		ACTIONS_DONE() ;
+		cmd = 0 ;
+		/* fall thru */
+	case PC6_JOIN :
+		switch (plc->p_state) {
+		case PS_ACTIVE:
+			/*PC88b*/
+			if (!phy->cf_join) {
+				phy->cf_join = TRUE ;
+				queue_event(smc,EVENT_CFM,CF_JOIN+np) ; ;
+			}
+			if (cmd == PC_JOIN)
+				GO_STATE(PC8_ACTIVE) ;
+			/*PC82*/
+			if (cmd == PC_TRACE) {
+				GO_STATE(PC2_TRACE) ;
+				break ;
+			}
+			break ;
+		}
+		break ;
+
+	case PC7_VERIFY :
+		break ;
+
+	case ACTIONS(PC8_ACTIVE) :
+		/*
+		 * start LEM for SMT
+		 */
+		sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ;
+
+		phy->tr_flag = FALSE ;
+		mib->fddiPORTConnectState = PCM_ACTIVE ;
+
+		/* Set the active interrupt mask register */
+		outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ;
+
+		ACTIONS_DONE() ;
+		break ;
+	case PC8_ACTIVE :
+		/*PC81 is done by PL_TNE_EXPIRED irq */
+		/*PC82*/
+		if (cmd == PC_TRACE) {
+			GO_STATE(PC2_TRACE) ;
+			break ;
+		}
+		/*PC88c: is done by TRACE_PROP irq */
+
+		break ;
+	case ACTIONS(PC9_MAINT) :
+		stop_pcm_timer0(smc,phy) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ;
+		CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ;
+		CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;	/* disable LEM int. */
+		sm_ph_lem_stop(smc,np) ;		/* disable LEM */
+		phy->cf_loop = FALSE ;
+		phy->cf_join = FALSE ;
+		queue_event(smc,EVENT_CFM,CF_JOIN+np) ;
+		plc_go_state(smc,np,PL_PCM_STOP) ;
+		mib->fddiPORTConnectState = PCM_DISABLED ;
+		SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ;
+		sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ;
+		outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ;
+		ACTIONS_DONE() ;
+		break ;
+	case PC9_MAINT :
+		DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ;
+		/*PC90*/
+		if (cmd == PC_ENABLE) {
+			GO_STATE(PC0_OFF) ;
+			break ;
+		}
+		break ;
+
+	default:
+		SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ;
+		break ;
+	}
+}
+
+/*
+ * force line state on a PHY output	(only in MAINT state)
+ */
+static void sm_ph_linestate(smc,phy,ls)
+struct s_smc *smc ;
+int phy;
+int ls;
+{
+	int	cntrl ;
+
+	SK_UNUSED(smc) ;
+
+	cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) |
+						PL_PCM_STOP | PL_MAINT ;
+	switch(ls) {
+	case PC_QLS: 		/* Force Quiet */
+		cntrl |= PL_M_QUI0 ;
+		break ;
+	case PC_MLS: 		/* Force Master */
+		cntrl |= PL_M_MASTR ;
+		break ;
+	case PC_HLS: 		/* Force Halt */
+		cntrl |= PL_M_HALT ;
+		break ;
+	default :
+	case PC_ILS: 		/* Force Idle */
+		cntrl |= PL_M_IDLE ;
+		break ;
+	case PC_LS_PDR: 	/* Enable repeat filter */
+		cntrl |= PL_M_TPDR ;
+		break ;
+	}
+	outpw(PLC(phy,PL_CNTRL_B),cntrl) ;
+}
+
+
+static void reset_lem_struct(phy)
+struct s_phy *phy;
+{
+	struct lem_counter *lem = &phy->lem ;
+
+	phy->mib->fddiPORTLer_Estimate = 15 ;
+	lem->lem_float_ber = 15 * 100 ;
+}
+
+/*
+ * link error monitor
+ */
+static void lem_evaluate(smc,phy)
+struct s_smc *smc ;
+struct s_phy *phy;
+{
+	int ber ;
+	u_long errors ;
+	struct lem_counter *lem = &phy->lem ;
+	struct fddi_mib_p	*mib ;
+	int			cond ;
+
+	mib = phy->mib ;
+
+	if (!lem->lem_on)
+		return ;
+
+	errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ;
+	lem->lem_errors += errors ;
+	mib->fddiPORTLem_Ct += errors ;
+
+	errors = lem->lem_errors ;
+	/*
+	 * calculation is called on a intervall of 8 seconds
+	 *	-> this means, that one error in 8 sec. is one of 8*125*10E6
+	 *	the same as BER = 10E-9
+	 * Please note:
+	 *	-> 9 errors in 8 seconds mean:
+	 *	   BER = 9 * 10E-9  and this is
+	 *	    < 10E-8, so the limit of 10E-8 is not reached!
+	 */
+
+		if (!errors)		ber = 15 ;
+	else	if (errors <= 9)	ber = 9 ;
+	else	if (errors <= 99)	ber = 8 ;
+	else	if (errors <= 999)	ber = 7 ;
+	else	if (errors <= 9999)	ber = 6 ;
+	else	if (errors <= 99999)	ber = 5 ;
+	else	if (errors <= 999999)	ber = 4 ;
+	else	if (errors <= 9999999)	ber = 3 ;
+	else	if (errors <= 99999999)	ber = 2 ;
+	else	if (errors <= 999999999) ber = 1 ;
+	else				ber = 0 ;
+
+	/*
+	 * weighted average
+	 */
+	ber *= 100 ;
+	lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ;
+	lem->lem_float_ber /= 10 ;
+	mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ;
+	if (mib->fddiPORTLer_Estimate < 4) {
+		mib->fddiPORTLer_Estimate = 4 ;
+	}
+
+	if (lem->lem_errors) {
+		DB_PCMN(1,"LEM %c :\n",phy->np == PB? 'B' : 'A',0) ;
+		DB_PCMN(1,"errors      : %ld\n",lem->lem_errors,0) ;
+		DB_PCMN(1,"sum_errors  : %ld\n",mib->fddiPORTLem_Ct,0) ;
+		DB_PCMN(1,"current BER : 10E-%d\n",ber/100,0) ;
+		DB_PCMN(1,"float BER   : 10E-(%d/100)\n",lem->lem_float_ber,0) ;
+		DB_PCMN(1,"avg. BER    : 10E-%d\n",
+			mib->fddiPORTLer_Estimate,0) ;
+	}
+
+	lem->lem_errors = 0L ;
+
+#ifndef	SLIM_SMT
+	cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ?
+		TRUE : FALSE ;
+#ifdef	SMT_EXT_CUTOFF
+	smt_ler_alarm_check(smc,phy,cond) ;
+#endif	/* nSMT_EXT_CUTOFF */
+	if (cond != mib->fddiPORTLerFlag) {
+		smt_srf_event(smc,SMT_COND_PORT_LER,
+			(int) (INDEX_PORT+ phy->np) ,cond) ;
+	}
+#endif
+
+	if (	mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) {
+		phy->pc_lem_fail = TRUE ;		/* flag */
+		mib->fddiPORTLem_Reject_Ct++ ;
+		/*
+		 * "forgive 10e-2" if we cutoff so we can come
+		 * up again ..
+		 */
+		lem->lem_float_ber += 2*100 ;
+
+		/*PC81b*/
+#ifdef	CONCENTRATOR
+		DB_PCMN(1,"PCM: LER cutoff on port %d cutoff %d\n",
+			phy->np, mib->fddiPORTLer_Cutoff) ;
+#endif
+#ifdef	SMT_EXT_CUTOFF
+		smt_port_off_event(smc,phy->np);
+#else	/* nSMT_EXT_CUTOFF */
+		queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
+#endif	/* nSMT_EXT_CUTOFF */
+	}
+}
+
+/*
+ * called by SMT to calculate LEM bit error rate
+ */
+void sm_lem_evaluate(smc)
+struct s_smc *smc ;
+{
+	int np ;
+
+	for (np = 0 ; np < NUMPHYS ; np++)
+		lem_evaluate(smc,&smc->y[np]) ;
+}
+
+static void lem_check_lct(smc,phy)
+struct s_smc *smc ;
+struct s_phy	*phy ;
+{
+	struct lem_counter	*lem = &phy->lem ;
+	struct fddi_mib_p	*mib ;
+	int errors ;
+
+	mib = phy->mib ;
+
+	phy->pc_lem_fail = FALSE ;		/* flag */
+	errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ;
+	lem->lem_errors += errors ;
+	mib->fddiPORTLem_Ct += errors ;
+	if (lem->lem_errors) {
+		switch(phy->lc_test) {
+		case LC_SHORT:
+			if (lem->lem_errors >= smc->s.lct_short)
+				phy->pc_lem_fail = TRUE ;
+			break ;
+		case LC_MEDIUM:
+			if (lem->lem_errors >= smc->s.lct_medium)
+				phy->pc_lem_fail = TRUE ;
+			break ;
+		case LC_LONG:
+			if (lem->lem_errors >= smc->s.lct_long)
+				phy->pc_lem_fail = TRUE ;
+			break ;
+		case LC_EXTENDED:
+			if (lem->lem_errors >= smc->s.lct_extended)
+				phy->pc_lem_fail = TRUE ;
+			break ;
+		}
+		DB_PCMN(1," >>errors : %d\n",lem->lem_errors,0) ;
+	}
+	if (phy->pc_lem_fail) {
+		mib->fddiPORTLCTFail_Ct++ ;
+		mib->fddiPORTLem_Reject_Ct++ ;
+	}
+	else
+		mib->fddiPORTLCTFail_Ct = 0 ;
+}
+
+/*
+ * LEM functions
+ */
+static void sm_ph_lem_start(smc,np,threshold)
+struct s_smc *smc ;
+int np;
+int threshold;
+{
+	struct lem_counter *lem = &smc->y[np].lem ;
+
+	lem->lem_on = 1 ;
+	lem->lem_errors = 0L ;
+
+	/* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too
+	 * often.
+	 */
+
+	outpw(PLC(np,PL_LE_THRESHOLD),threshold) ;
+	(void)inpw(PLC(np,PL_LINK_ERR_CTR)) ;	/* clear error counter */
+
+	/* enable LE INT */
+	SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ;
+}
+
+static void sm_ph_lem_stop(smc,np)
+struct s_smc *smc ;
+int np;
+{
+	struct lem_counter *lem = &smc->y[np].lem ;
+
+	lem->lem_on = 0 ;
+	CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ;
+}
+
+/* ARGSUSED */
+void sm_pm_ls_latch(smc,phy,on_off)
+struct s_smc *smc ;
+int phy;
+int on_off;		/* en- or disable ident. ls */
+{
+	SK_UNUSED(smc) ;
+
+	phy = phy ; on_off = on_off ;
+}
+
+
+/*
+ * PCM pseudo code
+ * receive actions are called AFTER the bit n is received,
+ * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received
+ */
+
+/*
+ * PCM pseudo code 5.1 .. 6.1
+ */
+static void pc_rcode_actions(smc,bit,phy)
+struct s_smc *smc ;
+int bit;
+struct s_phy *phy;
+{
+	struct fddi_mib_p	*mib ;
+
+	mib = phy->mib ;
+
+	DB_PCMN(1,"SIG rec %x %x: \n", bit,phy->r_val[bit] ) ;
+	bit++ ;
+
+	switch(bit) {
+	case 0:
+	case 1:
+	case 2:
+		break ;
+	case 3 :
+		if (phy->r_val[1] == 0 && phy->r_val[2] == 0)
+			mib->fddiPORTNeighborType = TA ;
+		else if (phy->r_val[1] == 0 && phy->r_val[2] == 1)
+			mib->fddiPORTNeighborType = TB ;
+		else if (phy->r_val[1] == 1 && phy->r_val[2] == 0)
+			mib->fddiPORTNeighborType = TS ;
+		else if (phy->r_val[1] == 1 && phy->r_val[2] == 1)
+			mib->fddiPORTNeighborType = TM ;
+		break ;
+	case 4:
+		if (mib->fddiPORTMy_Type == TM &&
+			mib->fddiPORTNeighborType == TM) {
+			DB_PCMN(1,"PCM %c : E100 withhold M-M\n",
+				phy->phy_name,0) ;
+			mib->fddiPORTPC_Withhold = PC_WH_M_M ;
+			RS_SET(smc,RS_EVENT) ;
+		}
+		else if (phy->t_val[3] || phy->r_val[3]) {
+			mib->fddiPORTPC_Withhold = PC_WH_NONE ;
+			if (mib->fddiPORTMy_Type == TM ||
+			    mib->fddiPORTNeighborType == TM)
+				phy->pc_mode = PM_TREE ;
+			else
+				phy->pc_mode = PM_PEER ;
+
+			/* reevaluate the selection criteria (wc_flag) */
+			all_selection_criteria (smc);
+
+			if (phy->wc_flag) {
+				mib->fddiPORTPC_Withhold = PC_WH_PATH ;
+			}
+		}
+		else {
+			mib->fddiPORTPC_Withhold = PC_WH_OTHER ;
+			RS_SET(smc,RS_EVENT) ;
+			DB_PCMN(1,"PCM %c : E101 withhold other\n",
+				phy->phy_name,0) ;
+		}
+		phy->twisted = ((mib->fddiPORTMy_Type != TS) &&
+				(mib->fddiPORTMy_Type != TM) &&
+				(mib->fddiPORTNeighborType ==
+				mib->fddiPORTMy_Type)) ;
+		if (phy->twisted) {
+			DB_PCMN(1,"PCM %c : E102 !!! TWISTED !!!\n",
+				phy->phy_name,0) ;
+		}
+		break ;
+	case 5 :
+		break ;
+	case 6:
+		if (phy->t_val[4] || phy->r_val[4]) {
+			if ((phy->t_val[4] && phy->t_val[5]) ||
+			    (phy->r_val[4] && phy->r_val[5]) )
+				phy->lc_test = LC_EXTENDED ;
+			else
+				phy->lc_test = LC_LONG ;
+		}
+		else if (phy->t_val[5] || phy->r_val[5])
+			phy->lc_test = LC_MEDIUM ;
+		else
+			phy->lc_test = LC_SHORT ;
+		switch (phy->lc_test) {
+		case LC_SHORT :				/* 50ms */
+			outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ;
+			phy->t_next[7] = smc->s.pcm_lc_short ;
+			break ;
+		case LC_MEDIUM :			/* 500ms */
+			outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ;
+			phy->t_next[7] = smc->s.pcm_lc_medium ;
+			break ;
+		case LC_LONG :
+			SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
+			phy->t_next[7] = smc->s.pcm_lc_long ;
+			break ;
+		case LC_EXTENDED :
+			SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ;
+			phy->t_next[7] = smc->s.pcm_lc_extended ;
+			break ;
+		}
+		if (phy->t_next[7] > smc->s.pcm_lc_medium) {
+			start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy);
+		}
+		DB_PCMN(1,"LCT timer = %ld us\n", phy->t_next[7], 0) ;
+		phy->t_next[9] = smc->s.pcm_t_next_9 ;
+		break ;
+	case 7:
+		if (phy->t_val[6]) {
+			phy->cf_loop = TRUE ;
+		}
+		phy->td_flag = TRUE ;
+		break ;
+	case 8:
+		if (phy->t_val[7] || phy->r_val[7]) {
+			DB_PCMN(1,"PCM %c : E103 LCT fail %s\n",
+				phy->phy_name,phy->t_val[7]? "local":"remote") ;
+			queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ;
+		}
+		break ;
+	case 9:
+		if (phy->t_val[8] || phy->r_val[8]) {
+			if (phy->t_val[8])
+				phy->cf_loop = TRUE ;
+			phy->td_flag = TRUE ;
+		}
+		break ;
+	case 10:
+		if (phy->r_val[9]) {
+			/* neighbor intends to have MAC on output */ ;
+			mib->fddiPORTMacIndicated.R_val = TRUE ;
+		}
+		else {
+			/* neighbor does not intend to have MAC on output */ ;
+			mib->fddiPORTMacIndicated.R_val = FALSE ;
+		}
+		break ;
+	}
+}
+
+/*
+ * PCM pseudo code 5.1 .. 6.1
+ */
+static void pc_tcode_actions(smc,bit,phy)
+struct s_smc *smc ;
+const int bit;
+struct s_phy *phy;
+{
+	int	np = phy->np ;
+	struct fddi_mib_p	*mib ;
+
+	mib = phy->mib ;
+
+	switch(bit) {
+	case 0:
+		phy->t_val[0] = 0 ;		/* no escape used */
+		break ;
+	case 1:
+		if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM)
+			phy->t_val[1] = 1 ;
+		else
+			phy->t_val[1] = 0 ;
+		break ;
+	case 2 :
+		if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM)
+			phy->t_val[2] = 1 ;
+		else
+			phy->t_val[2] = 0 ;
+		break ;
+	case 3:
+		{
+		int	type,ne ;
+		int	policy ;
+
+		type = mib->fddiPORTMy_Type ;
+		ne = mib->fddiPORTNeighborType ;
+		policy = smc->mib.fddiSMTConnectionPolicy ;
+
+		phy->t_val[3] = 1 ;	/* Accept connection */
+		switch (type) {
+		case TA :
+			if (
+				((policy & POLICY_AA) && ne == TA) ||
+				((policy & POLICY_AB) && ne == TB) ||
+				((policy & POLICY_AS) && ne == TS) ||
+				((policy & POLICY_AM) && ne == TM) )
+				phy->t_val[3] = 0 ;	/* Reject */
+			break ;
+		case TB :
+			if (
+				((policy & POLICY_BA) && ne == TA) ||
+				((policy & POLICY_BB) && ne == TB) ||
+				((policy & POLICY_BS) && ne == TS) ||
+				((policy & POLICY_BM) && ne == TM) )
+				phy->t_val[3] = 0 ;	/* Reject */
+			break ;
+		case TS :
+			if (
+				((policy & POLICY_SA) && ne == TA) ||
+				((policy & POLICY_SB) && ne == TB) ||
+				((policy & POLICY_SS) && ne == TS) ||
+				((policy & POLICY_SM) && ne == TM) )
+				phy->t_val[3] = 0 ;	/* Reject */
+			break ;
+		case TM :
+			if (	ne == TM ||
+				((policy & POLICY_MA) && ne == TA) ||
+				((policy & POLICY_MB) && ne == TB) ||
+				((policy & POLICY_MS) && ne == TS) ||
+				((policy & POLICY_MM) && ne == TM) )
+				phy->t_val[3] = 0 ;	/* Reject */
+			break ;
+		}
+#ifndef	SLIM_SMT
+		/*
+		 * detect undesirable connection attempt event
+		 */
+		if (	(type == TA && ne == TA ) ||
+			(type == TA && ne == TS ) ||
+			(type == TB && ne == TB ) ||
+			(type == TB && ne == TS ) ||
+			(type == TS && ne == TA ) ||
+			(type == TS && ne == TB ) ) {
+			smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION,
+				(int) (INDEX_PORT+ phy->np) ,0) ;
+		}
+#endif
+		}
+		break ;
+	case 4:
+		if (mib->fddiPORTPC_Withhold == PC_WH_NONE) {
+			if (phy->pc_lem_fail) {
+				phy->t_val[4] = 1 ;	/* long */
+				phy->t_val[5] = 0 ;
+			}
+			else {
+				phy->t_val[4] = 0 ;
+				if (mib->fddiPORTLCTFail_Ct > 0)
+					phy->t_val[5] = 1 ;	/* medium */
+				else
+					phy->t_val[5] = 0 ;	/* short */
+
+				/*
+				 * Implementers choice: use medium
+				 * instead of short when undesired
+				 * connection attempt is made.
+				 */
+				if (phy->wc_flag)
+					phy->t_val[5] = 1 ;	/* medium */
+			}
+			mib->fddiPORTConnectState = PCM_CONNECTING ;
+		}
+		else {
+			mib->fddiPORTConnectState = PCM_STANDBY ;
+			phy->t_val[4] = 1 ;	/* extended */
+			phy->t_val[5] = 1 ;
+		}
+		break ;
+	case 5:
+		break ;
+	case 6:
+		/* we do NOT have a MAC for LCT */
+		phy->t_val[6] = 0 ;
+		break ;
+	case 7:
+		phy->cf_loop = FALSE ;
+		lem_check_lct(smc,phy) ;
+		if (phy->pc_lem_fail) {
+			DB_PCMN(1,"PCM %c : E104 LCT failed\n",
+				phy->phy_name,0) ;
+			phy->t_val[7] = 1 ;
+		}
+		else
+			phy->t_val[7] = 0 ;
+		break ;
+	case 8:
+		phy->t_val[8] = 0 ;	/* Don't request MAC loopback */
+		break ;
+	case 9:
+		phy->cf_loop = 0 ;
+		if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) ||
+		     ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) {
+			queue_event(smc,EVENT_PCM+np,PC_START) ;
+			break ;
+		}
+		phy->t_val[9] = FALSE ;
+		switch (smc->s.sas) {
+		case SMT_DAS :
+			/*
+			 * MAC intended on output
+			 */
+			if (phy->pc_mode == PM_TREE) {
+				if ((np == PB) || ((np == PA) &&
+				(smc->y[PB].mib->fddiPORTConnectState !=
+					PCM_ACTIVE)))
+					phy->t_val[9] = TRUE ;
+			}
+			else {
+				if (np == PB)
+					phy->t_val[9] = TRUE ;
+			}
+			break ;
+		case SMT_SAS :
+			if (np == PS)
+				phy->t_val[9] = TRUE ;
+			break ;
+#ifdef	CONCENTRATOR
+		case SMT_NAC :
+			/*
+			 * MAC intended on output
+			 */
+			if (np == PB)
+				phy->t_val[9] = TRUE ;
+			break ;
+#endif
+		}
+		mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ;
+		break ;
+	}
+	DB_PCMN(1,"SIG snd %x %x: \n", bit,phy->t_val[bit] ) ;
+}
+
+/*
+ * return status twisted (called by SMT)
+ */
+int pcm_status_twisted(smc)
+struct s_smc *smc ;
+{
+	int	twist = 0 ;
+	if (smc->s.sas != SMT_DAS)
+		return(0) ;
+	if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE))
+		twist |= 1 ;
+	if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE))
+		twist |= 2 ;
+	return(twist) ;
+}
+
+/*
+ * return status	(called by SMT)
+ *	type
+ *	state
+ *	remote phy type
+ *	remote mac yes/no
+ */
+void pcm_status_state(smc,np,type,state,remote,mac)
+struct s_smc *smc ;
+int np;
+int *type;
+int *state;
+int *remote;
+int *mac;
+{
+	struct s_phy	*phy = &smc->y[np] ;
+	struct fddi_mib_p	*mib ;
+
+	mib = phy->mib ;
+
+	/* remote PHY type and MAC - set only if active */
+	*mac = 0 ;
+	*type = mib->fddiPORTMy_Type ;		/* our PHY type */
+	*state = mib->fddiPORTConnectState ;
+	*remote = mib->fddiPORTNeighborType ;
+
+	switch(mib->fddiPORTPCMState) {
+	case PC8_ACTIVE :
+		*mac = mib->fddiPORTMacIndicated.R_val ;
+		break ;
+	}
+}
+
+/*
+ * return rooted station status (called by SMT)
+ */
+int pcm_rooted_station(smc)
+struct s_smc *smc ;
+{
+	int	n ;
+
+	for (n = 0 ; n < NUMPHYS ; n++) {
+		if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE &&
+		    smc->y[n].mib->fddiPORTNeighborType == TM)
+			return(0) ;
+	}
+	return(1) ;
+}
+
+/*
+ * Interrupt actions for PLC & PCM events
+ */
+void plc_irq(smc,np,cmd)
+struct s_smc *smc ;
+int np;			/* PHY index */
+unsigned int cmd;
+{
+	struct s_phy *phy = &smc->y[np] ;
+	struct s_plc *plc = &phy->plc ;
+	int		n ;
+#ifdef	SUPERNET_3
+	int		corr_mask ;
+#endif	/* SUPERNET_3 */
+	int		i ;
+
+	if (np >= smc->s.numphys) {
+		plc->soft_err++ ;
+		return ;
+	}
+	if (cmd & PL_EBUF_ERR) {	/* elastic buff. det. over-|underflow*/
+		/*
+		 * Check whether the SRF Condition occured.
+		 */
+		if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){
+			/*
+			 * This is the real Elasticity Error.
+			 * More than one in a row are treated as a
+			 * single one.
+			 * Only count this in the active state.
+			 */
+			phy->mib->fddiPORTEBError_Ct ++ ;
+
+		}
+
+		plc->ebuf_err++ ;
+		if (plc->ebuf_cont <= 1000) {
+			/*
+			 * Prevent counter from being wrapped after
+			 * hanging years in that interrupt.
+			 */
+			plc->ebuf_cont++ ;	/* Ebuf continous error */
+		}
+
+#ifdef	SUPERNET_3
+		if (plc->ebuf_cont == 1000 &&
+			((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) ==
+			PLC_REV_SN3)) {
+			/*
+			 * This interrupt remeained high for at least
+			 * 1000 consecutive interrupt calls.
+			 *
+			 * This is caused by a hardware error of the
+			 * ORION part of the Supernet III chipset.
+			 *
+			 * Disable this bit from the mask.
+			 */
+			corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ;
+			outpw(PLC(np,PL_INTR_MASK),corr_mask);
+
+			/*
+			 * Disconnect from the ring.
+			 * Call the driver with the reset indication.
+			 */
+			queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+
+			/*
+			 * Make an error log entry.
+			 */
+			SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ;
+
+			/*
+			 * Indicate the Reset.
+			 */
+			drv_reset_indication(smc) ;
+		}
+#endif	/* SUPERNET_3 */
+	} else {
+		/* Reset the continous error variable */
+		plc->ebuf_cont = 0 ;	/* reset Ebuf continous error */
+	}
+	if (cmd & PL_PHYINV) {		/* physical layer invalid signal */
+		plc->phyinv++ ;
+	}
+	if (cmd & PL_VSYM_CTR) {	/* violation symbol counter has incr.*/
+		plc->vsym_ctr++ ;
+	}
+	if (cmd & PL_MINI_CTR) {	/* dep. on PLC_CNTRL_A's MINI_CTR_INT*/
+		plc->mini_ctr++ ;
+	}
+	if (cmd & PL_LE_CTR) {		/* link error event counter */
+		int	j ;
+
+		/*
+		 * note: PL_LINK_ERR_CTR MUST be read to clear it
+		 */
+		j = inpw(PLC(np,PL_LE_THRESHOLD)) ;
+		i = inpw(PLC(np,PL_LINK_ERR_CTR)) ;
+
+		if (i < j) {
+			/* wrapped around */
+			i += 256 ;
+		}
+
+		if (phy->lem.lem_on) {
+			/* Note: Lem errors shall only be counted when
+			 * link is ACTIVE or LCT is active.
+			 */
+			phy->lem.lem_errors += i ;
+			phy->mib->fddiPORTLem_Ct += i ;
+		}
+	}
+	if (cmd & PL_TPC_EXPIRED) {	/* TPC timer reached zero */
+		if (plc->p_state == PS_LCT) {
+			/*
+			 * end of LCT
+			 */
+			;
+		}
+		plc->tpc_exp++ ;
+	}
+	if (cmd & PL_LS_MATCH) {	/* LS == LS in PLC_CNTRL_B's MATCH_LS*/
+		switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) {
+		case PL_I_IDLE :	phy->curr_ls = PC_ILS ;		break ;
+		case PL_I_HALT :	phy->curr_ls = PC_HLS ;		break ;
+		case PL_I_MASTR :	phy->curr_ls = PC_MLS ;		break ;
+		case PL_I_QUIET :	phy->curr_ls = PC_QLS ;		break ;
+		}
+	}
+	if (cmd & PL_PCM_BREAK) {	/* PCM has entered the BREAK state */
+		int	reason;
+
+		reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ;
+
+		switch (reason) {
+		case PL_B_PCS :		plc->b_pcs++ ;	break ;
+		case PL_B_TPC :		plc->b_tpc++ ;	break ;
+		case PL_B_TNE :		plc->b_tne++ ;	break ;
+		case PL_B_QLS :		plc->b_qls++ ;	break ;
+		case PL_B_ILS :		plc->b_ils++ ;	break ;
+		case PL_B_HLS :		plc->b_hls++ ;	break ;
+		}
+
+		/*jd 05-Aug-1999 changed: Bug #10419 */
+		DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag);
+		if (smc->e.DisconnectFlag == FALSE) {
+			DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason);
+			queue_event(smc,EVENT_PCM+np,PC_START) ;
+		}
+		else {
+			DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason);
+		}
+		return ;
+	}
+	/*
+	 * If both CODE & ENABLE are set ignore enable
+	 */
+	if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */
+		queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ;
+		n = inpw(PLC(np,PL_RCV_VECTOR)) ;
+		for (i = 0 ; i < plc->p_bits ; i++) {
+			phy->r_val[plc->p_start+i] = n & 1 ;
+			n >>= 1 ;
+		}
+	}
+	else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/
+		queue_event(smc,EVENT_PCM+np,PC_JOIN) ;
+	}
+	if (cmd & PL_TRACE_PROP) {	/* MLS while PC8_ACTIV || PC2_TRACE */
+		/*PC22b*/
+		if (!phy->tr_flag) {
+			DB_PCMN(1,"PCM : irq TRACE_PROP %d %d\n",
+				np,smc->mib.fddiSMTECMState) ;
+			phy->tr_flag = TRUE ;
+			smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ;
+			queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
+		}
+	}
+	/*
+	 * filter PLC glitch ???
+	 * QLS || HLS only while in PC2_TRACE state
+	 */
+	if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) {
+		/*PC22a*/
+		if (smc->e.path_test == PT_PASSED) {
+			DB_PCMN(1,"PCM : state = %s %d\n", get_pcmstate(smc,np),
+				phy->mib->fddiPORTPCMState) ;
+
+			smc->e.path_test = PT_PENDING ;
+			queue_event(smc,EVENT_ECM,EC_PATH_TEST) ;
+		}
+	}
+	if (cmd & PL_TNE_EXPIRED) {	/* TNE: length of noise events */
+		/* break_required (TNE > NS_Max) */
+		if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) {
+			if (!phy->tr_flag) {
+			   DB_PCMN(1,"PCM %c : PC81 %s\n",phy->phy_name,"NSE");
+			   queue_event(smc,EVENT_PCM+np,PC_START) ;
+			   return ;
+			}
+		}
+	}
+#if	0
+	if (cmd & PL_NP_ERR) {		/* NP has requested to r/w an inv reg*/
+		/*
+		 * It's a bug by AMD
+		 */
+		plc->np_err++ ;
+	}
+	/* pin inactiv (GND) */
+	if (cmd & PL_PARITY_ERR) {	/* p. error dedected on TX9-0 inp */
+		plc->parity_err++ ;
+	}
+	if (cmd & PL_LSDO) {		/* carrier detected */
+		;
+	}
+#endif
+}
+
+void pcm_set_lct_short(smc,n)
+struct s_smc *smc ;
+int n ;
+{
+	if (n <= 0 || n > 1000)
+		return ;
+	smc->s.lct_short = n ;
+}
+
+#ifdef	DEBUG
+/*
+ * fill state struct
+ */
+void pcm_get_state(smc,state)
+struct s_smc *smc ;
+struct smt_state *state ;
+{
+	struct s_phy	*phy ;
+	struct pcm_state *pcs ;
+	int	i ;
+	int	ii ;
+	short	rbits ;
+	short	tbits ;
+	struct fddi_mib_p	*mib ;
+
+	for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ;
+		i++ , phy++, pcs++ ) {
+		mib = phy->mib ;
+		pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ;
+		pcs->pcm_state = (u_char) mib->fddiPORTPCMState ;
+		pcs->pcm_mode = phy->pc_mode ;
+		pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ;
+		pcs->pcm_bsf = mib->fddiPORTBS_Flag ;
+		pcs->pcm_lsf = phy->ls_flag ;
+		pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ;
+		pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ;
+		for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) {
+			rbits <<= 1 ;
+			tbits <<= 1 ;
+			if (phy->r_val[NUMBITS-1-ii])
+				rbits |= 1 ;
+			if (phy->t_val[NUMBITS-1-ii])
+				tbits |= 1 ;
+		}
+		pcs->pcm_r_val = rbits ;
+		pcs->pcm_t_val = tbits ;
+	}
+}
+
+int get_pcm_state(smc,np)
+struct s_smc *smc ;
+int np;
+{
+	int pcs ;
+
+	SK_UNUSED(smc) ;
+
+	switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
+		case PL_PC0 :	pcs = PC_STOP ;		break ;
+		case PL_PC1 :	pcs = PC_START ;	break ;
+		case PL_PC2 :	pcs = PC_TRACE ;	break ;
+		case PL_PC3 :	pcs = PC_SIGNAL ;	break ;
+		case PL_PC4 :	pcs = PC_SIGNAL ;	break ;
+		case PL_PC5 :	pcs = PC_SIGNAL ;	break ;
+		case PL_PC6 :	pcs = PC_JOIN ;		break ;
+		case PL_PC7 :	pcs = PC_JOIN ;		break ;
+		case PL_PC8 :	pcs = PC_ENABLE ;	break ;
+		case PL_PC9 :	pcs = PC_MAINT ;	break ;
+		default :	pcs = PC_DISABLE ; 	break ;
+	}
+	return(pcs) ;
+}
+
+char *get_linestate(smc,np)
+struct s_smc *smc ;
+int np;
+{
+	char *ls = "" ;
+
+	SK_UNUSED(smc) ;
+
+	switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) {
+		case PL_L_NLS :	ls = "NOISE" ;	break ;
+		case PL_L_ALS :	ls = "ACTIV" ;	break ;
+		case PL_L_UND :	ls = "UNDEF" ;	break ;
+		case PL_L_ILS4:	ls = "ILS 4" ;	break ;
+		case PL_L_QLS :	ls = "QLS" ;	break ;
+		case PL_L_MLS :	ls = "MLS" ;	break ;
+		case PL_L_HLS :	ls = "HLS" ;	break ;
+		case PL_L_ILS16:ls = "ILS16" ;	break ;
+#ifdef	lint
+		default:	ls = "unknown" ; break ;
+#endif
+	}
+	return(ls) ;
+}
+
+char *get_pcmstate(smc,np)
+struct s_smc *smc ;
+int np;
+{
+	char *pcs ;
+	
+	SK_UNUSED(smc) ;
+
+	switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) {
+		case PL_PC0 :	pcs = "OFF" ;		break ;
+		case PL_PC1 :	pcs = "BREAK" ;		break ;
+		case PL_PC2 :	pcs = "TRACE" ;		break ;
+		case PL_PC3 :	pcs = "CONNECT";	break ;
+		case PL_PC4 :	pcs = "NEXT" ;		break ;
+		case PL_PC5 :	pcs = "SIGNAL" ;	break ;
+		case PL_PC6 :	pcs = "JOIN" ;		break ;
+		case PL_PC7 :	pcs = "VERIFY" ;	break ;
+		case PL_PC8 :	pcs = "ACTIV" ;		break ;
+		case PL_PC9 :	pcs = "MAINT" ;		break ;
+		default :	pcs = "UNKNOWN" ; 	break ;
+	}
+	return(pcs) ;
+}
+
+void list_phy(smc)
+struct s_smc *smc ;
+{
+	struct s_plc *plc ;
+	int np ;
+
+	for (np = 0 ; np < NUMPHYS ; np++) {
+		plc  = &smc->y[np].plc ;
+		printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ;
+		printf("\tsoft_error: %ld \t\tPC_Start : %ld\n",
+						plc->soft_err,plc->b_pcs);
+		printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n",
+			plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ;
+		printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n",
+						plc->ebuf_err,plc->b_tne) ;
+		printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n",
+			plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ;
+		printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n",
+						plc->vsym_ctr,plc->b_ils)  ;
+		printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n",
+						plc->mini_ctr,plc->b_hls) ;
+		printf("\tnodepr_err: %ld\n",plc->np_err) ;
+		printf("\tTPC_exp : %ld\n",plc->tpc_exp) ;
+		printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ;
+	}
+}
+
+
+#ifdef	CONCENTRATOR
+void pcm_lem_dump(smc)
+struct s_smc *smc ;
+{
+	int		i ;
+	struct s_phy	*phy ;
+	struct fddi_mib_p	*mib ;
+
+	char		*entostring() ;
+
+	printf("PHY	errors	BER\n") ;
+	printf("----------------------\n") ;
+	for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) {
+		if (!plc_is_installed(smc,i))
+			continue ;
+		mib = phy->mib ;
+		printf("%s\t%ld\t10E-%d\n",
+			entostring(smc,ENTITY_PHY(i)),
+			mib->fddiPORTLem_Ct,
+			mib->fddiPORTLer_Estimate) ;
+	}
+}
+#endif
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/pmf.c linux.18p8/drivers/net/skfp/pmf.c
--- linux.vanilla/drivers/net/skfp/pmf.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/pmf.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,1701 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	Parameter Management Frame processing for SMT 7.2
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	SLIM_SMT
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)pmf.c	1.37 97/08/04 (C) SK " ;
+#endif
+
+static int smt_authorize() ;
+static int smt_check_set_count() ;
+static const struct s_p_tab *smt_get_ptab() ;
+static int smt_mib_phys() ;
+int smt_set_para() ;
+void smt_add_para() ;
+
+#define MOFFSS(e)	((int)&(((struct fddi_mib *)0)->e))
+#define MOFFSA(e)	((int) (((struct fddi_mib *)0)->e))
+
+#define MOFFMS(e)	((int)&(((struct fddi_mib_m *)0)->e))
+#define MOFFMA(e)	((int) (((struct fddi_mib_m *)0)->e))
+
+#define MOFFAS(e)	((int)&(((struct fddi_mib_a *)0)->e))
+#define MOFFAA(e)	((int) (((struct fddi_mib_a *)0)->e))
+
+#define MOFFPS(e)	((int)&(((struct fddi_mib_p *)0)->e))
+#define MOFFPA(e)	((int) (((struct fddi_mib_p *)0)->e))
+
+
+#define AC_G	0x01		/* Get */
+#define AC_GR	0x02		/* Get/Set */
+#define AC_S	0x04		/* Set */
+#define AC_NA	0x08
+#define AC_GROUP	0x10		/* Group */
+#define MS2BCLK(x)	((x)*12500L)
+/*
+	F	LFag (byte)
+	B	byte
+	S	u_short	16 bit
+	C	Counter 32 bit
+	L	Long 32 bit
+	T	Timer_2	32 bit
+	P	TimeStamp ;
+	A	LongAddress (6 byte)
+	E	Enum 16 bit
+	R	ResId 16 Bit
+*/
+static const struct s_p_tab {
+	u_short	p_num ;		/* parameter code */
+	u_char	p_access ;	/* access rights */
+	u_short	p_offset ;	/* offset in mib */
+	char	p_swap[3] ;	/* format string */
+} p_tab[] = {
+	/* StationIdGrp */
+	{ SMT_P100A,AC_GROUP	} ,
+	{ SMT_P100B,AC_G,	MOFFSS(fddiSMTStationId),	"8"	} ,
+	{ SMT_P100D,AC_G,	MOFFSS(fddiSMTOpVersionId),	"S"	} ,
+	{ SMT_P100E,AC_G,	MOFFSS(fddiSMTHiVersionId),	"S"	} ,
+	{ SMT_P100F,AC_G,	MOFFSS(fddiSMTLoVersionId),	"S"	} ,
+	{ SMT_P1010,AC_G,	MOFFSA(fddiSMTManufacturerData), "D" } ,
+	{ SMT_P1011,AC_GR,	MOFFSA(fddiSMTUserData),	"D"	} ,
+	{ SMT_P1012,AC_G,	MOFFSS(fddiSMTMIBVersionId),	"S"	} ,
+
+	/* StationConfigGrp */
+	{ SMT_P1014,AC_GROUP	} ,
+	{ SMT_P1015,AC_G,	MOFFSS(fddiSMTMac_Ct),		"B"	} ,
+	{ SMT_P1016,AC_G,	MOFFSS(fddiSMTNonMaster_Ct),	"B"	} ,
+	{ SMT_P1017,AC_G,	MOFFSS(fddiSMTMaster_Ct),	"B"	} ,
+	{ SMT_P1018,AC_G,	MOFFSS(fddiSMTAvailablePaths),	"B"	} ,
+	{ SMT_P1019,AC_G,	MOFFSS(fddiSMTConfigCapabilities),"S"	} ,
+	{ SMT_P101A,AC_GR,	MOFFSS(fddiSMTConfigPolicy),	"wS"	} ,
+	{ SMT_P101B,AC_GR,	MOFFSS(fddiSMTConnectionPolicy),"wS"	} ,
+	{ SMT_P101D,AC_GR,	MOFFSS(fddiSMTTT_Notify),	"wS"	} ,
+	{ SMT_P101E,AC_GR,	MOFFSS(fddiSMTStatRptPolicy),	"bB"	} ,
+	{ SMT_P101F,AC_GR,	MOFFSS(fddiSMTTrace_MaxExpiration),"lL"	} ,
+	{ SMT_P1020,AC_G,	MOFFSA(fddiSMTPORTIndexes),	"II"	} ,
+	{ SMT_P1021,AC_G,	MOFFSS(fddiSMTMACIndexes),	"I"	} ,
+	{ SMT_P1022,AC_G,	MOFFSS(fddiSMTBypassPresent),	"F"	} ,
+
+	/* StatusGrp */
+	{ SMT_P1028,AC_GROUP	} ,
+	{ SMT_P1029,AC_G,	MOFFSS(fddiSMTECMState),	"E"	} ,
+	{ SMT_P102A,AC_G,	MOFFSS(fddiSMTCF_State),	"E"	} ,
+	{ SMT_P102C,AC_G,	MOFFSS(fddiSMTRemoteDisconnectFlag),"F"	} ,
+	{ SMT_P102D,AC_G,	MOFFSS(fddiSMTStationStatus),	"E"	} ,
+	{ SMT_P102E,AC_G,	MOFFSS(fddiSMTPeerWrapFlag),	"F"	} ,
+
+	/* MIBOperationGrp */
+	{ SMT_P1032,AC_GROUP	} ,
+	{ SMT_P1033,AC_G,	MOFFSA(fddiSMTTimeStamp),"P"		} ,
+	{ SMT_P1034,AC_G,	MOFFSA(fddiSMTTransitionTimeStamp),"P"	} ,
+	/* NOTE : SMT_P1035 is already swapped ! SMT_P_SETCOUNT */
+	{ SMT_P1035,AC_G,	MOFFSS(fddiSMTSetCount),"4P"		} ,
+	{ SMT_P1036,AC_G,	MOFFSS(fddiSMTLastSetStationId),"8"	} ,
+
+	{ SMT_P103C,AC_S,	0,				"wS"	} ,
+
+	/*
+	 * PRIVATE EXTENSIONS
+	 * only accessable locally to get/set passwd
+	 */
+	{ SMT_P10F0,AC_GR,	MOFFSA(fddiPRPMFPasswd),	"8"	} ,
+	{ SMT_P10F1,AC_GR,	MOFFSS(fddiPRPMFStation),	"8"	} ,
+#ifdef	ESS
+	{ SMT_P10F2,AC_GR,	MOFFSS(fddiESSPayload),		"lL"	} ,
+	{ SMT_P10F3,AC_GR,	MOFFSS(fddiESSOverhead),	"lL"	} ,
+	{ SMT_P10F4,AC_GR,	MOFFSS(fddiESSMaxTNeg),		"lL"	} ,
+	{ SMT_P10F5,AC_GR,	MOFFSS(fddiESSMinSegmentSize),	"lL"	} ,
+	{ SMT_P10F6,AC_GR,	MOFFSS(fddiESSCategory),	"lL"	} ,
+	{ SMT_P10F7,AC_GR,	MOFFSS(fddiESSSynchTxMode),	"wS"	} ,
+#endif
+#ifdef	SBA
+	{ SMT_P10F8,AC_GR,	MOFFSS(fddiSBACommand),		"bF"	} ,
+	{ SMT_P10F9,AC_GR,	MOFFSS(fddiSBAAvailable),	"bF"	} ,
+#endif
+	/* MAC Attributes */
+	{ SMT_P200A,AC_GROUP	} ,
+	{ SMT_P200B,AC_G,	MOFFMS(fddiMACFrameStatusFunctions),"S"	} ,
+	{ SMT_P200D,AC_G,	MOFFMS(fddiMACT_MaxCapabilitiy),"T"	} ,
+	{ SMT_P200E,AC_G,	MOFFMS(fddiMACTVXCapabilitiy),"T"	} ,
+
+	/* ConfigGrp */
+	{ SMT_P2014,AC_GROUP	} ,
+	{ SMT_P2016,AC_G,	MOFFMS(fddiMACAvailablePaths),	"B"	} ,
+	{ SMT_P2017,AC_G,	MOFFMS(fddiMACCurrentPath),	"S"	} ,
+	{ SMT_P2018,AC_G,	MOFFMS(fddiMACUpstreamNbr),	"A"	} ,
+	{ SMT_P2019,AC_G,	MOFFMS(fddiMACDownstreamNbr),	"A"	} ,
+	{ SMT_P201A,AC_G,	MOFFMS(fddiMACOldUpstreamNbr),	"A"	} ,
+	{ SMT_P201B,AC_G,	MOFFMS(fddiMACOldDownstreamNbr),"A"	} ,
+	{ SMT_P201D,AC_G,	MOFFMS(fddiMACDupAddressTest),	"E"	} ,
+	{ SMT_P2020,AC_GR,	MOFFMS(fddiMACRequestedPaths),	"wS"	} ,
+	{ SMT_P2021,AC_G,	MOFFMS(fddiMACDownstreamPORTType),"E"	} ,
+	{ SMT_P2022,AC_G,	MOFFMS(fddiMACIndex),		"S"	} ,
+
+	/* AddressGrp */
+	{ SMT_P2028,AC_GROUP	} ,
+	{ SMT_P2029,AC_G,	MOFFMS(fddiMACSMTAddress),	"A"	} ,
+
+	/* OperationGrp */
+	{ SMT_P2032,AC_GROUP	} ,
+	{ SMT_P2033,AC_G,	MOFFMS(fddiMACT_Req),		"T"	} ,
+	{ SMT_P2034,AC_G,	MOFFMS(fddiMACT_Neg),		"T"	} ,
+	{ SMT_P2035,AC_G,	MOFFMS(fddiMACT_Max),		"T"	} ,
+	{ SMT_P2036,AC_G,	MOFFMS(fddiMACTvxValue),	"T"	} ,
+	{ SMT_P2038,AC_G,	MOFFMS(fddiMACT_Pri0),		"T"	} ,
+	{ SMT_P2039,AC_G,	MOFFMS(fddiMACT_Pri1),		"T"	} ,
+	{ SMT_P203A,AC_G,	MOFFMS(fddiMACT_Pri2),		"T"	} ,
+	{ SMT_P203B,AC_G,	MOFFMS(fddiMACT_Pri3),		"T"	} ,
+	{ SMT_P203C,AC_G,	MOFFMS(fddiMACT_Pri4),		"T"	} ,
+	{ SMT_P203D,AC_G,	MOFFMS(fddiMACT_Pri5),		"T"	} ,
+	{ SMT_P203E,AC_G,	MOFFMS(fddiMACT_Pri6),		"T"	} ,
+
+
+	/* CountersGrp */
+	{ SMT_P2046,AC_GROUP	} ,
+	{ SMT_P2047,AC_G,	MOFFMS(fddiMACFrame_Ct),	"C"	} ,
+	{ SMT_P2048,AC_G,	MOFFMS(fddiMACCopied_Ct),	"C"	} ,
+	{ SMT_P2049,AC_G,	MOFFMS(fddiMACTransmit_Ct),	"C"	} ,
+	{ SMT_P204A,AC_G,	MOFFMS(fddiMACToken_Ct),	"C"	} ,
+	{ SMT_P2051,AC_G,	MOFFMS(fddiMACError_Ct),	"C"	} ,
+	{ SMT_P2052,AC_G,	MOFFMS(fddiMACLost_Ct),		"C"	} ,
+	{ SMT_P2053,AC_G,	MOFFMS(fddiMACTvxExpired_Ct),	"C"	} ,
+	{ SMT_P2054,AC_G,	MOFFMS(fddiMACNotCopied_Ct),	"C"	} ,
+	{ SMT_P2056,AC_G,	MOFFMS(fddiMACRingOp_Ct),	"C"	} ,
+
+	/* FrameErrorConditionGrp */
+	{ SMT_P205A,AC_GROUP	} ,
+	{ SMT_P205F,AC_GR,	MOFFMS(fddiMACFrameErrorThreshold),"wS"	} ,
+	{ SMT_P2060,AC_G,	MOFFMS(fddiMACFrameErrorRatio),	"S"	} ,
+
+	/* NotCopiedConditionGrp */
+	{ SMT_P2064,AC_GROUP	} ,
+	{ SMT_P2067,AC_GR,	MOFFMS(fddiMACNotCopiedThreshold),"wS"	} ,
+	{ SMT_P2069,AC_G,	MOFFMS(fddiMACNotCopiedRatio),	"S"	} ,
+
+	/* StatusGrp */
+	{ SMT_P206E,AC_GROUP	} ,
+	{ SMT_P206F,AC_G,	MOFFMS(fddiMACRMTState),	"S"	} ,
+	{ SMT_P2070,AC_G,	MOFFMS(fddiMACDA_Flag),	"F"	} ,
+	{ SMT_P2071,AC_G,	MOFFMS(fddiMACUNDA_Flag),	"F"	} ,
+	{ SMT_P2072,AC_G,	MOFFMS(fddiMACFrameErrorFlag),	"F"	} ,
+	{ SMT_P2073,AC_G,	MOFFMS(fddiMACNotCopiedFlag),	"F"	} ,
+	{ SMT_P2074,AC_G,	MOFFMS(fddiMACMA_UnitdataAvailable),"F"	} ,
+	{ SMT_P2075,AC_G,	MOFFMS(fddiMACHardwarePresent),	"F"	} ,
+	{ SMT_P2076,AC_GR,	MOFFMS(fddiMACMA_UnitdataEnable),"bF"	} ,
+
+	/*
+	 * PRIVATE EXTENSIONS
+	 * only accessable locally to get/set TMIN
+	 */
+	{ SMT_P20F0,AC_NA						} ,
+	{ SMT_P20F1,AC_GR,	MOFFMS(fddiMACT_Min),		"lT"	} ,
+
+	/* Path Attributes */
+	/*
+	 * DON't swap 320B,320F,3210: they are already swapped in swap_para()
+	 */
+	{ SMT_P320A,AC_GROUP	} ,
+	{ SMT_P320B,AC_G,	MOFFAS(fddiPATHIndex),		"r"	} ,
+	{ SMT_P320F,AC_GR,	MOFFAS(fddiPATHSbaPayload),	"l4"	} ,
+	{ SMT_P3210,AC_GR,	MOFFAS(fddiPATHSbaOverhead),	"l4"	} ,
+	/* fddiPATHConfiguration */
+	{ SMT_P3212,AC_G,	0,				""	} ,
+	{ SMT_P3213,AC_GR,	MOFFAS(fddiPATHT_Rmode),	"lT"	} ,
+	{ SMT_P3214,AC_GR,	MOFFAS(fddiPATHSbaAvailable),	"lL"	} ,
+	{ SMT_P3215,AC_GR,	MOFFAS(fddiPATHTVXLowerBound),	"lT"	} ,
+	{ SMT_P3216,AC_GR,	MOFFAS(fddiPATHT_MaxLowerBound),"lT"	} ,
+	{ SMT_P3217,AC_GR,	MOFFAS(fddiPATHMaxT_Req),	"lT"	} ,
+
+	/* Port Attributes */
+	/* ConfigGrp */
+	{ SMT_P400A,AC_GROUP	} ,
+	{ SMT_P400C,AC_G,	MOFFPS(fddiPORTMy_Type),	"E"	} ,
+	{ SMT_P400D,AC_G,	MOFFPS(fddiPORTNeighborType),	"E"	} ,
+	{ SMT_P400E,AC_GR,	MOFFPS(fddiPORTConnectionPolicies),"bB"	} ,
+	{ SMT_P400F,AC_G,	MOFFPS(fddiPORTMacIndicated),	"2"	} ,
+	{ SMT_P4010,AC_G,	MOFFPS(fddiPORTCurrentPath),	"E"	} ,
+	{ SMT_P4011,AC_GR,	MOFFPA(fddiPORTRequestedPaths),	"l4"	} ,
+	{ SMT_P4012,AC_G,	MOFFPS(fddiPORTMACPlacement),	"S"	} ,
+	{ SMT_P4013,AC_G,	MOFFPS(fddiPORTAvailablePaths),	"B"	} ,
+	{ SMT_P4016,AC_G,	MOFFPS(fddiPORTPMDClass),	"E"	} ,
+	{ SMT_P4017,AC_G,	MOFFPS(fddiPORTConnectionCapabilities),	"B"} ,
+	{ SMT_P401D,AC_G,	MOFFPS(fddiPORTIndex),		"R"	} ,
+
+	/* OperationGrp */
+	{ SMT_P401E,AC_GROUP	} ,
+	{ SMT_P401F,AC_GR,	MOFFPS(fddiPORTMaint_LS),	"wE"	} ,
+	{ SMT_P4021,AC_G,	MOFFPS(fddiPORTBS_Flag),	"F"	} ,
+	{ SMT_P4022,AC_G,	MOFFPS(fddiPORTPC_LS),		"E"	} ,
+
+	/* ErrorCtrsGrp */
+	{ SMT_P4028,AC_GROUP	} ,
+	{ SMT_P4029,AC_G,	MOFFPS(fddiPORTEBError_Ct),	"C"	} ,
+	{ SMT_P402A,AC_G,	MOFFPS(fddiPORTLCTFail_Ct),	"C"	} ,
+
+	/* LerGrp */
+	{ SMT_P4032,AC_GROUP	} ,
+	{ SMT_P4033,AC_G,	MOFFPS(fddiPORTLer_Estimate),	"F"	} ,
+	{ SMT_P4034,AC_G,	MOFFPS(fddiPORTLem_Reject_Ct),	"C"	} ,
+	{ SMT_P4035,AC_G,	MOFFPS(fddiPORTLem_Ct),		"C"	} ,
+	{ SMT_P403A,AC_GR,	MOFFPS(fddiPORTLer_Cutoff),	"bB"	} ,
+	{ SMT_P403B,AC_GR,	MOFFPS(fddiPORTLer_Alarm),	"bB"	} ,
+
+	/* StatusGrp */
+	{ SMT_P403C,AC_GROUP	} ,
+	{ SMT_P403D,AC_G,	MOFFPS(fddiPORTConnectState),	"E"	} ,
+	{ SMT_P403E,AC_G,	MOFFPS(fddiPORTPCMStateX),	"E"	} ,
+	{ SMT_P403F,AC_G,	MOFFPS(fddiPORTPC_Withhold),	"E"	} ,
+	{ SMT_P4040,AC_G,	MOFFPS(fddiPORTLerFlag),	"F"	} ,
+	{ SMT_P4041,AC_G,	MOFFPS(fddiPORTHardwarePresent),"F"	} ,
+
+	{ SMT_P4046,AC_S,	0,				"wS"	} ,
+
+	{ 0,	AC_GROUP	} ,
+	{ 0 }
+} ;
+
+
+static SMbuf *smt_build_pmf_response() ;
+
+void smt_pmf_received_pack(smc,mb,local)
+struct s_smc *smc ;
+SMbuf *mb ;
+int local ;
+{
+	struct smt_header	*sm ;
+	SMbuf		*reply ;
+
+	sm = smtod(mb,struct smt_header *) ;
+	DB_SMT("SMT: processing PMF frame at %x len %d\n",sm,mb->sm_len) ;
+#ifdef	DEBUG
+	dump_smt(smc,sm,"PMF Received") ;
+#endif
+	/*
+	 * Start the watchdog: It may be a long, long packet and
+	 * maybe the watchdog occurs ...
+	 */
+	smt_start_watchdog(smc) ;
+
+	if (sm->smt_class == SMT_PMF_GET ||
+	    sm->smt_class == SMT_PMF_SET) {
+		reply = smt_build_pmf_response(smc,sm,
+			sm->smt_class == SMT_PMF_SET,local) ;
+		if (reply) {
+			sm = smtod(reply,struct smt_header *) ;
+#ifdef	DEBUG
+			dump_smt(smc,sm,"PMF Reply") ;
+#endif
+			smt_send_frame(smc,reply,FC_SMT_INFO,local) ;
+		}
+	}
+}
+
+extern	SMbuf	*smt_get_mbuf() ;
+
+static SMbuf *smt_build_pmf_response(smc,req,set,local)
+struct s_smc *smc ;
+struct smt_header *req ;
+int	set ;
+int	local ;
+{
+	SMbuf			*mb ;
+	struct smt_header	*smt ;
+	struct smt_para		*pa ;
+	struct smt_p_reason	*res ;
+	const struct s_p_tab	*pt ;
+	int			len ;
+	int			index ;
+	int			idx_end ;
+	int			error ;
+	int			range ;
+	SK_LOC_DECL(struct s_pcon,pcon) ;
+	SK_LOC_DECL(struct s_pcon,set_pcon) ;
+
+	/*
+	 * build SMT header
+	 */
+	if (!(mb = smt_get_mbuf(smc)))
+		return(mb) ;
+
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_dest = req->smt_source ;	/* DA == source of request */
+	smt->smt_class = req->smt_class ;	/* same class (GET/SET) */
+	smt->smt_type = SMT_REPLY ;
+	smt->smt_version = SMT_VID_2 ;
+	smt->smt_tid = req->smt_tid ;		/* same TID */
+	smt->smt_pad = 0 ;
+	smt->smt_len = 0 ;
+
+	/*
+	 * setup parameter status
+	 */
+	pcon.pc_len = SMT_MAX_INFO_LEN ;	/* max para length */
+	pcon.pc_err = 0 ;			/* no error */
+	pcon.pc_badset = 0 ;			/* no bad set count */
+	pcon.pc_p = (void *) (smt + 1) ;	/* paras start here */
+
+	/*
+	 * check authoriziation and set count
+	 */
+	error = 0 ;
+	if (set) {
+		if (!local && smt_authorize(smc,req))
+			error = SMT_RDF_AUTHOR ;
+		else if (smt_check_set_count(smc,req))
+			pcon.pc_badset = SMT_RDF_BADSET ;
+	}
+	/*
+	 * add reason code and all mandatory parameters
+	 */
+	res = (struct smt_p_reason *) pcon.pc_p ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P_REASON,0,0) ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ;
+	/* update 1035 and 1036 later if set */
+	set_pcon = pcon ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P1035,0,0) ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P1036,0,0) ;
+
+	pcon.pc_err = error ;
+	len = req->smt_len ;
+	pa = (struct smt_para *) (req + 1) ;
+	/*
+	 * process list of paras
+	 */
+	while (!pcon.pc_err && len > 0 ) {
+		if (((u_short)len < pa->p_len + PARA_LEN) || (pa->p_len & 3)) {
+			pcon.pc_err = SMT_RDF_LENGTH ;
+			break ;
+		}
+
+		if (((range = (pa->p_type & 0xf000)) == 0x2000) ||
+			range == 0x3000 || range == 0x4000) {
+			/*
+			 * get index for PART,MAC ad PATH group
+			 */
+			index = *((u_char *)pa + PARA_LEN + 3) ;/* index */
+			idx_end = index ;
+			if (!set && (pa->p_len != 4)) {
+				pcon.pc_err = SMT_RDF_LENGTH ;
+				break ;
+			}
+			if (!index && !set) {
+				switch (range) {
+				case 0x2000 :
+					index = INDEX_MAC ;
+					idx_end = index - 1 + NUMMACS ;
+					break ;
+				case 0x3000 :
+					index = INDEX_PATH ;
+					idx_end = index - 1 + NUMPATHS ;
+					break ;
+				case 0x4000 :
+					index = INDEX_PORT ;
+					idx_end = index - 1 + NUMPHYS ;
+#ifndef	CONCENTRATOR
+					if (smc->s.sas == SMT_SAS)
+						idx_end = INDEX_PORT ;
+#endif
+					break ;
+				}
+			}
+		}
+		else {
+			/*
+			 * smt group has no index
+			 */
+			if (!set && (pa->p_len != 0)) {
+				pcon.pc_err = SMT_RDF_LENGTH ;
+				break ;
+			}
+			index = 0 ;
+			idx_end = 0 ;
+		}
+		while (index <= idx_end) {
+			/*
+			 * if group
+			 *	add all paras of group
+			 */
+			pt = smt_get_ptab(pa->p_type) ;
+			if (pt && pt->p_access == AC_GROUP && !set) {
+				pt++ ;
+				while (pt->p_access == AC_G ||
+					pt->p_access == AC_GR) {
+					smt_add_para(smc,&pcon,pt->p_num,
+						index,local);
+					pt++ ;
+				}
+			}
+			/*
+			 * ignore
+			 *	AUTHORIZATION in get/set
+			 *	SET COUNT in set
+			 */
+			else if (pa->p_type != SMT_P_AUTHOR &&
+				 (!set || (pa->p_type != SMT_P1035))) {
+				int	st ;
+				if (pcon.pc_badset) {
+					smt_add_para(smc,&pcon,pa->p_type,
+						index,local) ;
+				}
+				else if (set) {
+					st = smt_set_para(smc,pa,index,local,1);
+					/*
+					 * return para even if error
+					 */
+					smt_add_para(smc,&pcon,pa->p_type,
+						index,local) ;
+					pcon.pc_err = st ;
+				}
+				else {
+					if (pt && pt->p_access == AC_S) {
+						pcon.pc_err =
+							SMT_RDF_ILLEGAL ;
+					}
+					smt_add_para(smc,&pcon,pa->p_type,
+						index,local) ;
+				}
+			}
+			if (pcon.pc_err)
+				break ;
+			index++ ;
+		}
+		len -= pa->p_len + PARA_LEN ;
+		pa = (struct smt_para *) ((char *)pa + pa->p_len + PARA_LEN) ;
+	}
+	smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
+	mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
+
+	/* update reason code */
+	res->rdf_reason = pcon.pc_badset ? pcon.pc_badset :
+			pcon.pc_err ? pcon.pc_err : SMT_RDF_SUCCESS ;
+	if (set && (res->rdf_reason == SMT_RDF_SUCCESS)) {
+		/*
+		 * increment set count
+		 * set time stamp
+		 * store station id of last set
+		 */
+		smc->mib.fddiSMTSetCount.count++ ;
+		smt_set_timestamp(smc,smc->mib.fddiSMTSetCount.timestamp) ;
+		smc->mib.fddiSMTLastSetStationId = req->smt_sid ;
+		smt_add_para(smc,&set_pcon,(u_short) SMT_P1035,0,0) ;
+		smt_add_para(smc,&set_pcon,(u_short) SMT_P1036,0,0) ;
+	}
+	return(mb) ;
+}
+
+extern void *sm_to_para() ;
+
+static int smt_authorize(smc,sm)
+struct s_smc *smc ;
+struct smt_header *sm ;
+{
+	struct smt_para	*pa ;
+	int		i ;
+	char		*p ;
+
+	/*
+	 * check source station id if not zero
+	 */
+	p = (char *) &smc->mib.fddiPRPMFStation ;
+	for (i = 0 ; i < 8 && !p[i] ; i++)
+		;
+	if (i != 8) {
+		if (memcmp((char *) &sm->smt_sid,
+			(char *) &smc->mib.fddiPRPMFStation,8))
+			return(1) ;
+	}
+	/*
+	 * check authoriziation parameter if passwd not zero
+	 */
+	p = (char *) smc->mib.fddiPRPMFPasswd ;
+	for (i = 0 ; i < 8 && !p[i] ; i++)
+		;
+	if (i != 8) {
+		pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P_AUTHOR) ;
+		if (!pa)
+			return(1) ;
+		if (pa->p_len != 8)
+			return(1) ;
+		if (memcmp((char *)(pa+1),(char *)smc->mib.fddiPRPMFPasswd,8))
+			return(1) ;
+	}
+	return(0) ;
+}
+
+static int smt_check_set_count(smc,sm)
+struct s_smc *smc ;
+struct smt_header *sm ;
+{
+	struct smt_para	*pa ;
+	struct smt_p_setcount	*sc ;
+
+	pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P1035) ;
+	if (pa) {
+		sc = (struct smt_p_setcount *) pa ;
+		if ((smc->mib.fddiSMTSetCount.count != sc->count) ||
+			memcmp((char *) smc->mib.fddiSMTSetCount.timestamp,
+			(char *)sc->timestamp,8))
+			return(1) ;
+	}
+	return(0) ;
+}
+
+void smt_add_para(smc,pcon,para,index,local)
+struct s_smc *smc ;
+struct s_pcon *pcon ;
+u_short para ;
+int index ;
+int local ;
+{
+	struct smt_para	*pa ;
+	const struct s_p_tab	*pt ;
+	struct fddi_mib_m *mib_m = 0 ;
+	struct fddi_mib_p *mib_p = 0 ;
+	int		len ;
+	int		plen ;
+	char		*from ;
+	char		*to ;
+	const char	*swap ;
+	char		c ;
+	int		range ;
+	char		*mib_addr ;
+	int		mac ;
+	int		path ;
+	int		port ;
+	int		sp_len ;
+
+	/*
+	 * skip if errror
+	 */
+	if (pcon->pc_err)
+		return ;
+
+	/*
+	 * actions don't have a value
+	 */
+	pt = smt_get_ptab(para) ;
+	if (pt && pt->p_access == AC_S)
+		return ;
+
+	to = (char *) (pcon->pc_p) ;	/* destination pointer */
+	len = pcon->pc_len ;		/* free space */
+	plen = len ;			/* remember start length */
+	pa = (struct smt_para *) to ;	/* type/length pointer */
+	to += PARA_LEN ;		/* skip smt_para */
+	len -= PARA_LEN ;
+	/*
+	 * set index if required
+	 */
+	if (((range = (para & 0xf000)) == 0x2000) ||
+		range == 0x3000 || range == 0x4000) {
+		if (len < 4)
+			goto wrong_error ;
+		to[0] = 0 ;
+		to[1] = 0 ;
+		to[2] = 0 ;
+		to[3] = index ;
+		len -= 4 ;
+		to += 4 ;
+	}
+	mac = index - INDEX_MAC ;
+	path = index - INDEX_PATH ;
+	port = index - INDEX_PORT ;
+	/*
+	 * get pointer to mib
+	 */
+	switch (range) {
+	case 0x1000 :
+	default :
+		mib_addr = (char *) (&smc->mib) ;
+		break ;
+	case 0x2000 :
+		if (mac < 0 || mac >= NUMMACS) {
+			pcon->pc_err = SMT_RDF_NOPARAM ;
+			return ;
+		}
+		mib_addr = (char *) (&smc->mib.m[mac]) ;
+		mib_m = (struct fddi_mib_m *) mib_addr ;
+		break ;
+	case 0x3000 :
+		if (path < 0 || path >= NUMPATHS) {
+			pcon->pc_err = SMT_RDF_NOPARAM ;
+			return ;
+		}
+		mib_addr = (char *) (&smc->mib.a[path]) ;
+		break ;
+	case 0x4000 :
+		if (port < 0 || port >= smt_mib_phys(smc)) {
+			pcon->pc_err = SMT_RDF_NOPARAM ;
+			return ;
+		}
+		mib_addr = (char *) (&smc->mib.p[port_to_mib(smc,port)]) ;
+		mib_p = (struct fddi_mib_p *) mib_addr ;
+		break ;
+	}
+	/*
+	 * check special paras
+	 */
+	swap = 0 ;
+	switch (para) {
+	case SMT_P10F0 :
+	case SMT_P10F1 :
+#ifdef	ESS
+	case SMT_P10F2 :
+	case SMT_P10F3 :
+	case SMT_P10F4 :
+	case SMT_P10F5 :
+	case SMT_P10F6 :
+	case SMT_P10F7 :
+#endif
+#ifdef	SBA
+	case SMT_P10F8 :
+	case SMT_P10F9 :
+#endif
+	case SMT_P20F1 :
+		if (!local) {
+			pcon->pc_err = SMT_RDF_NOPARAM ;
+			return ;
+		}
+		break ;
+	case SMT_P2034 :
+	case SMT_P2046 :
+	case SMT_P2047 :
+	case SMT_P204A :
+	case SMT_P2051 :
+	case SMT_P2052 :
+		mac_update_counter(smc) ;
+		break ;
+	case SMT_P4022:
+		mib_p->fddiPORTPC_LS = LS2MIB(
+			sm_pm_get_ls(smc,port_to_mib(smc,port))) ;
+		break ;
+	case SMT_P_REASON :
+		* (u_long *) to = 0 ;
+		sp_len = 4 ;
+		goto sp_done ;
+	case SMT_P1033 :			/* time stamp */
+		smt_set_timestamp(smc,smc->mib.fddiSMTTimeStamp) ;
+		break ;
+
+	case SMT_P1020:				/* port indexes */
+#if	NUMPHYS == 12
+		swap = "IIIIIIIIIIII" ;
+#else
+#if	NUMPHYS == 2
+		if (smc->s.sas == SMT_SAS)
+			swap = "I" ;
+		else
+			swap = "II" ;
+#else
+#if	NUMPHYS == 24
+		swap = "IIIIIIIIIIIIIIIIIIIIIIII" ;
+#else
+	????
+#endif
+#endif
+#endif
+		break ;
+	case SMT_P3212 :
+		{
+			sp_len = cem_build_path(smc,to,path) ;
+			goto sp_done ;
+		}
+	case SMT_P1048 :		/* peer wrap condition */
+		{
+			struct smt_p_1048	*sp ;
+			sp = (struct smt_p_1048 *) to ;
+			sp->p1048_flag = smc->mib.fddiSMTPeerWrapFlag ;
+			sp->p1048_cf_state = smc->mib.fddiSMTCF_State ;
+			sp_len = sizeof(struct smt_p_1048) ;
+			goto sp_done ;
+		}
+	case SMT_P208C :
+		{
+			struct smt_p_208c	*sp ;
+			sp = (struct smt_p_208c *) to ;
+			sp->p208c_flag =
+				smc->mib.m[MAC0].fddiMACDuplicateAddressCond ;
+			sp->p208c_dupcondition =
+				(mib_m->fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0) |
+				(mib_m->fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0);
+			sp->p208c_fddilong =
+				mib_m->fddiMACSMTAddress ;
+			sp->p208c_fddiunalong =
+				mib_m->fddiMACUpstreamNbr ;
+			sp->p208c_pad = 0 ;
+			sp_len = sizeof(struct smt_p_208c) ;
+			goto sp_done ;
+		}
+	case SMT_P208D :		/* frame error condition */
+		{
+			struct smt_p_208d	*sp ;
+			sp = (struct smt_p_208d *) to ;
+			sp->p208d_flag =
+				mib_m->fddiMACFrameErrorFlag ;
+			sp->p208d_frame_ct =
+				mib_m->fddiMACFrame_Ct ;
+			sp->p208d_error_ct =
+				mib_m->fddiMACError_Ct ;
+			sp->p208d_lost_ct =
+				mib_m->fddiMACLost_Ct ;
+			sp->p208d_ratio =
+				mib_m->fddiMACFrameErrorRatio ;
+			sp_len = sizeof(struct smt_p_208d) ;
+			goto sp_done ;
+		}
+	case SMT_P208E :		/* not copied condition */
+		{
+			struct smt_p_208e	*sp ;
+			sp = (struct smt_p_208e *) to ;
+			sp->p208e_flag =
+				mib_m->fddiMACNotCopiedFlag ;
+			sp->p208e_not_copied =
+				mib_m->fddiMACNotCopied_Ct ;
+			sp->p208e_copied =
+				mib_m->fddiMACCopied_Ct ;
+			sp->p208e_not_copied_ratio =
+				mib_m->fddiMACNotCopiedRatio ;
+			sp_len = sizeof(struct smt_p_208e) ;
+			goto sp_done ;
+		}
+	case SMT_P208F :	/* neighbor change event */
+		{
+			struct smt_p_208f	*sp ;
+			sp = (struct smt_p_208f *) to ;
+			sp->p208f_multiple =
+				mib_m->fddiMACMultiple_N ;
+			sp->p208f_nacondition =
+				mib_m->fddiMACDuplicateAddressCond ;
+			sp->p208f_old_una =
+				mib_m->fddiMACOldUpstreamNbr ;
+			sp->p208f_new_una =
+				mib_m->fddiMACUpstreamNbr ;
+			sp->p208f_old_dna =
+				mib_m->fddiMACOldDownstreamNbr ;
+			sp->p208f_new_dna =
+				mib_m->fddiMACDownstreamNbr ;
+			sp->p208f_curren_path =
+				mib_m->fddiMACCurrentPath ;
+			sp->p208f_smt_address =
+				mib_m->fddiMACSMTAddress ;
+			sp_len = sizeof(struct smt_p_208f) ;
+			goto sp_done ;
+		}
+	case SMT_P2090 :
+		{
+			struct smt_p_2090	*sp ;
+			sp = (struct smt_p_2090 *) to ;
+			sp->p2090_multiple =
+				mib_m->fddiMACMultiple_P ;
+			sp->p2090_availablepaths =
+				mib_m->fddiMACAvailablePaths ;
+			sp->p2090_currentpath =
+				mib_m->fddiMACCurrentPath ;
+			sp->p2090_requestedpaths =
+				mib_m->fddiMACRequestedPaths ;
+			sp_len = sizeof(struct smt_p_2090) ;
+			goto sp_done ;
+		}
+	case SMT_P4050 :
+		{
+			struct smt_p_4050	*sp ;
+			sp = (struct smt_p_4050 *) to ;
+			sp->p4050_flag =
+				mib_p->fddiPORTLerFlag ;
+			sp->p4050_pad = 0 ;
+			sp->p4050_cutoff =
+				mib_p->fddiPORTLer_Cutoff ; ;
+			sp->p4050_alarm =
+				mib_p->fddiPORTLer_Alarm ; ;
+			sp->p4050_estimate =
+				mib_p->fddiPORTLer_Estimate ;
+			sp->p4050_reject_ct =
+				mib_p->fddiPORTLem_Reject_Ct ;
+			sp->p4050_ct =
+				mib_p->fddiPORTLem_Ct ;
+			sp_len = sizeof(struct smt_p_4050) ;
+			goto sp_done ;
+		}
+
+	case SMT_P4051 :
+		{
+			struct smt_p_4051	*sp ;
+			sp = (struct smt_p_4051 *) to ;
+			sp->p4051_multiple =
+				mib_p->fddiPORTMultiple_U ;
+			sp->p4051_porttype =
+				mib_p->fddiPORTMy_Type ;
+			sp->p4051_connectstate =
+				mib_p->fddiPORTConnectState ; ;
+			sp->p4051_pc_neighbor =
+				mib_p->fddiPORTNeighborType ;
+			sp->p4051_pc_withhold =
+				mib_p->fddiPORTPC_Withhold ;
+			sp_len = sizeof(struct smt_p_4051) ;
+			goto sp_done ;
+		}
+	case SMT_P4052 :
+		{
+			struct smt_p_4052	*sp ;
+			sp = (struct smt_p_4052 *) to ;
+			sp->p4052_flag =
+				mib_p->fddiPORTEB_Condition ;
+			sp->p4052_eberrorcount =
+				mib_p->fddiPORTEBError_Ct ;
+			sp_len = sizeof(struct smt_p_4052) ;
+			goto sp_done ;
+		}
+	case SMT_P4053 :
+		{
+			struct smt_p_4053	*sp ;
+			sp = (struct smt_p_4053 *) to ;
+			sp->p4053_multiple =
+				mib_p->fddiPORTMultiple_P ; ;
+			sp->p4053_availablepaths =
+				mib_p->fddiPORTAvailablePaths ;
+			sp->p4053_currentpath =
+				mib_p->fddiPORTCurrentPath ;
+			memcpy(	(char *) &sp->p4053_requestedpaths,
+				(char *) mib_p->fddiPORTRequestedPaths,4) ;
+			sp->p4053_mytype =
+				mib_p->fddiPORTMy_Type ;
+			sp->p4053_neighbortype =
+				mib_p->fddiPORTNeighborType ;
+			sp_len = sizeof(struct smt_p_4053) ;
+			goto sp_done ;
+		}
+	default :
+		break ;
+	}
+	/*
+	 * in table ?
+	 */
+	if (!pt) {
+		pcon->pc_err = (para & 0xff00) ? SMT_RDF_NOPARAM :
+						SMT_RDF_ILLEGAL ;
+		return ;
+	}
+	/*
+	 * check access rights
+	 */
+	switch (pt->p_access) {
+	case AC_G :
+	case AC_GR :
+		break ;
+	default :
+		pcon->pc_err = SMT_RDF_ILLEGAL ;
+		return ;
+	}
+	from = mib_addr + pt->p_offset ;
+	if (!swap)
+		swap = pt->p_swap ;		/* pointer to swap string */
+
+	/*
+	 * copy values
+	 */
+	while ((c = *swap++)) {
+		switch(c) {
+		case 'b' :
+		case 'w' :
+		case 'l' :
+			break ;
+		case 'S' :
+		case 'E' :
+		case 'R' :
+		case 'r' :
+			if (len < 4)
+				goto len_error ;
+			to[0] = 0 ;
+			to[1] = 0 ;
+#ifdef	LITTLE_ENDIAN
+			if (c == 'r') {
+				to[2] = *from++ ;
+				to[3] = *from++ ;
+			}
+			else {
+				to[3] = *from++ ;
+				to[2] = *from++ ;
+			}
+#else
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+#endif
+			to += 4 ;
+			len -= 4 ;
+			break ;
+		case 'I' :		/* for SET of port indexes */
+			if (len < 2)
+				goto len_error ;
+#ifdef	LITTLE_ENDIAN
+			to[1] = *from++ ;
+			to[0] = *from++ ;
+#else
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+#endif
+			to += 2 ;
+			len -= 2 ;
+			break ;
+		case 'F' :
+		case 'B' :
+			if (len < 4)
+				goto len_error ;
+			len -= 4 ;
+			to[0] = 0 ;
+			to[1] = 0 ;
+			to[2] = 0 ;
+			to[3] = *from++ ;
+			to += 4 ;
+			break ;
+		case 'C' :
+		case 'T' :
+		case 'L' :
+			if (len < 4)
+				goto len_error ;
+#ifdef	LITTLE_ENDIAN
+			to[3] = *from++ ;
+			to[2] = *from++ ;
+			to[1] = *from++ ;
+			to[0] = *from++ ;
+#else
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+#endif
+			len -= 4 ;
+			to += 4 ;
+			break ;
+		case '2' :		/* PortMacIndicated */
+			if (len < 4)
+				goto len_error ;
+			to[0] = 0 ;
+			to[1] = 0 ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+			len -= 4 ;
+			to += 4 ;
+			break ;
+		case '4' :
+			if (len < 4)
+				goto len_error ;
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+			len -= 4 ;
+			to += 4 ;
+			break ;
+		case 'A' :
+			if (len < 8)
+				goto len_error ;
+			to[0] = 0 ;
+			to[1] = 0 ;
+			memcpy((char *) to+2,(char *) from,6) ;
+			to += 8 ;
+			from += 8 ;
+			len -= 8 ;
+			break ;
+		case '8' :
+			if (len < 8)
+				goto len_error ;
+			memcpy((char *) to,(char *) from,8) ;
+			to += 8 ;
+			from += 8 ;
+			len -= 8 ;
+			break ;
+		case 'D' :
+			if (len < 32)
+				goto len_error ;
+			memcpy((char *) to,(char *) from,32) ;
+			to += 32 ;
+			from += 32 ;
+			len -= 32 ;
+			break ;
+		case 'P' :		/* timestamp is NOT swapped */
+			if (len < 8)
+				goto len_error ;
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+			to[4] = *from++ ;
+			to[5] = *from++ ;
+			to[6] = *from++ ;
+			to[7] = *from++ ;
+			to += 8 ;
+			len -= 8 ;
+			break ;
+		default :
+			SMT_PANIC(smc,SMT_E0119, SMT_E0119_MSG) ;
+			break ;
+		}
+	}
+
+done:
+	/*
+	 * make it even (in case of 'I' encoding)
+	 * note: len is DECREMENTED
+	 */
+	if (len & 3) {
+		to[0] = 0 ;
+		to[1] = 0 ;
+		to += 4 - (len & 3 ) ;
+		len = len & ~ 3 ;
+	}
+
+	/* set type and length */
+	pa->p_type = para ;
+	pa->p_len = plen - len - PARA_LEN ;
+	/* return values */
+	pcon->pc_p = (void *) to ;
+	pcon->pc_len = len ;
+	return ;
+
+sp_done:
+	len -= sp_len ;
+	to += sp_len ;
+	goto done ;
+
+len_error:
+	/* parameter does not fit in frame */
+	pcon->pc_err = SMT_RDF_TOOLONG ;
+	return ;
+
+wrong_error:
+	pcon->pc_err = SMT_RDF_LENGTH ;
+}
+
+/*
+ * set parameter
+ */
+int smt_set_para(smc,pa,index,local,set)
+struct s_smc *smc ;
+struct smt_para	*pa ;
+int index ;
+int local ;
+int set ;
+{
+#define IFSET(x)	if (set) (x)
+
+	const struct s_p_tab	*pt ;
+	int		len ;
+	char		*from ;
+	char		*to ;
+	const char	*swap ;
+	char		c ;
+	char		*mib_addr ;
+	struct fddi_mib	*mib ;
+	struct fddi_mib_m	*mib_m = 0 ;
+	struct fddi_mib_a	*mib_a = 0 ;
+	struct fddi_mib_p	*mib_p = 0 ;
+	int		mac ;
+	int		path ;
+	int		port ;
+	SK_LOC_DECL(u_char,byte_val) ;
+	SK_LOC_DECL(u_short,word_val) ;
+	SK_LOC_DECL(u_long,long_val) ;
+
+	mac = index - INDEX_MAC ;
+	path = index - INDEX_PATH ;
+	port = index - INDEX_PORT ;
+	len = pa->p_len ;
+	from = (char *) (pa + 1 ) ;
+
+	mib = &smc->mib ;
+	switch (pa->p_type & 0xf000) {
+	case 0x1000 :
+	default :
+		mib_addr = (char *) mib ;
+		break ;
+	case 0x2000 :
+		if (mac < 0 || mac >= NUMMACS) {
+			return(SMT_RDF_NOPARAM) ;
+		}
+		mib_m = &smc->mib.m[mac] ;
+		mib_addr = (char *) mib_m ;
+		from += 4 ;		/* skip index */
+		len -= 4 ;
+		break ;
+	case 0x3000 :
+		if (path < 0 || path >= NUMPATHS) {
+			return(SMT_RDF_NOPARAM) ;
+		}
+		mib_a = &smc->mib.a[path] ;
+		mib_addr = (char *) mib_a ;
+		from += 4 ;		/* skip index */
+		len -= 4 ;
+		break ;
+	case 0x4000 :
+		if (port < 0 || port >= smt_mib_phys(smc)) {
+			return(SMT_RDF_NOPARAM) ;
+		}
+		mib_p = &smc->mib.p[port_to_mib(smc,port)] ;
+		mib_addr = (char *) mib_p ;
+		from += 4 ;		/* skip index */
+		len -= 4 ;
+		break ;
+	}
+	switch (pa->p_type) {
+	case SMT_P10F0 :
+	case SMT_P10F1 :
+#ifdef	ESS
+	case SMT_P10F2 :
+	case SMT_P10F3 :
+	case SMT_P10F4 :
+	case SMT_P10F5 :
+	case SMT_P10F6 :
+	case SMT_P10F7 :
+#endif
+#ifdef	SBA
+	case SMT_P10F8 :
+	case SMT_P10F9 :
+#endif
+	case SMT_P20F1 :
+		if (!local) {
+			return(SMT_RDF_NOPARAM) ;
+		}
+		break ;
+	}
+	pt = smt_get_ptab(pa->p_type) ;
+	if (!pt) {
+		return( (pa->p_type & 0xff00) ? SMT_RDF_NOPARAM :
+						SMT_RDF_ILLEGAL ) ;
+	}
+	switch (pt->p_access) {
+	case AC_GR :
+	case AC_S :
+		break ;
+	default :
+		return(SMT_RDF_ILLEGAL) ;
+	}
+	to = mib_addr + pt->p_offset ;
+	swap = pt->p_swap ;		/* pointer to swap string */
+
+	while (swap && (c = *swap++)) {
+		switch(c) {
+		case 'b' :
+			to = (char *) &byte_val ;
+			break ;
+		case 'w' :
+			to = (char *) &word_val ;
+			break ;
+		case 'l' :
+			to = (char *) &long_val ;
+			break ;
+		case 'S' :
+		case 'E' :
+		case 'R' :
+		case 'r' :
+			if (len < 4) {
+				goto len_error ;
+			}
+			if (from[0] | from[1])
+				goto val_error ;
+#ifdef	LITTLE_ENDIAN
+			if (c == 'r') {
+				to[0] = from[2] ;
+				to[1] = from[3] ;
+			}
+			else {
+				to[1] = from[2] ;
+				to[0] = from[3] ;
+			}
+#else
+			to[0] = from[2] ;
+			to[1] = from[3] ;
+#endif
+			from += 4 ;
+			to += 2 ;
+			len -= 4 ;
+			break ;
+		case 'F' :
+		case 'B' :
+			if (len < 4) {
+				goto len_error ;
+			}
+			if (from[0] | from[1] | from[2])
+				goto val_error ;
+			to[0] = from[3] ;
+			len -= 4 ;
+			from += 4 ;
+			to += 4 ;
+			break ;
+		case 'C' :
+		case 'T' :
+		case 'L' :
+			if (len < 4) {
+				goto len_error ;
+			}
+#ifdef	LITTLE_ENDIAN
+			to[3] = *from++ ;
+			to[2] = *from++ ;
+			to[1] = *from++ ;
+			to[0] = *from++ ;
+#else
+			to[0] = *from++ ;
+			to[1] = *from++ ;
+			to[2] = *from++ ;
+			to[3] = *from++ ;
+#endif
+			len -= 4 ;
+			to += 4 ;
+			break ;
+		case 'A' :
+			if (len < 8)
+				goto len_error ;
+			if (set)
+				memcpy((char *) to,(char *) from+2,6) ;
+			to += 8 ;
+			from += 8 ;
+			len -= 8 ;
+			break ;
+		case '4' :
+			if (len < 4)
+				goto len_error ;
+			if (set)
+				memcpy((char *) to,(char *) from,4) ;
+			to += 4 ;
+			from += 4 ;
+			len -= 4 ;
+			break ;
+		case '8' :
+			if (len < 8)
+				goto len_error ;
+			if (set)
+				memcpy((char *) to,(char *) from,8) ;
+			to += 8 ;
+			from += 8 ;
+			len -= 8 ;
+			break ;
+		case 'D' :
+			if (len < 32)
+				goto len_error ;
+			if (set)
+				memcpy((char *) to,(char *) from,32) ;
+			to += 32 ;
+			from += 32 ;
+			len -= 32 ;
+			break ;
+		case 'P' :		/* timestamp is NOT swapped */
+			if (set) {
+				to[0] = *from++ ;
+				to[1] = *from++ ;
+				to[2] = *from++ ;
+				to[3] = *from++ ;
+				to[4] = *from++ ;
+				to[5] = *from++ ;
+				to[6] = *from++ ;
+				to[7] = *from++ ;
+			}
+			to += 8 ;
+			len -= 8 ;
+			break ;
+		default :
+			SMT_PANIC(smc,SMT_E0120, SMT_E0120_MSG) ;
+			return(SMT_RDF_ILLEGAL) ;
+		}
+	}
+	/*
+	 * actions and internal updates
+	 */
+	switch (pa->p_type) {
+	case SMT_P101A:			/* fddiSMTConfigPolicy */
+		if (word_val & ~1)
+			goto val_error ;
+		IFSET(mib->fddiSMTConfigPolicy = word_val) ;
+		break ;
+	case SMT_P101B :		/* fddiSMTConnectionPolicy */
+		if (!(word_val & POLICY_MM))
+			goto val_error ;
+		IFSET(mib->fddiSMTConnectionPolicy = word_val) ;
+		break ;
+	case SMT_P101D : 		/* fddiSMTTT_Notify */
+		if (word_val < 2 || word_val > 30)
+			goto val_error ;
+		IFSET(mib->fddiSMTTT_Notify = word_val) ;
+		break ;
+	case SMT_P101E :		/* fddiSMTStatRptPolicy */
+		if (byte_val & ~1)
+			goto val_error ;
+		IFSET(mib->fddiSMTStatRptPolicy = byte_val) ;
+		break ;
+	case SMT_P101F :		/* fddiSMTTrace_MaxExpiration */
+		/*
+		 * note: lower limit trace_max = 6.001773... s
+		 * NO upper limit
+		 */
+		if (long_val < (long)0x478bf51L)
+			goto val_error ;
+		IFSET(mib->fddiSMTTrace_MaxExpiration = long_val) ;
+		break ;
+#ifdef	ESS
+	case SMT_P10F2 :		/* fddiESSPayload */
+		if (long_val > 1562)
+			goto val_error ;
+		if (set && smc->mib.fddiESSPayload != long_val) {
+			smc->ess.raf_act_timer_poll = TRUE ;
+			smc->mib.fddiESSPayload = long_val ;
+		}
+		break ;
+	case SMT_P10F3 :		/* fddiESSOverhead */
+		if (long_val < 50 || long_val > 5000)
+			goto val_error ;
+		if (set && smc->mib.fddiESSPayload &&
+			smc->mib.fddiESSOverhead != long_val) {
+			smc->ess.raf_act_timer_poll = TRUE ;
+			smc->mib.fddiESSOverhead = long_val ;
+		}
+		break ;
+	case SMT_P10F4 :		/* fddiESSMaxTNeg */
+		if (long_val > -MS2BCLK(5) || long_val < -MS2BCLK(165))
+			goto val_error ;
+		IFSET(mib->fddiESSMaxTNeg = long_val) ;
+		break ;
+	case SMT_P10F5 :		/* fddiESSMinSegmentSize */
+		if (long_val < 1 || long_val > 4478)
+			goto val_error ;
+		IFSET(mib->fddiESSMinSegmentSize = long_val) ;
+		break ;
+	case SMT_P10F6 :		/* fddiESSCategory */
+		if ((long_val & 0xffff) != 1)
+			goto val_error ;
+		IFSET(mib->fddiESSCategory = long_val) ;
+		break ;
+	case SMT_P10F7 :		/* fddiESSSyncTxMode */
+		if (word_val > 1)
+			goto val_error ;
+		IFSET(mib->fddiESSSynchTxMode = word_val) ;
+		break ;
+#endif
+#ifdef	SBA
+	case SMT_P10F8 :		/* fddiSBACommand */
+		if (byte_val != SB_STOP && byte_val != SB_START)
+			goto val_error ;
+		IFSET(mib->fddiSBACommand = byte_val) ;
+		break ;
+	case SMT_P10F9 :		/* fddiSBAAvailable */
+		if (byte_val > 100)
+			goto val_error ;
+		IFSET(mib->fddiSBAAvailable = byte_val) ;
+		break ;
+#endif
+	case SMT_P2020 :		/* fddiMACRequestedPaths */
+		if ((word_val & (MIB_P_PATH_PRIM_PREFER |
+			MIB_P_PATH_PRIM_ALTER)) == 0 )
+			goto val_error ;
+		IFSET(mib_m->fddiMACRequestedPaths = word_val) ;
+		break ;
+	case SMT_P205F :		/* fddiMACFrameErrorThreshold */
+		/* 0 .. ffff acceptable */
+		IFSET(mib_m->fddiMACFrameErrorThreshold = word_val) ;
+		break ;
+	case SMT_P2067 :		/* fddiMACNotCopiedThreshold */
+		/* 0 .. ffff acceptable */
+		IFSET(mib_m->fddiMACNotCopiedThreshold = word_val) ;
+		break ;
+	case SMT_P2076:			/* fddiMACMA_UnitdataEnable */
+		if (byte_val & ~1)
+			goto val_error ;
+		if (set) {
+			mib_m->fddiMACMA_UnitdataEnable = byte_val ;
+			queue_event(smc,EVENT_RMT,RM_ENABLE_FLAG) ;
+		}
+		break ;
+	case SMT_P20F1 :		/* fddiMACT_Min */
+		IFSET(mib_m->fddiMACT_Min = long_val) ;
+		break ;
+	case SMT_P320F :
+		if (long_val > 1562)
+			goto val_error ;
+		IFSET(mib_a->fddiPATHSbaPayload = long_val) ;
+#ifdef	ESS
+		if (set)
+			ess_para_change(smc) ;
+#endif
+		break ;
+	case SMT_P3210 :
+		if (long_val > 5000)
+			goto val_error ;
+		
+		if (long_val != 0 && mib_a->fddiPATHSbaPayload == 0)
+			goto val_error ;
+
+		IFSET(mib_a->fddiPATHSbaOverhead = long_val) ;
+#ifdef	ESS
+		if (set)
+			ess_para_change(smc) ;
+#endif
+		break ;
+	case SMT_P3213:			/* fddiPATHT_Rmode */
+		/* no limit :
+		 * 0 .. 343.597 => 0 .. 2e32 * 80nS
+		 */
+		if (set) {
+			mib_a->fddiPATHT_Rmode = long_val ;
+			rtm_set_timer(smc) ;
+		}
+		break ;
+	case SMT_P3214 :		/* fddiPATHSbaAvailable */
+		if (long_val > 0x00BEBC20L)
+			goto val_error ;
+#ifdef SBA 
+		if (set && mib->fddiSBACommand == SB_STOP)
+			goto val_error ;
+#endif
+		IFSET(mib_a->fddiPATHSbaAvailable = long_val) ;
+		break ;
+	case SMT_P3215 :		/* fddiPATHTVXLowerBound */
+		IFSET(mib_a->fddiPATHTVXLowerBound = long_val) ;
+		goto change_mac_para ;
+	case SMT_P3216 :		/* fddiPATHT_MaxLowerBound */
+		IFSET(mib_a->fddiPATHT_MaxLowerBound = long_val) ;
+		goto change_mac_para ;
+	case SMT_P3217 :		/* fddiPATHMaxT_Req */
+		IFSET(mib_a->fddiPATHMaxT_Req = long_val) ;
+
+change_mac_para:
+		if (set && smt_set_mac_opvalues(smc)) {
+			RS_SET(smc,RS_EVENT) ;
+			smc->sm.please_reconnect = 1 ;
+			queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+		}
+		break ;
+	case SMT_P400E :		/* fddiPORTConnectionPolicies */
+		if (byte_val > 1)
+			goto val_error ;
+		IFSET(mib_p->fddiPORTConnectionPolicies = byte_val) ;
+		break ;
+	case SMT_P4011 :		/* fddiPORTRequestedPaths */
+		/* all 3*8 bits allowed */
+		IFSET(memcpy((char *)mib_p->fddiPORTRequestedPaths,
+			(char *)&long_val,4)) ;
+		break ;
+	case SMT_P401F:			/* fddiPORTMaint_LS */
+		if (word_val > 4)
+			goto val_error ;
+		IFSET(mib_p->fddiPORTMaint_LS = word_val) ;
+		break ;
+	case SMT_P403A :		/* fddiPORTLer_Cutoff */
+		if (byte_val < 4 || byte_val > 15)
+			goto val_error ;
+		IFSET(mib_p->fddiPORTLer_Cutoff = byte_val) ;
+		break ;
+	case SMT_P403B :		/* fddiPORTLer_Alarm */
+		if (byte_val < 4 || byte_val > 15)
+			goto val_error ;
+		IFSET(mib_p->fddiPORTLer_Alarm = byte_val) ;
+		break ;
+
+	/*
+	 * Actions
+	 */
+	case SMT_P103C :		/* fddiSMTStationAction */
+		if (smt_action(smc,SMT_STATION_ACTION, (int) word_val, 0))
+			goto val_error ;
+		break ;
+	case SMT_P4046:			/* fddiPORTAction */
+		if (smt_action(smc,SMT_PORT_ACTION, (int) word_val,
+			port_to_mib(smc,port)))
+			goto val_error ;
+		break ;
+	default :
+		break ;
+	}
+	return(0) ;
+
+val_error:
+	/* parameter value in frame is out of range */
+	return(SMT_RDF_RANGE) ;
+
+len_error:
+	/* parameter value in frame is too short */
+	return(SMT_RDF_LENGTH) ;
+
+#if	0
+no_author_error:
+	/* parameter not setable, because the SBA is not active
+	 * Please note: we give the return code 'not authorizeed
+	 *  because SBA denied is not a valid return code in the
+	 * PMF protocol.
+	 */
+	return(SMT_RDF_AUTHOR) ;
+#endif
+}
+
+static const struct s_p_tab *smt_get_ptab(para)
+u_short para ;
+{
+	const struct s_p_tab	*pt ;
+	for (pt = p_tab ; pt->p_num && pt->p_num != para ; pt++)
+		;
+	return(pt->p_num ? pt : 0) ;
+}
+
+static int smt_mib_phys(smc)
+struct s_smc *smc ;
+{
+#ifdef	CONCENTRATOR
+	SK_UNUSED(smc) ;
+
+	return(NUMPHYS) ;
+#else
+	if (smc->s.sas == SMT_SAS)
+		return(1) ;
+	return(NUMPHYS) ;
+#endif
+}
+
+int port_to_mib(smc,p)
+struct s_smc *smc ;
+int p ;
+{
+#ifdef	CONCENTRATOR
+	SK_UNUSED(smc) ;
+
+	return(p) ;
+#else
+	if (smc->s.sas == SMT_SAS)
+		return(PS) ;
+	return(p) ;
+#endif
+}
+
+
+#ifdef	DEBUG
+#ifndef	BOOT
+void dump_smt(smc,sm,text)
+struct s_smc *smc ;
+struct smt_header *sm ;
+char *text ;
+{
+	int	len ;
+	struct smt_para	*pa ;
+	char	*c ;
+	int	n ;
+	int	nn ;
+#ifdef	LITTLE_ENDIAN
+	int	smtlen ;
+#endif
+
+	SK_UNUSED(smc) ;
+
+#ifdef	DEBUG_BRD
+	if (smc->debug.d_smtf < 2)
+#else
+	if (debug.d_smtf < 2)
+#endif
+		return ;
+#ifdef	LITTLE_ENDIAN
+	smtlen = sm->smt_len + sizeof(struct smt_header) ;
+#endif
+	printf("SMT Frame [%s]:\nDA  ",text) ;
+	dump_hex((char *) &sm->smt_dest,6) ;
+	printf("\tSA ") ;
+	dump_hex((char *) &sm->smt_source,6) ;
+	printf(" Class %x Type %x Version %x\n",
+		sm->smt_class,sm->smt_type,sm->smt_version)  ;
+	printf("TID %lx\t\tSID ",sm->smt_tid) ;
+	dump_hex((char *) &sm->smt_sid,8) ;
+	printf(" LEN %x\n",sm->smt_len) ;
+
+	len = sm->smt_len ;
+	pa = (struct smt_para *) (sm + 1) ;
+	while (len > 0 ) {
+		int	plen ;
+#ifdef UNIX
+		printf("TYPE %x LEN %x VALUE\t",pa->p_type,pa->p_len) ;
+#else
+		printf("TYPE %04x LEN %2x VALUE\t",pa->p_type,pa->p_len) ;
+#endif
+		n = pa->p_len ;
+		if ( (n < 0 ) || (n > (int)(len - PARA_LEN))) {
+			n = len - PARA_LEN ;
+			printf(" BAD LENGTH\n") ;
+			break ;
+		}
+#ifdef	LITTLE_ENDIAN
+		smt_swap_para(sm,smtlen,0) ;
+#endif
+		if (n < 24) {
+			dump_hex((char *)(pa+1),(int) n) ;
+			printf("\n") ;
+		}
+		else {
+			int	first = 0 ;
+			c = (char *)(pa+1) ;
+			dump_hex(c,16) ;
+			printf("\n") ;
+			n -= 16 ;
+			c += 16 ;
+			while (n > 0) {
+				nn = (n > 16) ? 16 : n ;
+				if (n > 64) {
+					if (first == 0)
+						printf("\t\t\t...\n") ;
+					first = 1 ;
+				}
+				else {
+					printf("\t\t\t") ;
+					dump_hex(c,nn) ;
+					printf("\n") ;
+				}
+				n -= nn ;
+				c += 16 ;
+			}
+		}
+#ifdef	LITTLE_ENDIAN
+		smt_swap_para(sm,smtlen,1) ;
+#endif
+		plen = (pa->p_len + PARA_LEN + 3) & ~3 ;
+		len -= plen ;
+		pa = (struct smt_para *)((char *)pa + plen) ;
+	}
+	printf("-------------------------------------------------\n\n") ;
+}
+
+void dump_hex(p,len)
+char *p ;
+int len ;
+{
+	int	n = 0 ;
+	while (len--) {
+		n++ ;
+#ifdef UNIX
+		printf("%x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ;
+#else
+		printf("%02x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ;
+#endif
+	}
+}
+#endif	/* no BOOT */
+#endif	/* DEBUG */
+
+
+#endif	/* no SLIM_SMT */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/queue.c linux.18p8/drivers/net/skfp/queue.c
--- linux.vanilla/drivers/net/skfp/queue.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/queue.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT Event Queue Management
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)queue.c	2.9 97/08/04 (C) SK " ;
+#endif
+
+#define PRINTF(a,b,c)
+
+/*
+ * init event queue management
+ */
+void ev_init(smc)
+struct s_smc *smc ;
+{
+	smc->q.ev_put = smc->q.ev_get = smc->q.ev_queue ;
+}
+
+/*
+ * add event to queue
+ */
+void queue_event(smc,class,event)
+struct s_smc *smc ;
+int class ;
+int event ;
+{
+	PRINTF("queue class %d event %d\n",class,event) ;
+	smc->q.ev_put->class = class ;
+	smc->q.ev_put->event = event ;
+	if (++smc->q.ev_put == &smc->q.ev_queue[MAX_EVENT])
+		smc->q.ev_put = smc->q.ev_queue ;
+
+	if (smc->q.ev_put == smc->q.ev_get) {
+		SMT_ERR_LOG(smc,SMT_E0137, SMT_E0137_MSG) ;
+	}
+}
+
+/*
+ * timer_event is called from HW timer package.
+ */
+void timer_event(smc,token)
+struct s_smc *smc ;
+u_long token ;
+{
+	PRINTF("timer event class %d token %d\n",
+		EV_T_CLASS(token),
+		EV_T_EVENT(token)) ;
+	queue_event(smc,EV_T_CLASS(token),EV_T_EVENT(token));
+}
+
+/*
+ * event dispatcher
+ *	while event queue is not empty
+ *		get event from queue
+ *		send command to state machine
+ *	end
+ */
+void ev_dispatcher(smc)
+struct s_smc *smc ;
+{
+	struct event_queue *ev ;	/* pointer into queue */
+	int		class ;
+
+	ev = smc->q.ev_get ;
+	PRINTF("dispatch get %x put %x\n",ev,smc->q.ev_put) ;
+	while (ev != smc->q.ev_put) {
+		PRINTF("dispatch class %d event %d\n",ev->class,ev->event) ;
+		switch(class = ev->class) {
+		case EVENT_ECM :		/* Entity Corordination  Man. */
+			ecm(smc,(int)ev->event) ;
+			break ;
+		case EVENT_CFM :		/* Configuration Man. */
+			cfm(smc,(int)ev->event) ;
+			break ;
+		case EVENT_RMT :		/* Ring Man. */
+			rmt(smc,(int)ev->event) ;
+			break ;
+		case EVENT_SMT :
+			smt_event(smc,(int)ev->event) ;
+			break ;
+#ifdef	CONCENTRATOR
+		case 99 :
+			timer_test_event(smc,(int)ev->event) ;
+			break ;
+#endif
+		case EVENT_PCMA :		/* PHY A */
+		case EVENT_PCMB :		/* PHY B */
+		default :
+			if (class >= EVENT_PCMA &&
+			    class < EVENT_PCMA + NUMPHYS) {
+				pcm(smc,class - EVENT_PCMA,(int)ev->event) ;
+				break ;
+			}
+			SMT_PANIC(smc,SMT_E0121, SMT_E0121_MSG) ;
+			return ;
+		}
+
+		if (++ev == &smc->q.ev_queue[MAX_EVENT])
+			ev = smc->q.ev_queue ;
+
+		/* Renew get: it is used in queue_events to detect overruns */
+		smc->q.ev_get = ev;
+	}
+}
+
+/*
+ * smt_online connects to or disconnects from the ring
+ * MUST be called to initiate connection establishment
+ *
+ *	on	0	disconnect
+ *	on	1	connect
+ */
+u_short smt_online(smc,on)
+struct s_smc *smc ;
+int on ;
+{
+	queue_event(smc,EVENT_ECM,on ? EC_CONNECT : EC_DISCONNECT) ;
+	ev_dispatcher(smc) ;
+	return(smc->mib.fddiSMTCF_State) ;
+}
+
+/*
+ * set SMT flag to value
+ *	flag		flag name
+ *	value		flag value
+ * dump current flag setting
+ */
+#ifdef	CONCENTRATOR
+void do_smt_flag(smc,flag,value)
+struct s_smc *smc ;
+char *flag ;
+int value ;
+{
+#ifdef	DEBUG
+	struct smt_debug	*deb;
+
+	SK_UNUSED(smc) ;
+
+#ifdef	DEBUG_BRD
+	deb = &smc->debug;
+#else
+	deb = &debug;
+#endif
+	if (!strcmp(flag,"smt"))
+		deb->d_smt = value ;
+	else if (!strcmp(flag,"smtf"))
+		deb->d_smtf = value ;
+	else if (!strcmp(flag,"pcm"))
+		deb->d_pcm = value ;
+	else if (!strcmp(flag,"rmt"))
+		deb->d_rmt = value ;
+	else if (!strcmp(flag,"cfm"))
+		deb->d_cfm = value ;
+	else if (!strcmp(flag,"ecm"))
+		deb->d_ecm = value ;
+	printf("smt	%d\n",deb->d_smt) ;
+	printf("smtf	%d\n",deb->d_smtf) ;
+	printf("pcm	%d\n",deb->d_pcm) ;
+	printf("rmt	%d\n",deb->d_rmt) ;
+	printf("cfm	%d\n",deb->d_cfm) ;
+	printf("ecm	%d\n",deb->d_ecm) ;
+#endif	/* DEBUG */
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/rmt.c linux.18p8/drivers/net/skfp/rmt.c
--- linux.vanilla/drivers/net/skfp/rmt.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/rmt.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,674 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT RMT
+	Ring Management
+*/
+
+/*
+ * Hardware independant state machine implemantation
+ * The following external SMT functions are referenced :
+ *
+ * 		queue_event()
+ * 		smt_timer_start()
+ * 		smt_timer_stop()
+ *
+ * 	The following external HW dependant functions are referenced :
+ *		sm_ma_control()
+ *		sm_mac_check_beacon_claim()
+ *
+ * 	The following HW dependant events are required :
+ *		RM_RING_OP
+ *		RM_RING_NON_OP
+ *		RM_MY_BEACON
+ *		RM_OTHER_BEACON
+ *		RM_MY_CLAIM
+ *		RM_TRT_EXP
+ *		RM_VALID_CLAIM
+ *
+ */
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)rmt.c	2.13 99/07/02 (C) SK " ;
+#endif
+
+/*
+ * FSM Macros
+ */
+#define AFLAG	0x10
+#define GO_STATE(x)	(smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)
+#define ACTIONS_DONE()	(smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)
+#define ACTIONS(x)	(x|AFLAG)
+
+#define RM0_ISOLATED	0
+#define RM1_NON_OP	1		/* not operational */
+#define RM2_RING_OP	2		/* ring operational */
+#define RM3_DETECT	3		/* detect dupl addresses */
+#define RM4_NON_OP_DUP	4		/* dupl. addr detected */
+#define RM5_RING_OP_DUP	5		/* ring oper. with dupl. addr */
+#define RM6_DIRECTED	6		/* sending directed beacons */
+#define RM7_TRACE	7		/* trace initiated */
+
+#ifdef	DEBUG
+/*
+ * symbolic state names
+ */
+static const char * const rmt_states[] = {
+	"RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",
+	"RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",
+	"RM7_TRACE"
+} ;
+
+/*
+ * symbolic event names
+ */
+static const char * const rmt_events[] = {
+	"NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",
+	"RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",
+	"RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",
+	"RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",
+	"RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",
+	"RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"
+} ;
+#endif
+
+/*
+ * Globals
+ * in struct s_rmt
+ */
+
+
+/*
+ * function declarations
+ */
+static void rmt_fsm() ;
+static void start_rmt_timer0() ;
+static void start_rmt_timer1() ;
+static void start_rmt_timer2() ;
+static void stop_rmt_timer0() ;
+static void stop_rmt_timer1() ;
+static void stop_rmt_timer2() ;
+static void rmt_dup_actions() ;
+static void rmt_reinsert_actions() ;
+static void rmt_leave_actions() ;
+static void rmt_new_dup_actions() ;
+
+#ifndef SUPERNET_3
+extern void restart_trt_for_dbcn() ;
+#endif /*SUPERNET_3*/
+
+/*
+	init RMT state machine
+	clear all RMT vars and flags
+*/
+void rmt_init(smc)
+struct s_smc *smc ;
+{
+	smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;
+	smc->r.dup_addr_test = DA_NONE ;
+	smc->r.da_flag = 0 ;
+	smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+	smc->r.sm_ma_avail = FALSE ;
+	smc->r.loop_avail = 0 ;
+	smc->r.bn_flag = 0 ;
+	smc->r.jm_flag = 0 ;
+	smc->r.no_flag = TRUE ;
+}
+
+/*
+	RMT state machine
+	called by dispatcher
+
+	do
+		display state change
+		process event
+	until SM is stable
+*/
+void rmt(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+	int	state ;
+
+	do {
+		DB_RMT("RMT : state %s%s",
+			(smc->mib.m[MAC0].fddiMACRMTState & AFLAG) ? "ACTIONS " : "",
+			rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG]) ;
+		DB_RMT(" event %s\n",rmt_events[event],0) ;
+		state = smc->mib.m[MAC0].fddiMACRMTState ;
+		rmt_fsm(smc,event) ;
+		event = 0 ;
+	} while (state != smc->mib.m[MAC0].fddiMACRMTState) ;
+	rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;
+}
+
+/*
+	process RMT event
+*/
+static void rmt_fsm(smc,cmd)
+struct s_smc *smc ;
+int cmd ;
+{
+	/*
+	 * RM00-RM70 : from all states
+	 */
+	if (!smc->r.rm_join && !smc->r.rm_loop &&
+		smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&
+		smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {
+		RS_SET(smc,RS_NORINGOP) ;
+		rmt_indication(smc,0) ;
+		GO_STATE(RM0_ISOLATED) ;
+		return ;
+	}
+
+	switch(smc->mib.m[MAC0].fddiMACRMTState) {
+	case ACTIONS(RM0_ISOLATED) :
+		stop_rmt_timer0(smc) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+
+		/*
+		 * Disable MAC.
+		 */
+		sm_ma_control(smc,MA_OFFLINE) ;
+		smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+		smc->r.loop_avail = FALSE ;
+		smc->r.sm_ma_avail = FALSE ;
+		smc->r.no_flag = TRUE ;
+		DB_RMTN(1,"RMT : ISOLATED\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM0_ISOLATED :
+		/*RM01*/
+		if (smc->r.rm_join || smc->r.rm_loop) {
+			/*
+			 * According to the standard the MAC must be reset
+			 * here. The FORMAC will be initialized and Claim
+			 * and Beacon Frames will be uploaded to the MAC.
+			 * So any change of Treq will take effect NOW.
+			 */
+			sm_ma_control(smc,MA_RESET) ;
+			GO_STATE(RM1_NON_OP) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM1_NON_OP) :
+		start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+		sm_ma_control(smc,MA_BEACON) ;
+		DB_RMTN(1,"RMT : RING DOWN\n",0,0) ;
+		RS_SET(smc,RS_NORINGOP) ;
+		smc->r.sm_ma_avail = FALSE ;
+		rmt_indication(smc,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM1_NON_OP :
+		/*RM12*/
+		if (cmd == RM_RING_OP) {
+			RS_SET(smc,RS_RINGOPCHANGE) ;
+			GO_STATE(RM2_RING_OP) ;
+			break ;
+		}
+		/*RM13*/
+		else if (cmd == RM_TIMEOUT_NON_OP) {
+			smc->r.bn_flag = FALSE ;
+			smc->r.no_flag = TRUE ;
+			GO_STATE(RM3_DETECT) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM2_RING_OP) :
+		stop_rmt_timer0(smc) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+		smc->r.no_flag = FALSE ;
+		if (smc->r.rm_loop)
+			smc->r.loop_avail = TRUE ;
+		if (smc->r.rm_join) {
+			smc->r.sm_ma_avail = TRUE ;
+			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
+				else
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+		}
+		DB_RMTN(1,"RMT : RING UP\n",0,0) ;
+		RS_CLEAR(smc,RS_NORINGOP) ;
+		RS_SET(smc,RS_RINGOPCHANGE) ;
+		rmt_indication(smc,1) ;
+		smt_stat_counter(smc,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM2_RING_OP :
+		/*RM21*/
+		if (cmd == RM_RING_NON_OP) {
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+			smc->r.loop_avail = FALSE ;
+			RS_SET(smc,RS_RINGOPCHANGE) ;
+			GO_STATE(RM1_NON_OP) ;
+			break ;
+		}
+		/*RM22a*/
+		else if (cmd == RM_ENABLE_FLAG) {
+			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
+				else
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+		}
+		/*RM25*/
+		else if (smc->r.dup_addr_test == DA_FAILED) {
+			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
+			smc->r.loop_avail = FALSE ;
+			smc->r.da_flag = TRUE ;
+			GO_STATE(RM5_RING_OP_DUP) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM3_DETECT) :
+		start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;
+		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
+		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
+		sm_mac_check_beacon_claim(smc) ;
+		DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM3_DETECT :
+		if (cmd == RM_TIMEOUT_POLL) {
+			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
+			sm_mac_check_beacon_claim(smc) ;
+			break ;
+		}
+		if (cmd == RM_TIMEOUT_D_MAX) {
+			smc->r.timer0_exp = TRUE ;
+		}
+		/*
+		 *jd(22-Feb-1999)
+		 * We need a time ">= 2*mac_d_max" since we had finished
+		 * Claim or Beacon state. So we will restart timer0 at
+		 * every state change.
+		 */
+		if (cmd == RM_TX_STATE_CHANGE) {
+			start_rmt_timer0(smc,
+					 smc->s.mac_d_max*2,
+					 RM_TIMEOUT_D_MAX) ;
+		}
+		/*RM32*/
+		if (cmd == RM_RING_OP) {
+			GO_STATE(RM2_RING_OP) ;
+			break ;
+		}
+		/*RM33a*/
+		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)
+			&& smc->r.bn_flag) {
+			smc->r.bn_flag = FALSE ;
+		}
+		/*RM33b*/
+		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
+			int	tx ;
+			/*
+			 * set bn_flag only if in state T4 or T5:
+			 * only if we're the beaconer should we start the
+			 * trace !
+			 */
+			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
+			DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0);
+				smc->r.bn_flag = TRUE ;
+				/*
+				 * If one of the upstream stations beaconed
+				 * and the link to the upstream neighbor is
+				 * lost we need to restart the stuck timer to
+				 * check the "stuck beacon" condition.
+				 */
+				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
+					RM_TIMEOUT_T_STUCK) ;
+			}
+			/*
+			 * We do NOT need to clear smc->r.bn_flag in case of
+			 * not being in state T4 or T5, because the flag
+			 * must be cleared in order to get in this condition.
+			 */
+
+			DB_RMTN(2,
+			"RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
+			tx,smc->r.bn_flag) ;
+		}
+		/*RM34a*/
+		else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {
+			rmt_new_dup_actions(smc) ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		/*RM34b*/
+		else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
+			rmt_new_dup_actions(smc) ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		/*RM34c*/
+		else if (cmd == RM_VALID_CLAIM) {
+			rmt_new_dup_actions(smc) ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		/*RM36*/
+		else if (cmd == RM_TIMEOUT_T_STUCK &&
+			smc->r.rm_join && smc->r.bn_flag) {
+			GO_STATE(RM6_DIRECTED) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM4_NON_OP_DUP) :
+		start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);
+		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
+		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
+		sm_mac_check_beacon_claim(smc) ;
+		DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM4_NON_OP_DUP :
+		if (cmd == RM_TIMEOUT_POLL) {
+			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
+			sm_mac_check_beacon_claim(smc) ;
+			break ;
+		}
+		/*RM41*/
+		if (!smc->r.da_flag) {
+			GO_STATE(RM1_NON_OP) ;
+			break ;
+		}
+		/*RM44a*/
+		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
+			smc->r.bn_flag) {
+			smc->r.bn_flag = FALSE ;
+		}
+		/*RM44b*/
+		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
+			int	tx ;
+			/*
+			 * set bn_flag only if in state T4 or T5:
+			 * only if we're the beaconer should we start the
+			 * trace !
+			 */
+			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
+			DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0);
+				smc->r.bn_flag = TRUE ;
+				/*
+				 * If one of the upstream stations beaconed
+				 * and the link to the upstream neighbor is
+				 * lost we need to restart the stuck timer to
+				 * check the "stuck beacon" condition.
+				 */
+				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
+					RM_TIMEOUT_T_STUCK) ;
+			}
+			/*
+			 * We do NOT need to clear smc->r.bn_flag in case of
+			 * not being in state T4 or T5, because the flag
+			 * must be cleared in order to get in this condition.
+			 */
+
+			DB_RMTN(2,
+			"RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n",
+			tx,smc->r.bn_flag) ;
+		}
+		/*RM44c*/
+		else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {
+			rmt_dup_actions(smc) ;
+		}
+		/*RM45*/
+		else if (cmd == RM_RING_OP) {
+			smc->r.no_flag = FALSE ;
+			GO_STATE(RM5_RING_OP_DUP) ;
+			break ;
+		}
+		/*RM46*/
+		else if (cmd == RM_TIMEOUT_T_STUCK &&
+			smc->r.rm_join && smc->r.bn_flag) {
+			GO_STATE(RM6_DIRECTED) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM5_RING_OP_DUP) :
+		stop_rmt_timer0(smc) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+		DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ;
+		ACTIONS_DONE() ;
+		break;
+	case RM5_RING_OP_DUP :
+		/*RM52*/
+		if (smc->r.dup_addr_test == DA_PASSED) {
+			smc->r.da_flag = FALSE ;
+			GO_STATE(RM2_RING_OP) ;
+			break ;
+		}
+		/*RM54*/
+		else if (cmd == RM_RING_NON_OP) {
+			smc->r.jm_flag = FALSE ;
+			smc->r.bn_flag = FALSE ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM6_DIRECTED) :
+		start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;
+		stop_rmt_timer1(smc) ;
+		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
+		sm_ma_control(smc,MA_DIRECTED) ;
+		RS_SET(smc,RS_BEACON) ;
+		DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM6_DIRECTED :
+		/*RM63*/
+		if (cmd == RM_TIMEOUT_POLL) {
+			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
+			sm_mac_check_beacon_claim(smc) ;
+#ifndef SUPERNET_3
+			/* Because of problems with the Supernet II chip set
+			 * sending of Directed Beacon will stop after 165ms
+			 * therefore restart_trt_for_dbcn(smc) will be called
+			 * to prevent this.
+			 */
+			restart_trt_for_dbcn(smc) ;
+#endif /*SUPERNET_3*/
+			break ;
+		}
+		if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
+			!smc->r.da_flag) {
+			smc->r.bn_flag = FALSE ;
+			GO_STATE(RM3_DETECT) ;
+			break ;
+		}
+		/*RM64*/
+		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
+			smc->r.da_flag) {
+			smc->r.bn_flag = FALSE ;
+			GO_STATE(RM4_NON_OP_DUP) ;
+			break ;
+		}
+		/*RM67*/
+		else if (cmd == RM_TIMEOUT_T_DIRECT) {
+			GO_STATE(RM7_TRACE) ;
+			break ;
+		}
+		break ;
+	case ACTIONS(RM7_TRACE) :
+		stop_rmt_timer0(smc) ;
+		stop_rmt_timer1(smc) ;
+		stop_rmt_timer2(smc) ;
+		smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;
+		queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
+		DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ;
+		ACTIONS_DONE() ;
+		break ;
+	case RM7_TRACE :
+		break ;
+	default:
+		SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;
+		break;
+	}
+}
+
+/*
+ * (jd) RMT duplicate address actions
+ * leave the ring or reinsert just as configured
+ */
+static void rmt_dup_actions(smc)
+struct s_smc *smc ;
+{
+	if (smc->r.jm_flag) {
+	}
+	else {
+		if (smc->s.rmt_dup_mac_behavior) {
+			SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
+                        rmt_reinsert_actions(smc) ;
+		}
+		else {
+			SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
+			rmt_leave_actions(smc) ;
+		}
+	}
+}
+
+/*
+ * Reconnect to the Ring
+ */
+static void rmt_reinsert_actions(smc)
+struct s_smc *smc ;
+{
+	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+	queue_event(smc,EVENT_ECM,EC_CONNECT) ;
+}
+
+/*
+ * duplicate address detected
+ */
+static void rmt_new_dup_actions(smc)
+struct s_smc *smc ;
+{
+	smc->r.da_flag = TRUE ;
+	smc->r.bn_flag = FALSE ;
+	smc->r.jm_flag = FALSE ;
+	/*
+	 * we have three options : change address, jam or leave
+	 * we leave the ring as default 
+	 * Optionally it's possible to reinsert after leaving the Ring
+	 * but this will not conform with SMT Spec.
+	 */
+	if (smc->s.rmt_dup_mac_behavior) {
+		SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
+		rmt_reinsert_actions(smc) ;
+	}
+	else {
+		SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
+		rmt_leave_actions(smc) ;
+	}
+}
+
+
+/*
+ * leave the ring
+ */
+static void rmt_leave_actions(smc)
+struct s_smc *smc ;
+{
+	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+	/*
+	 * Note: Do NOT try again later. (with please reconnect)
+	 * The station must be left from the ring!
+	 */
+}
+
+/*
+ * SMT timer interface
+ *	start RMT timer 0
+ */
+static void start_rmt_timer0(smc,value,event)
+struct s_smc *smc ;
+u_long value ;
+int event ;
+{
+	smc->r.timer0_exp = FALSE ;		/* clear timer event flag */
+	smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));
+}
+
+/*
+ * SMT timer interface
+ *	start RMT timer 1
+ */
+static void start_rmt_timer1(smc,value,event)
+struct s_smc *smc ;
+u_long value ;
+int event ;
+{
+	smc->r.timer1_exp = FALSE ;	/* clear timer event flag */
+	smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));
+}
+
+/*
+ * SMT timer interface
+ *	start RMT timer 2
+ */
+static void start_rmt_timer2(smc,value,event)
+struct s_smc *smc ;
+u_long value ;
+int event ;
+{
+	smc->r.timer2_exp = FALSE ;		/* clear timer event flag */
+	smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));
+}
+
+/*
+ * SMT timer interface
+ *	stop RMT timer 0
+ */
+static void stop_rmt_timer0(smc)
+struct s_smc *smc ;
+{
+	if (smc->r.rmt_timer0.tm_active)
+		smt_timer_stop(smc,&smc->r.rmt_timer0) ;
+}
+
+/*
+ * SMT timer interface
+ *	stop RMT timer 1
+ */
+static void stop_rmt_timer1(smc)
+struct s_smc *smc ;
+{
+	if (smc->r.rmt_timer1.tm_active)
+		smt_timer_stop(smc,&smc->r.rmt_timer1) ;
+}
+
+/*
+ * SMT timer interface
+ *	stop RMT timer 2
+ */
+static void stop_rmt_timer2(smc)
+struct s_smc *smc ;
+{
+	if (smc->r.rmt_timer2.tm_active)
+		smt_timer_stop(smc,&smc->r.rmt_timer2) ;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/skfddi.c linux.18p8/drivers/net/skfp/skfddi.c
--- linux.vanilla/drivers/net/skfp/skfddi.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/skfddi.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,2614 @@
+/*
+ * File Name:
+ *   skfddi.c
+ *
+ * Copyright Information:
+ *   Copyright SysKonnect 1998,1999.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * The information in this file is provided "AS IS" without warranty.
+ *
+ * Abstract:
+ *   A Linux device driver supporting the SysKonnect FDDI PCI controller
+ *   familie.
+ *
+ * Maintainers:
+ *   CG    Christoph Goos (cgoos@syskonnect.de)
+ *
+ * Contributors:
+ *   DM    David S. Miller
+ *   OT    Oliver Teuber
+ *
+ * Address all questions to:
+ *   linux@syskonnect.de
+ *
+ * The technical manual for the adapters is available from SysKonnect's
+ * web pages: www.syskonnect.com
+ * Goto "Support" and search Knowledge Base for "manual".
+ *
+ * Driver Architecture:
+ *   The driver architecture is based on the DEC FDDI driver by
+ *   Lawrence V. Stefani and several ethernet drivers.
+ *   I also used an existing Windows NT miniport driver.
+ *   All hardware dependant fuctions are handled by the SysKonnect
+ *   Hardware Module.
+ *   The only headerfiles that are directly related to this source
+ *   are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h.
+ *   The others belong to the SysKonnect FDDI Hardware Module and
+ *   should better not be changed.
+ * NOTE:
+ *   Compiling this driver produces some warnings, but I did not fix
+ *   this, because the Hardware Module source is used for different
+ *   drivers, and fixing it for Linux might bring problems on other
+ *   projects. To keep the source common for all those drivers (and
+ *   thus simplify fixes to it), please do not clean it up!
+ *
+ * Modification History:
+ *              Date            Name    Description
+ *              02-Mar-98       CG	Created.
+ *
+ *		10-Mar-99	CG	Support for 2.2.x added.
+ *		25-Mar-99	CG	Corrected IRQ routing for SMP (APIC)
+ *		26-Oct-99	CG	Fixed compilation error on 2.2.13
+ *		12-Nov-99	CG	Source code release
+ *		15-Dec-99	CG	Removed some printk statements
+ *		11-Jan-2000	CG	Fixed printk statements
+ *		21-Jan-2000	OT	Added byte counter
+ *		07-May-2000	DM	64 bit fixes, new dma interface
+ *		18-Jul-2000	CG	Submitted to 2.2.17 kernel source tree.
+ *
+ * Compilation options (-Dxxx):
+ *              DRIVERDEBUG     print lots of messages to log file
+ *              DUMPPACKETS     print received/transmitted packets to logfile
+ * 
+ * Tested cpu architectures:
+ *	- i386
+ *	- sparc64
+ */
+
+/* Version information string - should be updated prior to */
+/* each new release!!! */
+#define VERSION		"2.07"
+
+static const char *boot_msg = 
+	"SysKonnect FDDI PCI Adapter driver v" VERSION " for\n"
+	"  SK-55xx/SK-58xx adapters (SK-NET FDDI-FP/UP/LP)";
+
+/* Include files */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/ctype.h>	// isdigit
+
+#include <linux/netdevice.h>
+#include <linux/fddidevice.h>
+#include <linux/skbuff.h>
+
+#include	"h/types.h"
+#undef ADDR			// undo Linux definition
+#include	"h/skfbi.h"
+#include	"h/fddi.h"
+#include	"h/smc.h"
+#include	"h/smtstate.h"
+
+
+// Define global routines
+int skfp_probe(struct device *dev);
+
+
+// Define module-wide (static) routines
+static struct device *alloc_device(struct device *dev, u_long iobase);
+static struct device *insert_device(struct device *dev,
+				    int (*init) (struct device *));
+static int fddi_dev_index(unsigned char *s);
+static void init_dev(struct device *dev, u_long iobase);
+static void link_modules(struct device *dev, struct device *tmp);
+static int skfp_driver_init(struct device *dev);
+static int skfp_open(struct device *dev);
+static int skfp_close(struct device *dev);
+static void skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct enet_statistics *skfp_ctl_get_stats(struct device *dev);
+static void skfp_ctl_set_multicast_list(struct device *dev);
+static void skfp_ctl_set_multicast_list_wo_lock(struct device *dev);
+static int skfp_ctl_set_mac_address(struct device *dev, void *addr);
+static int skfp_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static int skfp_send_pkt(struct sk_buff *skb, struct device *dev);
+static void send_queued_packets(struct s_smc *smc);
+static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr);
+static void ResetAdapter(struct s_smc *smc);
+
+
+// Functions needed by the hardware module
+void *mac_drv_get_space(struct s_smc *smc, u_int size);
+void *mac_drv_get_desc_mem(struct s_smc *smc, u_int size);
+unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt);
+unsigned long dma_master(struct s_smc *smc, void *virt, int len, int flag);
+void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr,
+		  int flag);
+void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd);
+void llc_restart_tx(struct s_smc *smc);
+void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+			 int frag_count, int len);
+void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+			 int frag_count);
+void mac_drv_fill_rxd(struct s_smc *smc);
+void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+		       int frag_count);
+int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
+		    int la_len);
+void smt_timer_poll(struct s_smc *smc);
+void ring_status_indication(struct s_smc *smc, u_long status);
+unsigned long smt_get_time(void);
+void smt_stat_counter(struct s_smc *smc, int stat);
+void cfm_state_change(struct s_smc *smc, int c_state);
+void ecm_state_change(struct s_smc *smc, int e_state);
+void pcm_state_change(struct s_smc *smc, int plc, int p_state);
+void rmt_state_change(struct s_smc *smc, int r_state);
+void drv_reset_indication(struct s_smc *smc);
+void dump_data(unsigned char *Data, int length);
+
+
+// External functions from the hardware module
+extern u_int mac_drv_check_space();
+extern void read_address(struct s_smc *smc, u_char * mac_addr);
+extern void card_stop(struct s_smc *smc);
+extern int mac_drv_init(struct s_smc *smc);
+extern void hwm_tx_frag(struct s_smc *smc, char far * virt, u_long phys,
+			int len, int frame_status);
+extern int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count,
+		       int frame_len, int frame_status);
+extern int init_smt(struct s_smc *smc, u_char * mac_addr);
+extern void fddi_isr(struct s_smc *smc);
+extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys,
+			int len, int frame_status);
+extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
+extern void mac_drv_clear_tx_queue(struct s_smc *smc);
+extern void mac_drv_clear_rx_queue(struct s_smc *smc);
+extern void mac_clear_multicast(struct s_smc *smc);
+extern void enable_tx_irq(struct s_smc *smc, u_short queue);
+extern void mac_drv_clear_txd(struct s_smc *smc);
+
+
+// Define module-wide (static) variables
+
+static int num_boards = 0;	/* total number of adapters configured */
+static int num_fddi = 0;
+static int autoprobed = 0;
+
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+static struct device *unlink_modules(struct device *p);
+static int loading_module = 1;
+#else
+static int loading_module = 0;
+#endif				// MODULE
+
+#ifdef DRIVERDEBUG
+#define PRINTK(s, args...) printk(s, ## args)
+#else
+#define PRINTK(s, args...)
+#endif				// DRIVERDEBUG
+
+#define PRIV(dev) (&(((struct s_smc *)dev->priv)->os))
+
+/*
+ * ==============
+ * = skfp_probe =
+ * ==============
+ *   
+ * Overview:
+ *   Probes for supported FDDI PCI controllers
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This routine is called by the OS for each FDDI device name (fddi0,
+ *   fddi1,...,fddi6, fddi7) specified in drivers/net/Space.c.
+ *   If loaded as a module, it will detect and initialize all 
+ *   adapters the first time it is called.
+ *
+ *   Let's say that skfp_probe() is getting called to initialize fddi0.
+ *   Furthermore, let's say there are three supported controllers in the
+ *   system.  Before skfp_probe() leaves, devices fddi0, fddi1, and fddi2
+ *   will be initialized and a global flag will be set to indicate that
+ *   skfp_probe() has already been called.
+ *
+ *   However...the OS doesn't know that we've already initialized
+ *   devices fddi1 and fddi2 so skfp_probe() gets called again and again
+ *   until it reaches the end of the device list for FDDI (presently,
+ *   fddi7).  It's important that the driver "pretend" to probe for
+ *   devices fddi1 and fddi2 and return success.  Devices fddi3
+ *   through fddi7 will return failure since they weren't initialized.
+ *
+ *   This algorithm seems to work for the time being.  As other FDDI
+ *   drivers are written for Linux, a more generic approach (perhaps
+ *   similar to the Ethernet card approach) may need to be implemented.
+ *   
+ * Return Codes:
+ *   0           - This device (fddi0, fddi1, etc) configured successfully
+ *   -ENODEV - No devices present, or no SysKonnect FDDI PCI device
+ *                         present for this device name
+ *
+ *
+ * Side Effects:
+ *   Device structures for FDDI adapters (fddi0, fddi1, etc) are
+ *   initialized and the board resources are read and stored in
+ *   the device structure.
+ */
+int skfp_probe(struct device *dev)
+{
+	int i;			/* used in for loops */
+	struct pci_dev *pdev = NULL;	/* PCI device structure */
+#ifndef MEM_MAPPED_IO
+	u16 port;		/* temporary I/O (port) address */
+	int port_len;		/* length of port address range (in bytes) */
+#else
+	unsigned long port;
+#endif
+	u16 command;	/* PCI Configuration space Command register val */
+	struct s_smc *smc;	/* board pointer */
+	struct device *tmp = dev;
+	u8 first_dev_used = 0;
+	u16 SubSysId;
+#ifdef __sparc_v9__
+	unsigned short	pci_tmp;
+#endif
+
+	PRINTK(KERN_INFO "entering skfp_probe\n");
+
+	/*
+	 * Verify whether we're going through skfp_probe() again
+	 *
+	 * If so, see if we're going through for a subsequent fddi device that
+	 * we've already initialized.  If we are, return success (0).  If not,
+	 * return failure (-ENODEV).
+	 */
+
+	if (autoprobed) {
+		PRINTK(KERN_INFO "Already entered skfp_probe\n");
+		if (dev != NULL) {
+			if ((strncmp(dev->name, "fddi", 4) == 0) &&
+			    (dev->base_addr != 0)) {
+				return (0);
+			}
+			return (-ENODEV);
+		}
+	}
+	autoprobed = 1;		/* set global flag */
+
+	printk("%s\n", boot_msg);
+
+	/* Scan for Syskonnect FDDI PCI controllers */
+	if (!pci_present()) {	/* is PCI BIOS even present? */
+		printk("no PCI BIOS present\n");
+		return (-ENODEV);
+	}
+	for (i = 0; i < SKFP_MAX_NUM_BOARDS; i++) {	// scan for PCI cards
+		PRINTK(KERN_INFO "Check device %d\n", i);
+		if ((pdev=pci_find_device(PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP,
+			pdev)) == 0) {
+			break;
+		}
+
+#ifndef MEM_MAPPED_IO
+		/* Verify that I/O enable bit is set (PCI slot is enabled) */
+		pci_read_config_word(pdev, PCI_COMMAND, &command);
+		if ((command & PCI_COMMAND_IO) == 0) {
+			PRINTK("I/O enable bit not set!");
+			PRINTK(" Verify that slot is enabled\n");
+			continue;
+		}
+
+		/* Turn off memory mapped space and enable mastering */
+
+		PRINTK(KERN_INFO "Command Reg: %04x\n", command);
+		command |= PCI_COMMAND_MASTER;
+		command &= ~PCI_COMMAND_MEMORY;
+		pci_write_config_word(pdev, PCI_COMMAND, command);
+
+		/* Read I/O base address from PCI Configuration Space */
+
+		pci_read_config_word(pdev, PCI_BASE_ADDRESS_1, &port);
+		port &= PCI_BASE_ADDRESS_IO_MASK; // clear I/O bit (bit 0)
+
+		/* Verify port address range is not already being used */
+
+		port_len = FP_IO_LEN;
+		if (check_region(port, port_len) != 0) {
+			printk("I/O range allocated to adapter");
+			printk(" (0x%X-0x%X) is already being used!\n", port,
+			       (port + port_len - 1));
+			continue;
+		}
+#else
+		/* Verify that MEM enable bit is set (PCI slot is enabled) */
+		pci_read_config_word(pdev, PCI_COMMAND, &command);
+		if ((command & PCI_COMMAND_MEMORY) == 0) {
+			PRINTK("MEMORY-I/O enable bit not set!");
+			PRINTK(" Verify that slot is enabled\n");
+			continue;
+		}
+
+		pci_set_master(pdev);
+
+#ifdef __sparc_v9__
+		/* SPARC machines do not initialize the cache line size */
+                pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64);
+		/* SPARC machines do not set "Memory write and invalidate" */
+                pci_read_config_word(pdev, PCI_COMMAND, &pci_tmp);
+		pci_tmp |= PCI_COMMAND_INVALIDATE;
+                pci_write_config_word(pdev, PCI_COMMAND, pci_tmp);
+#endif 
+		
+		port = pdev->base_address[0];
+		port &= PCI_BASE_ADDRESS_MEM_MASK;
+
+#ifndef __sparc_v9__
+		port = (unsigned long)ioremap(port, 0x4000);
+#else
+		/* workaround for bug in 2.2 kernel for sparcv9 */
+		/* use port as is */
+#endif
+		if (!port){
+			printk("skfp:  Unable to map MEMORY register, "
+			"FDDI adapter will be disabled.\n");
+			break;
+		}
+#endif
+		
+		if ((!loading_module) || first_dev_used) {
+			/* Allocate a device structure for this adapter */
+			tmp = alloc_device(dev, port);
+		}
+		first_dev_used = 1;	// only significant first time
+
+		pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &SubSysId);
+		
+		if (tmp != NULL) {
+			if (loading_module)
+				link_modules(dev, tmp);
+			dev = tmp;
+			init_dev(dev, port);
+			dev->irq = pdev->irq;
+
+			/* Initialize board structure with bus-specific info */
+
+			smc = (struct s_smc *) dev->priv;
+			smc->os.dev = dev;
+			smc->os.bus_type = SK_BUS_TYPE_PCI;
+			smc->os.pdev = *pdev;
+			smc->os.QueueSkb = MAX_TX_QUEUE_LEN;
+			smc->os.MaxFrameSize = MAX_FRAME_SIZE;
+			smc->os.dev = dev;
+			smc->hw.slot = -1;
+			smc->os.ResetRequested = FALSE;
+			skb_queue_head_init(&smc->os.SendSkbQueue);
+
+			if (skfp_driver_init(dev) == 0) {
+				// only increment global board 
+				// count on success
+				num_boards++;
+				request_region(dev->base_addr,
+					       FP_IO_LEN, dev->name);
+				if ((SubSysId & 0xff00) == 0x5500 ||
+					(SubSysId & 0xff00) == 0x5800) {
+				printk("%s: SysKonnect FDDI PCI adapter"
+				       " found (SK-%04X)\n", dev->name,
+					SubSysId);
+				} else {
+				printk("%s: FDDI PCI adapter found\n",
+					dev->name);
+				}
+			} else {
+				kfree(dev);
+				i = SKFP_MAX_NUM_BOARDS;	// stop search
+
+			}
+
+		}		// if (dev != NULL)
+
+	}			// for SKFP_MAX_NUM_BOARDS
+
+	/*
+	 * If we're at this point we're going through skfp_probe() for the
+	 * first time. Return success (0) if we've initialized 1 or more
+	 * boards. Otherwise, return failure (-ENODEV).
+	 */
+
+	if (num_boards > 0)
+		return (0);
+	else {
+		printk("no SysKonnect FDDI adapter found\n");
+		return (-ENODEV);
+	}
+}				// skfp_probe
+
+
+/************************
+ *
+ * Search the entire 'fddi' device list for a fixed probe. If a match isn't
+ * found then check for an autoprobe or unused device location. If they
+ * are not available then insert a new device structure at the end of
+ * the current list.
+ *
+ ************************/
+static struct device *alloc_device(struct device *dev, u_long iobase)
+{
+	struct device *adev = NULL;
+	int fixed = 0, new_dev = 0;
+
+	PRINTK(KERN_INFO "entering alloc_device\n");
+	if (!dev)
+		return dev;
+
+	num_fddi = fddi_dev_index(dev->name);
+	if (loading_module) {
+		num_fddi++;
+		dev = insert_device(dev, skfp_probe);
+		return dev;
+	}
+	while (1) {
+		if (((dev->base_addr == NO_ADDRESS) ||
+		     (dev->base_addr == 0)) && !adev) {
+			adev = dev;
+		} else if ((dev->priv == NULL) && (dev->base_addr == iobase)) {
+			fixed = 1;
+		} else {
+			if (dev->next == NULL) {
+				new_dev = 1;
+			} else if (strncmp(dev->next->name, "fddi", 4) != 0) {
+				new_dev = 1;
+			}
+		}
+		if ((dev->next == NULL) || new_dev || fixed)
+			break;
+		dev = dev->next;
+		num_fddi++;
+	}			// while (1)
+
+	if (adev && !fixed) {
+		dev = adev;
+		num_fddi = fddi_dev_index(dev->name);
+		new_dev = 0;
+	}
+	if (((dev->next == NULL) && ((dev->base_addr != NO_ADDRESS) &&
+				     (dev->base_addr != 0)) && !fixed) ||
+	    new_dev) {
+		num_fddi++;	/* New device */
+		dev = insert_device(dev, skfp_probe);
+	}
+	if (dev) {
+		if (!dev->priv) {
+			/* Allocate space for private board structure */
+			dev->priv = (void *) kmalloc(sizeof(struct s_smc),
+						     GFP_KERNEL);
+			if (dev->priv == NULL) {
+				printk("%s: Could not allocate memory for",
+					dev->name);
+				printk(" private board structure!\n");
+				return (NULL);
+			}
+			/* clear structure */
+			memset(dev->priv, 0, sizeof(struct s_smc));
+		}
+	}
+	return dev;
+}				// alloc_device
+
+
+
+/************************
+ *
+ * Initialize device structure
+ *
+ ************************/
+static void init_dev(struct device *dev, u_long iobase)
+{
+	/* Initialize new device structure */
+
+	dev->rmem_end = 0;	/* shared memory isn't used */
+	dev->rmem_start = 0;	/* shared memory isn't used */
+	dev->mem_end = 0;	/* shared memory isn't used */
+	dev->mem_start = 0;	/* shared memory isn't used */
+	dev->base_addr = iobase;	/* save port (I/O) base address */
+	dev->irq = 0;		/* set in skfp_driver_init() */
+	dev->if_port = 0;	/* not applicable to FDDI adapters */
+	dev->dma = 0;		/* Bus Master DMA doesn't require channel */
+	dev->interrupt = 0;
+
+	dev->get_stats = &skfp_ctl_get_stats;
+	dev->open = &skfp_open;
+	dev->stop = &skfp_close;
+	dev->hard_start_xmit = &skfp_send_pkt;
+	dev->hard_header = NULL;	/* set in fddi_setup() */
+	dev->rebuild_header = NULL;	/* set in fddi_setup() */
+	dev->set_multicast_list = &skfp_ctl_set_multicast_list;
+	dev->set_mac_address = &skfp_ctl_set_mac_address;
+	dev->do_ioctl = &skfp_ioctl;
+	dev->set_config = NULL;	/* not supported for now &&& */
+	dev->header_cache_update = NULL;	/* not supported */
+	dev->change_mtu = NULL;	/* set in fddi_setup() */
+
+	/* Initialize remaining device structure information */
+	fddi_setup(dev);
+}				// init_device
+
+
+/************************
+ *
+ * If at end of fddi device list and can't use current entry, malloc
+ * one up. If memory could not be allocated, print an error message.
+ *
+************************/
+static struct device *insert_device(struct device *dev,
+				    int (*init) (struct device *))
+{
+	struct device *new;
+	int len;
+
+	PRINTK(KERN_INFO "entering insert_device\n");
+	len = sizeof(struct device) + sizeof(struct s_smc);
+	new = (struct device *) kmalloc(len, GFP_KERNEL);
+	if (new == NULL) {
+		printk("fddi%d: Device not initialised, insufficient memory\n",
+		       num_fddi);
+		return NULL;
+	} else {
+		memset((char *) new, 0, len);
+		new->name = (char *) (new + 1);
+		new->priv = (struct s_smc *) (new->name + 8);
+		new->init = init;	/* initialisation routine */
+		if (!loading_module) {
+			new->next = dev->next;
+			dev->next = new;
+		}
+		/* create new device name */
+		if (num_fddi > 999) {
+			sprintf(new->name, "fddi????");
+		} else {
+			sprintf(new->name, "fddi%d", num_fddi);
+		}
+	}
+	return new;
+}				// insert_device
+
+
+/************************
+ *
+ * Get the number of a "fddiX" string
+ *
+ ************************/
+static int fddi_dev_index(unsigned char *s)
+{
+	int i = 0, j = 0;
+
+	for (; *s; s++) {
+		if (isdigit(*s)) {
+			j = 1;
+			i = (i * 10) + (*s - '0');
+		} else if (j)
+			break;
+	}
+	return i;
+}				// fddi_dev_index
+
+
+/************************
+ *
+ * Used if loaded as module only. Link the device structures
+ * together. Needed to release them all at unload.
+ *
+************************/
+static void link_modules(struct device *dev, struct device *tmp)
+{
+	struct device *p = dev;
+
+	if (p) {
+		while (((struct s_smc *) (p->priv))->os.next_module) {
+			p = ((struct s_smc *) (p->priv))->os.next_module;
+		}
+
+		if (dev != tmp) {
+			((struct s_smc *) (p->priv))->os.next_module = tmp;
+		} else {
+			((struct s_smc *) (p->priv))->os.next_module = NULL;
+		}
+	}
+	return;
+}				// link_modules
+
+
+
+/*
+ * ====================
+ * = skfp_driver_init =
+ * ====================
+ *   
+ * Overview:
+ *   Initializes remaining adapter board structure information
+ *   and makes sure adapter is in a safe state prior to skfp_open().
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This function allocates additional resources such as the host memory
+ *   blocks needed by the adapter.
+ *   The adapter is also reset. The OS must call skfp_open() to open 
+ *   the adapter and bring it on-line.
+ *
+ * Return Codes:
+ *    0 - initialization succeeded
+ *   -1 - initialization failed
+ */
+static int skfp_driver_init(struct device *dev)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+	skfddi_priv *bp = PRIV(dev);
+	u8 val;			/* used for I/O read/writes */
+
+	PRINTK(KERN_INFO "entering skfp_driver_init\n");
+
+	// set the io address in private structures
+	bp->base_addr = dev->base_addr;
+	smc->hw.iop = dev->base_addr;
+
+	// Get the interrupt level from the PCI Configuration Table
+	val = dev->irq;
+
+	smc->hw.irq = val;
+
+	spin_lock_init(&bp->DriverLock);
+	
+	// Determine the required size of the 'shared' memory area.
+	bp->SharedMemSize = mac_drv_check_space();
+	PRINTK(KERN_INFO "Memory for HWM: %ld\n", bp->SharedMemSize);
+	if (bp->SharedMemSize > 0) {
+		bp->SharedMemSize += 16;	// for descriptor alignment
+
+		bp->SharedMemAddr = kmalloc(bp->SharedMemSize, GFP_KERNEL);
+		if (!bp->SharedMemSize) {
+			printk("could not allocate mem for ");
+			printk("hardware module: %ld byte\n",
+			       bp->SharedMemSize);
+			return (-1);
+		}
+		bp->SharedMemHeap = 0;	// Nothing used yet.
+
+	} else {
+		bp->SharedMemAddr = NULL;
+		bp->SharedMemHeap = 0;
+	}			// SharedMemSize > 0
+
+	memset(bp->SharedMemAddr, 0, bp->SharedMemSize);
+
+	card_stop(smc);		// Reset adapter.
+
+	PRINTK(KERN_INFO "mac_drv_init()..\n");
+	if (mac_drv_init(smc) != 0) {
+		PRINTK(KERN_INFO "mac_drv_init() failed.\n");
+		return (-1);
+	}
+	read_address(smc, NULL);
+	PRINTK(KERN_INFO "HW-Addr: %02x %02x %02x %02x %02x %02x\n",
+	       smc->hw.fddi_canon_addr.a[0],
+	       smc->hw.fddi_canon_addr.a[1],
+	       smc->hw.fddi_canon_addr.a[2],
+	       smc->hw.fddi_canon_addr.a[3],
+	       smc->hw.fddi_canon_addr.a[4],
+	       smc->hw.fddi_canon_addr.a[5]);
+	memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6);
+
+	smt_reset_defaults(smc, 0);
+
+	return (0);
+}				// skfp_driver_init
+
+
+/*
+ * =============
+ * = skfp_open =
+ * =============
+ *   
+ * Overview:
+ *   Opens the adapter
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This function brings the adapter to an operational state.
+ *
+ * Return Codes:
+ *   0           - Adapter was successfully opened
+ *   -EAGAIN - Could not register IRQ
+ */
+static int skfp_open(struct device *dev)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+
+	PRINTK(KERN_INFO "entering skfp_open\n");
+	/* Register IRQ - support shared interrupts by passing device ptr */
+	if (request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ,
+			dev->name, dev)) {
+		printk("%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
+		return (-EAGAIN);
+	}
+	/*
+	 * Set current address to factory MAC address
+	 *
+	 * Note: We've already done this step in skfp_driver_init.
+	 *       However, it's possible that a user has set a node
+	 *               address override, then closed and reopened the
+	 *               adapter.  Unless we reset the device address field
+	 *               now, we'll continue to use the existing modified
+	 *               address.
+	 */
+	read_address(smc, NULL);
+	memcpy(dev->dev_addr, smc->hw.fddi_canon_addr.a, 6);
+
+	init_smt(smc, NULL);
+	smt_online(smc, 1);
+	STI_FBI();
+
+	MOD_INC_USE_COUNT;
+
+	/* Set device structure info */
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* Clear local multicast address tables */
+	mac_clear_multicast(smc);
+
+	/* Disable promiscuous filter settings */
+	mac_drv_rx_mode(smc, RX_DISABLE_PROMISC);
+
+	return (0);
+}				// skfp_open
+
+
+/*
+ * ==============
+ * = skfp_close =
+ * ==============
+ *   
+ * Overview:
+ *   Closes the device/module.
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This routine closes the adapter and brings it to a safe state.
+ *   The interrupt service routine is deregistered with the OS.
+ *   The adapter can be opened again with another call to skfp_open().
+ *
+ * Return Codes:
+ *   Always return 0.
+ *
+ * Assumptions:
+ *   No further requests for this adapter are made after this routine is
+ *   called.  skfp_open() can be called to reset and reinitialize the
+ *   adapter.
+ */
+static int skfp_close(struct device *dev)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+	struct sk_buff *skb;
+	skfddi_priv *bp = PRIV(dev);
+
+	CLI_FBI();
+	smt_reset_defaults(smc, 1);
+	card_stop(smc);
+	mac_drv_clear_tx_queue(smc);
+	mac_drv_clear_rx_queue(smc);
+
+	/* Clear device structure flags */
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	/* Deregister (free) IRQ */
+	free_irq(dev->irq, dev);
+
+	for (;;) {
+		skb = skb_dequeue(&bp->SendSkbQueue);
+		if (skb == NULL)
+			break;
+		bp->QueueSkb++;
+		dev_kfree_skb(skb);
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return (0);
+}				// skfp_close
+
+
+/*
+ * ==================
+ * = skfp_interrupt =
+ * ==================
+ *   
+ * Overview:
+ *   Interrupt processing routine
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   irq        - interrupt vector
+ *   dev_id     - pointer to device information
+ *       regs   - pointer to registers structure
+ *
+ * Functional Description:
+ *   This routine calls the interrupt processing routine for this adapter.  It
+ *   disables and reenables adapter interrupts, as appropriate.  We can support
+ *   shared interrupts since the incoming dev_id pointer provides our device
+ *   structure context. All the real work is done in the hardware module.
+ *
+ * Return Codes:
+ *   None
+ *
+ * Assumptions:
+ *   The interrupt acknowledgement at the hardware level (eg. ACKing the PIC
+ *   on Intel-based systems) is done by the operating system outside this
+ *   routine.
+ *
+ *       System interrupts are enabled through this call.
+ *
+ * Side Effects:
+ *   Interrupts are disabled, then reenabled at the adapter.
+ */
+
+void skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *) dev_id;
+	struct s_smc *smc;	/* private board structure pointer */
+	skfddi_priv *bp = PRIV(dev);
+
+
+	if (dev == NULL) {
+		printk("%s: ERROR: irq %d for unknown device\n", dev->name, irq);
+		return;
+	}
+	if (dev->interrupt) {
+		printk("%s: ERROR: reentering interrupt handler\n", dev->name);
+	}
+	dev->interrupt = 1;
+
+	smc = (struct s_smc *) dev->priv;
+
+	// IRQs enabled or disabled ?
+	if (inpd(ADDR(B0_IMSK)) == 0) {
+		// IRQs are disabled.
+		// printk(KERN_INFO "Foreign IRQ (B).\n");
+		dev->interrupt = 0;
+		return;
+	}
+	// Note: At this point, IRQs are enabled.
+	if ((inpd(ISR_A) & smc->hw.is_imask) == 0) {	// IRQ?
+		// Adapter did not issue an IRQ.
+		// printk(KERN_INFO "Foreign IRQ (C).\n");
+		dev->interrupt = 0;
+		return;
+	}
+	CLI_FBI();		// Disable IRQs from our adapter.
+	spin_lock(&bp->DriverLock);
+
+	// Call interrupt handler in hardware module (HWM).
+	fddi_isr(smc);
+
+	if (smc->os.ResetRequested) {
+		ResetAdapter(smc);
+		smc->os.ResetRequested = FALSE;
+	}
+	dev->interrupt = 0;
+	spin_unlock(&bp->DriverLock);
+	STI_FBI();		// Enable IRQs from our adapter.
+
+	return;
+}				// skfp_interrupt
+
+
+/*
+ * ======================
+ * = skfp_ctl_get_stats =
+ * ======================
+ *   
+ * Overview:
+ *   Get statistics for FDDI adapter
+ *  
+ * Returns:
+ *   Pointer to FDDI statistics structure
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   Gets current MIB objects from adapter, then
+ *   returns FDDI statistics structure as defined
+ *   in if_fddi.h.
+ *
+ *   Note: Since the FDDI statistics structure is
+ *   still new and the device structure doesn't
+ *   have an FDDI-specific get statistics handler,
+ *   we'll return the FDDI statistics structure as
+ *   a pointer to an Ethernet statistics structure.
+ *   That way, at least the first part of the statistics
+ *   structure can be decoded properly.
+ *   We'll have to pay attention to this routine as the
+ *   device structure becomes more mature and LAN media
+ *   independent.
+ *
+ */
+struct enet_statistics *skfp_ctl_get_stats(struct device *dev)
+{
+	struct s_smc *bp = (struct s_smc *) dev->priv;
+
+	/* Fill the bp->stats structure with driver-maintained counters */
+
+	bp->os.MacStat.port_bs_flag[0] = 0x1234;
+	bp->os.MacStat.port_bs_flag[1] = 0x5678;
+// goos: need to fill out fddi statistic
+#if 0
+	/* Get FDDI SMT MIB objects */
+
+/* Fill the bp->stats structure with the SMT MIB object values */
+
+	memcpy(bp->stats.smt_station_id, &bp->cmd_rsp_virt->smt_mib_get.smt_station_id, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_station_id));
+	bp->stats.smt_op_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_op_version_id;
+	bp->stats.smt_hi_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_hi_version_id;
+	bp->stats.smt_lo_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_lo_version_id;
+	memcpy(bp->stats.smt_user_data, &bp->cmd_rsp_virt->smt_mib_get.smt_user_data, sizeof(bp->cmd_rsp_virt->smt_mib_get.smt_user_data));
+	bp->stats.smt_mib_version_id = bp->cmd_rsp_virt->smt_mib_get.smt_mib_version_id;
+	bp->stats.smt_mac_cts = bp->cmd_rsp_virt->smt_mib_get.smt_mac_ct;
+	bp->stats.smt_non_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_non_master_ct;
+	bp->stats.smt_master_cts = bp->cmd_rsp_virt->smt_mib_get.smt_master_ct;
+	bp->stats.smt_available_paths = bp->cmd_rsp_virt->smt_mib_get.smt_available_paths;
+	bp->stats.smt_config_capabilities = bp->cmd_rsp_virt->smt_mib_get.smt_config_capabilities;
+	bp->stats.smt_config_policy = bp->cmd_rsp_virt->smt_mib_get.smt_config_policy;
+	bp->stats.smt_connection_policy = bp->cmd_rsp_virt->smt_mib_get.smt_connection_policy;
+	bp->stats.smt_t_notify = bp->cmd_rsp_virt->smt_mib_get.smt_t_notify;
+	bp->stats.smt_stat_rpt_policy = bp->cmd_rsp_virt->smt_mib_get.smt_stat_rpt_policy;
+	bp->stats.smt_trace_max_expiration = bp->cmd_rsp_virt->smt_mib_get.smt_trace_max_expiration;
+	bp->stats.smt_bypass_present = bp->cmd_rsp_virt->smt_mib_get.smt_bypass_present;
+	bp->stats.smt_ecm_state = bp->cmd_rsp_virt->smt_mib_get.smt_ecm_state;
+	bp->stats.smt_cf_state = bp->cmd_rsp_virt->smt_mib_get.smt_cf_state;
+	bp->stats.smt_remote_disconnect_flag = bp->cmd_rsp_virt->smt_mib_get.smt_remote_disconnect_flag;
+	bp->stats.smt_station_status = bp->cmd_rsp_virt->smt_mib_get.smt_station_status;
+	bp->stats.smt_peer_wrap_flag = bp->cmd_rsp_virt->smt_mib_get.smt_peer_wrap_flag;
+	bp->stats.smt_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_msg_time_stamp.ls;
+	bp->stats.smt_transition_time_stamp = bp->cmd_rsp_virt->smt_mib_get.smt_transition_time_stamp.ls;
+	bp->stats.mac_frame_status_functions = bp->cmd_rsp_virt->smt_mib_get.mac_frame_status_functions;
+	bp->stats.mac_t_max_capability = bp->cmd_rsp_virt->smt_mib_get.mac_t_max_capability;
+	bp->stats.mac_tvx_capability = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_capability;
+	bp->stats.mac_available_paths = bp->cmd_rsp_virt->smt_mib_get.mac_available_paths;
+	bp->stats.mac_current_path = bp->cmd_rsp_virt->smt_mib_get.mac_current_path;
+	memcpy(bp->stats.mac_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_upstream_nbr, FDDI_K_ALEN);
+	memcpy(bp->stats.mac_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_downstream_nbr, FDDI_K_ALEN);
+	memcpy(bp->stats.mac_old_upstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_upstream_nbr, FDDI_K_ALEN);
+	memcpy(bp->stats.mac_old_downstream_nbr, &bp->cmd_rsp_virt->smt_mib_get.mac_old_downstream_nbr, FDDI_K_ALEN);
+	bp->stats.mac_dup_address_test = bp->cmd_rsp_virt->smt_mib_get.mac_dup_address_test;
+	bp->stats.mac_requested_paths = bp->cmd_rsp_virt->smt_mib_get.mac_requested_paths;
+	bp->stats.mac_downstream_port_type = bp->cmd_rsp_virt->smt_mib_get.mac_downstream_port_type;
+	memcpy(bp->stats.mac_smt_address, &bp->cmd_rsp_virt->smt_mib_get.mac_smt_address, FDDI_K_ALEN);
+	bp->stats.mac_t_req = bp->cmd_rsp_virt->smt_mib_get.mac_t_req;
+	bp->stats.mac_t_neg = bp->cmd_rsp_virt->smt_mib_get.mac_t_neg;
+	bp->stats.mac_t_max = bp->cmd_rsp_virt->smt_mib_get.mac_t_max;
+	bp->stats.mac_tvx_value = bp->cmd_rsp_virt->smt_mib_get.mac_tvx_value;
+	bp->stats.mac_frame_error_threshold = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_threshold;
+	bp->stats.mac_frame_error_ratio = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_ratio;
+	bp->stats.mac_rmt_state = bp->cmd_rsp_virt->smt_mib_get.mac_rmt_state;
+	bp->stats.mac_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_da_flag;
+	bp->stats.mac_una_da_flag = bp->cmd_rsp_virt->smt_mib_get.mac_unda_flag;
+	bp->stats.mac_frame_error_flag = bp->cmd_rsp_virt->smt_mib_get.mac_frame_error_flag;
+	bp->stats.mac_ma_unitdata_available = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_available;
+	bp->stats.mac_hardware_present = bp->cmd_rsp_virt->smt_mib_get.mac_hardware_present;
+	bp->stats.mac_ma_unitdata_enable = bp->cmd_rsp_virt->smt_mib_get.mac_ma_unitdata_enable;
+	bp->stats.path_tvx_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_tvx_lower_bound;
+	bp->stats.path_t_max_lower_bound = bp->cmd_rsp_virt->smt_mib_get.path_t_max_lower_bound;
+	bp->stats.path_max_t_req = bp->cmd_rsp_virt->smt_mib_get.path_max_t_req;
+	memcpy(bp->stats.path_configuration, &bp->cmd_rsp_virt->smt_mib_get.path_configuration, sizeof(bp->cmd_rsp_virt->smt_mib_get.path_configuration));
+	bp->stats.port_my_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[0];
+	bp->stats.port_my_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_my_type[1];
+	bp->stats.port_neighbor_type[0] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[0];
+	bp->stats.port_neighbor_type[1] = bp->cmd_rsp_virt->smt_mib_get.port_neighbor_type[1];
+	bp->stats.port_connection_policies[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[0];
+	bp->stats.port_connection_policies[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_policies[1];
+	bp->stats.port_mac_indicated[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[0];
+	bp->stats.port_mac_indicated[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_indicated[1];
+	bp->stats.port_current_path[0] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[0];
+	bp->stats.port_current_path[1] = bp->cmd_rsp_virt->smt_mib_get.port_current_path[1];
+	memcpy(&bp->stats.port_requested_paths[0 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[0], 3);
+	memcpy(&bp->stats.port_requested_paths[1 * 3], &bp->cmd_rsp_virt->smt_mib_get.port_requested_paths[1], 3);
+	bp->stats.port_mac_placement[0] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[0];
+	bp->stats.port_mac_placement[1] = bp->cmd_rsp_virt->smt_mib_get.port_mac_placement[1];
+	bp->stats.port_available_paths[0] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[0];
+	bp->stats.port_available_paths[1] = bp->cmd_rsp_virt->smt_mib_get.port_available_paths[1];
+	bp->stats.port_pmd_class[0] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[0];
+	bp->stats.port_pmd_class[1] = bp->cmd_rsp_virt->smt_mib_get.port_pmd_class[1];
+	bp->stats.port_connection_capabilities[0] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[0];
+	bp->stats.port_connection_capabilities[1] = bp->cmd_rsp_virt->smt_mib_get.port_connection_capabilities[1];
+	bp->stats.port_bs_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[0];
+	bp->stats.port_bs_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_bs_flag[1];
+	bp->stats.port_ler_estimate[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[0];
+	bp->stats.port_ler_estimate[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_estimate[1];
+	bp->stats.port_ler_cutoff[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[0];
+	bp->stats.port_ler_cutoff[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_cutoff[1];
+	bp->stats.port_ler_alarm[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[0];
+	bp->stats.port_ler_alarm[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_alarm[1];
+	bp->stats.port_connect_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[0];
+	bp->stats.port_connect_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_connect_state[1];
+	bp->stats.port_pcm_state[0] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[0];
+	bp->stats.port_pcm_state[1] = bp->cmd_rsp_virt->smt_mib_get.port_pcm_state[1];
+	bp->stats.port_pc_withhold[0] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[0];
+	bp->stats.port_pc_withhold[1] = bp->cmd_rsp_virt->smt_mib_get.port_pc_withhold[1];
+	bp->stats.port_ler_flag[0] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[0];
+	bp->stats.port_ler_flag[1] = bp->cmd_rsp_virt->smt_mib_get.port_ler_flag[1];
+	bp->stats.port_hardware_present[0] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[0];
+	bp->stats.port_hardware_present[1] = bp->cmd_rsp_virt->smt_mib_get.port_hardware_present[1];
+
+
+	/* Fill the bp->stats structure with the FDDI counter values */
+
+	bp->stats.mac_frame_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.frame_cnt.ls;
+	bp->stats.mac_copied_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.copied_cnt.ls;
+	bp->stats.mac_transmit_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.transmit_cnt.ls;
+	bp->stats.mac_error_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.error_cnt.ls;
+	bp->stats.mac_lost_cts = bp->cmd_rsp_virt->cntrs_get.cntrs.lost_cnt.ls;
+	bp->stats.port_lct_fail_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[0].ls;
+	bp->stats.port_lct_fail_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lct_rejects[1].ls;
+	bp->stats.port_lem_reject_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[0].ls;
+	bp->stats.port_lem_reject_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.lem_rejects[1].ls;
+	bp->stats.port_lem_cts[0] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[0].ls;
+	bp->stats.port_lem_cts[1] = bp->cmd_rsp_virt->cntrs_get.cntrs.link_errors[1].ls;
+
+#endif
+	return ((struct enet_statistics *) &bp->os.MacStat);
+}				// ctl_get_stat
+
+
+/*
+ * ==============================
+ * = skfp_ctl_set_multicast_list =
+ * ==============================
+ *   
+ * Overview:
+ *   Enable/Disable LLC frame promiscuous mode reception
+ *   on the adapter and/or update multicast address table.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   This function aquires the driver lock and only calls
+ *   skfp_ctl_set_multicast_list_wo_lock then.
+ *   This routine follows a fairly simple algorithm for setting the
+ *   adapter filters and CAM:
+ *
+ *      if IFF_PROMISC flag is set
+ *              enable promiscuous mode
+ *      else
+ *              disable promiscuous mode
+ *              if number of multicast addresses <= max. multicast number
+ *                      add mc addresses to adapter table
+ *              else
+ *                      enable promiscuous mode
+ *              update adapter filters
+ *
+ * Assumptions:
+ *   Multicast addresses are presented in canonical (LSB) format.
+ *
+ * Side Effects:
+ *   On-board adapter filters are updated.
+ */
+static void skfp_ctl_set_multicast_list(struct device *dev)
+{
+#ifdef __SMP__
+	skfddi_priv *bp = PRIV(dev);
+#endif
+	unsigned long Flags;
+
+	spin_lock_irqsave(&bp->DriverLock, Flags);
+	skfp_ctl_set_multicast_list_wo_lock(dev);
+	spin_unlock_irqrestore(&bp->DriverLock, Flags);
+	return;
+}				// skfp_ctl_set_multicast_list
+
+
+
+static void skfp_ctl_set_multicast_list_wo_lock(struct device *dev)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+	struct dev_mc_list *dmi;	/* ptr to multicast addr entry */
+	int i;
+
+	/* Enable promiscuous mode, if necessary */
+	if (dev->flags & IFF_PROMISC) {
+		mac_drv_rx_mode(smc, RX_ENABLE_PROMISC);
+		PRINTK(KERN_INFO "PROMISCUOUS MODE ENABLED\n");
+	}
+	/* Else, update multicast address table */
+	else {
+		mac_drv_rx_mode(smc, RX_DISABLE_PROMISC);
+		PRINTK(KERN_INFO "PROMISCUOUS MODE DISABLED\n");
+
+		// Reset all MC addresses
+		mac_clear_multicast(smc);
+		mac_drv_rx_mode(smc, RX_DISABLE_ALLMULTI);
+
+		if (dev->flags & IFF_ALLMULTI) {
+			mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI);
+			PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n");
+		} else if (dev->mc_count > 0) {
+			if (dev->mc_count <= FPMAX_MULTICAST) {
+				/* use exact filtering */
+
+				// point to first multicast addr
+				dmi = dev->mc_list;
+
+				for (i = 0; i < dev->mc_count; i++) {
+					mac_add_multicast(smc,
+							  dmi->dmi_addr, 1);
+					PRINTK(KERN_INFO "ENABLE MC ADDRESS:");
+					PRINTK(" %02x %02x %02x ",
+					       dmi->dmi_addr[0],
+					       dmi->dmi_addr[1],
+					       dmi->dmi_addr[2]);
+					PRINTK("%02x %02x %02x\n",
+					       dmi->dmi_addr[3],
+					       dmi->dmi_addr[4],
+					       dmi->dmi_addr[5]);
+					dmi = dmi->next;
+				}	// for
+
+			} else {	// more MC addresses than HW supports
+
+				mac_drv_rx_mode(smc, RX_ENABLE_ALLMULTI);
+				PRINTK(KERN_INFO "ENABLE ALL MC ADDRESSES\n");
+			}
+		} else {	// no MC addresses
+
+			PRINTK(KERN_INFO "DISABLE ALL MC ADDRESSES\n");
+		}
+
+		/* Update adapter filters */
+		mac_update_multicast(smc);
+	}
+	return;
+}				// skfp_ctl_set_multicast_list_wo_lock
+
+
+/*
+ * ===========================
+ * = skfp_ctl_set_mac_address =
+ * ===========================
+ *   
+ * Overview:
+ *   set new mac address on adapter and update dev_addr field in device table.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   dev  - pointer to device information
+ *   addr - pointer to sockaddr structure containing unicast address to set
+ *
+ * Assumptions:
+ *   The address pointed to by addr->sa_data is a valid unicast
+ *   address and is presented in canonical (LSB) format.
+ */
+static int skfp_ctl_set_mac_address(struct device *dev, void *addr)
+{
+	struct s_smc *smc = (struct s_smc *) dev->priv;
+	struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
+#ifdef __SMP__
+	skfddi_priv *bp = (skfddi_priv *) & smc->os;
+#endif
+	unsigned long Flags;
+
+
+	memcpy(dev->dev_addr, p_sockaddr->sa_data, FDDI_K_ALEN);
+	spin_lock_irqsave(&bp->DriverLock, Flags);
+	ResetAdapter(smc);
+	spin_unlock_irqrestore(&bp->DriverLock, Flags);
+
+	return (0);		/* always return zero */
+}				// skfp_ctl_set_mac_address
+
+
+/*
+ * ==============
+ * = skfp_ioctl =
+ * ==============
+ *   
+ * Overview:
+ *
+ * Perform IOCTL call functions here. Some are privileged operations and the
+ * effective uid is checked in those cases.
+ *  
+ * Returns:
+ *   status value
+ *   0 - success
+ *   other - failure
+ *       
+ * Arguments:
+ *   dev  - pointer to device information
+ *   rq - pointer to ioctl request structure
+ *   cmd - ?
+ *
+ */
+
+
+static int skfp_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+	skfddi_priv *lp = PRIV(dev);
+	struct s_skfp_ioctl ioc;
+	int status = 0;
+
+	copy_from_user(&ioc, rq->ifr_data, sizeof(struct s_skfp_ioctl));
+	switch (ioc.cmd) {
+	case SKFP_GET_STATS:	/* Get the driver statistics */
+		ioc.len = sizeof(lp->MacStat);
+		copy_to_user(ioc.data, skfp_ctl_get_stats(dev), ioc.len);
+		break;
+	case SKFP_CLR_STATS:	/* Zero out the driver statistics */
+		if (suser()) {
+			memset(&lp->MacStat, 0, sizeof(lp->MacStat));
+		} else {
+			status = -EPERM;
+		}
+		break;
+	default:
+		printk("ioctl for %s: unknow cmd: %04x\n", dev->name, ioc.cmd);
+	}			// switch
+
+	return status;
+}				// skfp_ioctl
+
+
+/*
+ * =====================
+ * = skfp_send_pkt     =
+ * =====================
+ *   
+ * Overview:
+ *   Queues a packet for transmission and try to transmit it.
+ *  
+ * Returns:
+ *   Condition code
+ *       
+ * Arguments:
+ *   skb - pointer to sk_buff to queue for transmission
+ *   dev - pointer to device information
+ *
+ * Functional Description:
+ *   Here we assume that an incoming skb transmit request
+ *   is contained in a single physically contiguous buffer
+ *   in which the virtual address of the start of packet
+ *   (skb->data) can be converted to a physical address
+ *   by using virt_to_bus().
+ *
+ *   We have an internal queue for packets we can not send 
+ *   immediately. Packets in this queue can be given to the 
+ *   adapter if transmit buffers are freed.
+ *
+ *   We can't free the skb until after it's been DMA'd
+ *   out by the adapter, so we'll keep it in the driver and
+ *   return it in mac_drv_tx_complete.
+ *
+ * Return Codes:
+ *   0 - driver has queued and/or sent packet
+ *       1 - caller should requeue the sk_buff for later transmission
+ *
+ * Assumptions:
+ *   The entire packet is stored in one physically
+ *   contiguous buffer which is not cached and whose
+ *   32-bit physical address can be determined.
+ *
+ *   It's vital that this routine is NOT reentered for the
+ *   same board and that the OS is not in another section of
+ *   code (eg. skfp_interrupt) for the same board on a
+ *   different thread.
+ *
+ * Side Effects:
+ *   None
+ */
+static int skfp_send_pkt(struct sk_buff *skb, struct device *dev)
+{
+	skfddi_priv *bp = PRIV(dev);
+	unsigned long Flags;
+
+	PRINTK(KERN_INFO "skfp_send_pkt\n");
+	if (dev->interrupt)
+		return 1;
+
+	if (skb == NULL) {
+		mark_bh(NET_BH);
+		return 0;
+	}
+	if (dev->tbusy) {
+		// printk(KERN_INFO "%s transmit timeout\n", dev->name);
+		spin_lock_irqsave(&bp->DriverLock, Flags);
+		ResetAdapter((struct s_smc *) dev->priv);
+		spin_unlock_irqrestore(&bp->DriverLock, Flags);
+		return 1;
+	}
+	/*
+	 * Verify that incoming transmit request is OK
+	 *
+	 * Note: The packet size check is consistent with other
+	 *               Linux device drivers, although the correct packet
+	 *               size should be verified before calling the
+	 *               transmit routine.
+	 */
+
+	if (!(skb->len >= FDDI_K_LLC_ZLEN && skb->len <= FDDI_K_LLC_LEN)) {
+		bp->MacStat.tx_errors++;	/* bump error counter */
+		// dequeue packets from xmt queue and send them
+		mark_bh(NET_BH);
+		dev_kfree_skb(skb);
+		return (0);	/* return "success" */
+	}
+	if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
+		printk(KERN_INFO "%s: ERROR: Transmitter access conflict.\n",
+		       dev->name);
+		return 1;
+	}
+	if (bp->QueueSkb == 0) {	// return with tbusy set: queue full
+
+		// printk(KERN_INFO "%s: queue full\n", dev->name);
+		return 1;
+	}
+	bp->QueueSkb--;
+	skb_queue_tail(&bp->SendSkbQueue, skb);
+	send_queued_packets((struct s_smc *) dev->priv);
+	if (bp->QueueSkb > 0) {
+		dev->tbusy = 0;
+	}
+	dev->trans_start = jiffies;
+	return 0;
+
+}				// skfp_send_pkt
+
+
+/*
+ * =======================
+ * = send_queued_packets =
+ * =======================
+ *   
+ * Overview:
+ *   Send packets from the driver queue as long as there are some and
+ *   transmit resources are available.
+ *  
+ * Returns:
+ *   None
+ *       
+ * Arguments:
+ *   smc - pointer to smc (adapter) structure
+ *
+ * Functional Description:
+ *   Take a packet from queue if there is any. If not, then we are done.
+ *   Check if there are resources to send the packet. If not, requeue it
+ *   and exit. 
+ *   Set packet descriptor flags and give packet to adapter.
+ *   Check if any send resources can be freed (we do not use the
+ *   transmit complete interrupt).
+ */
+static void send_queued_packets(struct s_smc *smc)
+{
+	skfddi_priv *bp = (skfddi_priv *) & smc->os;
+	struct sk_buff *skb;
+	unsigned char fc;
+	int queue;
+	struct s_smt_fp_txd *txd;	// Current TxD.
+	static int log_counter=0;	// to avoid to much logging
+	unsigned long Flags;
+
+	int frame_status;	// HWM tx frame status.
+
+	PRINTK(KERN_INFO "send queued packets\n");
+	for (;;) {
+		// send first buffer from queue
+		skb = skb_dequeue(&bp->SendSkbQueue);
+
+		if (!skb) {
+			PRINTK(KERN_INFO "queue empty\n");
+			return;
+		}		// queue empty !
+
+		spin_lock_irqsave(&bp->DriverLock, Flags);
+		fc = skb->data[0];
+		queue = (fc & FC_SYNC_BIT) ? QUEUE_S : QUEUE_A0;
+#ifdef ESS
+		// Check if the frame may/must be sent as a synchronous frame.
+
+		if ((fc & ~(FC_SYNC_BIT | FC_LLC_PRIOR)) == FC_ASYNC_LLC) {
+			// It's an LLC frame.
+			if (!smc->ess.sync_bw_available)
+				fc &= ~FC_SYNC_BIT; // No bandwidth available.
+
+			else {	// Bandwidth is available.
+
+				if (smc->mib.fddiESSSynchTxMode) {
+					// Send as sync. frame.
+					fc |= FC_SYNC_BIT;
+				}
+			}
+		}
+#endif				// ESS
+		frame_status = hwm_tx_init(smc, fc, 1, skb->len, queue);
+
+		if ((frame_status & (LOC_TX | LAN_TX)) == 0) {
+			// Unable to send the frame.
+
+			if ((frame_status & RING_DOWN) != 0) {
+				// Ring is down.
+				PRINTK("Tx attempt while ring down.\n");
+			} else if ((frame_status & OUT_OF_TXD) != 0) {
+				if(log_counter == 0) {
+					// printk(KERN_INFO "%s: out of TXDs.\n",
+					//	bp->dev->name);
+				}
+				log_counter++;
+				if (log_counter >= 100000) 
+					log_counter = 0;
+			} else {
+				if(log_counter == 0) {
+					// printk(KERN_INFO "%s: out of transmit"
+					//	"resources\n",
+					//	bp->dev->name);
+				}
+				log_counter++;
+				if (log_counter >= 100000) 
+					log_counter = 0;
+			}
+
+			// Note: We will retry the operation as soon as
+			// transmit resources become available.
+			skb_queue_head(&bp->SendSkbQueue, skb);
+			spin_unlock_irqrestore(&bp->DriverLock, Flags);
+			return;	// Packet has been queued.
+
+		}		// if (unable to send frame)
+
+		bp->QueueSkb++;	// one packet less in local queue
+
+		// source address in packet ?
+		CheckSourceAddress(skb->data, smc->hw.fddi_canon_addr.a);
+
+		txd = (struct s_smt_fp_txd *) HWM_GET_CURR_TXD(smc, queue);
+
+		if (frame_status & LAN_TX) {
+			txd->txd_os.skb = skb;	// save skb
+
+		}
+		hwm_tx_frag(smc, skb->data, virt_to_bus(skb->data), skb->len,
+                      frame_status | FIRST_FRAG | LAST_FRAG | EN_IRQ_EOF);
+
+		if (!(frame_status & LAN_TX)) {		// local only frame
+			dev_kfree_skb(skb);
+		}
+		spin_unlock_irqrestore(&bp->DriverLock, Flags);
+	}			// for
+
+	return;			// never reached
+
+}				// send_queued_packets
+
+
+/************************
+ * 
+ * CheckSourceAddress
+ *
+ * Verify if the source address is set. Insert it if necessary.
+ *
+ ************************/
+void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr)
+{
+	unsigned char SRBit;
+
+	if ((((unsigned long) frame[1 + 6]) & ~0x01) != 0) // source routing bit
+
+		return;
+	if ((unsigned short) frame[1 + 10] != 0)
+		return;
+	SRBit = frame[1 + 6] & 0x01;
+	memcpy(&frame[1 + 6], hw_addr, 6);
+	frame[8] |= SRBit;
+}				// CheckSourceAddress
+
+
+/************************
+ *
+ *	ResetAdapter
+ *
+ *	Reset the adapter and bring it back to operational mode.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+static void ResetAdapter(struct s_smc *smc)
+{
+
+	PRINTK(KERN_INFO "[fddi: ResetAdapter]\n");
+
+	// Stop the adapter.
+
+	card_stop(smc);		// Stop all activity.
+
+	// Clear the transmit and receive descriptor queues.
+	mac_drv_clear_tx_queue(smc);
+	mac_drv_clear_rx_queue(smc);
+
+	// Restart the adapter.
+
+	smt_reset_defaults(smc, 1);	// Initialize the SMT module.
+
+	init_smt(smc, (smc->os.dev)->dev_addr);	// Initialize the hardware.
+
+	smt_online(smc, 1);	// Insert into the ring again.
+	STI_FBI();
+
+	// Restore original receive mode (multicasts, promiscuous, etc.).
+	skfp_ctl_set_multicast_list_wo_lock(smc->os.dev);
+}				// ResetAdapter
+
+
+//--------------- functions called by hardware module ----------------
+
+/************************
+ *
+ *	llc_restart_tx
+ *
+ *	The hardware driver calls this routine when the transmit complete
+ *	interrupt bits (end of frame) for the synchronous or asynchronous
+ *	queue is set.
+ *
+ * NOTE The hardware driver calls this function also if no packets are queued.
+ *	The routine must be able to handle this case.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void llc_restart_tx(struct s_smc *smc)
+{
+	skfddi_priv *bp = (skfddi_priv *) & smc->os;
+
+	PRINTK(KERN_INFO "[llc_restart_tx]\n");
+
+	// Try to send queued packets
+	spin_unlock(&bp->DriverLock);
+	send_queued_packets(smc);
+	spin_lock(&bp->DriverLock);
+	bp->dev->tbusy = 0;	// system may send again if it was blocked
+
+}				// llc_restart_tx
+
+
+/************************
+ *
+ *	mac_drv_get_space
+ *
+ *	The hardware module calls this function to allocate the memory
+ *	for the SMT MBufs if the define MB_OUTSIDE_SMC is specified.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	size - Size of memory in bytes to allocate.
+ * Out
+ *	!= 0	A pointer to the virtual address of the allocated memory.
+ *	== 0	Allocation error.
+ *
+ ************************/
+void *mac_drv_get_space(struct s_smc *smc, unsigned int size)
+{
+	void *virt;
+
+	PRINTK(KERN_INFO "mac_drv_get_space\n");
+	virt = (void *) (smc->os.SharedMemAddr + smc->os.SharedMemHeap);
+
+	if ((smc->os.SharedMemHeap + size) > smc->os.SharedMemSize) {
+		printk("Unexpected SMT memory size requested: %d\n", size);
+		return (NULL);
+	}
+	smc->os.SharedMemHeap += size;	// Move heap pointer.
+
+	PRINTK(KERN_INFO "mac_drv_get_space end\n");
+	PRINTK(KERN_INFO "virt addr: %lx\n", (ulong) virt);
+	PRINTK(KERN_INFO "bus  addr: %lx\n", (ulong) virt_to_bus(virt));
+	return (virt);
+}				// mac_drv_get_space
+
+
+/************************
+ *
+ *	mac_drv_get_desc_mem
+ *
+ *	This function is called by the hardware dependent module.
+ *	It allocates the memory for the RxD and TxD descriptors.
+ *
+ *	This memory must be non-cached, non-movable and non-swapable.
+ *	This memory should start at a physical page boundary.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	size - Size of memory in bytes to allocate.
+ * Out
+ *	!= 0	A pointer to the virtual address of the allocated memory.
+ *	== 0	Allocation error.
+ *
+ ************************/
+void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size)
+{
+
+	char *virt;
+
+	PRINTK(KERN_INFO "mac_drv_get_desc_mem\n");
+
+	// Descriptor memory must be aligned on 16-byte boundary.
+
+	virt = mac_drv_get_space(smc, size);
+
+	size = (u_int) ((0 - (unsigned long) virt) & 15);
+
+	PRINTK("Allocate %u bytes alignment gap ", size);
+	PRINTK("for descriptor memory.\n");
+
+	if (!mac_drv_get_space(smc, size)) {
+		printk("fddi: Unable to align descriptor memory.\n");
+		return (NULL);
+	}
+	return (virt + size);
+}				// mac_drv_get_desc_mem
+
+
+/************************
+ *
+ *	mac_drv_virt2phys
+ *
+ *	Get the physical address of a given virtual address.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	virt - A (virtual) pointer into our 'shared' memory area.
+ * Out
+ *	Physical address of the given virtual address.
+ *
+ ************************/
+unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt)
+{
+	return virt_to_bus(virt);
+}				// mac_drv_virt2phys
+
+
+/************************
+ *
+ *	dma_master
+ *
+ *	The HWM calls this function, when the driver leads through a DMA
+ *	transfer. If the OS-specific module must prepare the system hardware
+ *	for the DMA transfer, it should do it in this function.
+ *
+ *	The hardware module calls this dma_master if it wants to send an SMT
+ *	frame.  This means that the virt address passed in here is part of
+ *      the 'shared' memory area.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	virt - The virtual address of the data.
+ *
+ *	len - The length in bytes of the data.
+ *
+ *	flag - Indicates the transmit direction and the buffer type:
+ *		DMA_RD	(0x01)	system RAM ==> adapter buffer memory
+ *		DMA_WR	(0x02)	adapter buffer memory ==> system RAM
+ *		SMT_BUF (0x80)	SMT buffer
+ *
+ *	>> NOTE: SMT_BUF and DMA_RD are always set for PCI. <<
+ * Out
+ *	Returns the pyhsical address for the DMA transfer.
+ *
+ ************************/
+u_long dma_master(struct s_smc * smc, void *virt, int len, int flag)
+{
+	return (virt_to_bus(virt));
+}				// dma_master
+
+
+/************************
+ *
+ *	dma_complete
+ *
+ *	The hardware module calls this routine when it has completed a DMA
+ *	transfer. If the operating system dependant module has set up the DMA
+ *	channel via dma_master() (e.g. Windows NT or AIX) it should clean up
+ *	the DMA channel.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	descr - A pointer to a TxD or RxD, respectively.
+ *
+ *	flag - Indicates the DMA transfer direction / SMT buffer:
+ *		DMA_RD	(0x01)	system RAM ==> adapter buffer memory
+ *		DMA_WR	(0x02)	adapter buffer memory ==> system RAM
+ *		SMT_BUF (0x80)	SMT buffer (managed by HWM)
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag)
+{
+	return;
+}				// dma_complete
+
+
+/************************
+ *
+ *	mac_drv_tx_complete
+ *
+ *	Transmit of a packet is complete. Release the tx staging buffer.
+ *
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	txd - A pointer to the last TxD which is used by the frame.
+ * Out
+ *	Returns nothing.
+ *
+ ************************/
+void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd)
+{
+	struct sk_buff *skb;
+
+	PRINTK(KERN_INFO "entering mac_drv_tx_complete\n");
+	// Check if this TxD points to a skb
+
+	if (!(skb = txd->txd_os.skb)) {
+		PRINTK("TXD with no skb assigned.\n");
+		return;
+	}
+	txd->txd_os.skb = NULL;
+
+	smc->os.MacStat.tx_packets++;		// Count transmitted packets.
+	smc->os.MacStat.tx_bytes+=skb->len;	// Count bytes
+
+	// free the skb
+	dev_kfree_skb(skb);
+
+	PRINTK(KERN_INFO "leaving mac_drv_tx_complete\n");
+}				// mac_drv_tx_complete
+
+
+/************************
+ *
+ * dump packets to logfile
+ *
+ ************************/
+#ifdef DUMPPACKETS
+void dump_data(unsigned char *Data, int length)
+{
+	int i, j;
+	unsigned char s[255], sh[10];
+	if (length > 64) {
+		length = 64;
+	}
+	printk(KERN_INFO "---Packet start---\n");
+	for (i = 0, j = 0; i < length / 8; i++, j += 8)
+		printk(KERN_INFO "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+		       Data[j + 0], Data[j + 1], Data[j + 2], Data[j + 3],
+		       Data[j + 4], Data[j + 5], Data[j + 6], Data[j + 7]);
+	strcpy(s, "");
+	for (i = 0; i < length % 8; i++) {
+		sprintf(sh, "%02x ", Data[j + i]);
+		strcat(s, sh);
+	}
+	printk(KERN_INFO "%s\n", s);
+	printk(KERN_INFO "------------------\n");
+}				// dump_data
+#else
+#define dump_data(data,len)
+#endif				// DUMPPACKETS
+
+/************************
+ *
+ *	mac_drv_rx_complete
+ *
+ *	The hardware module calls this function if an LLC frame is received
+ *	in a receive buffer. Also the SMT, NSA, and directed beacon frames
+ *	from the network will be passed to the LLC layer by this function
+ *	if passing is enabled.
+ *
+ *	mac_drv_rx_complete forwards the frame to the LLC layer if it should
+ *	be received. It also fills the RxD ring with new receive buffers if
+ *	some can be queued.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	rxd - A pointer to the first RxD which is used by the receive frame.
+ *
+ *	frag_count - Count of RxDs used by the received frame.
+ *
+ *	len - Frame length.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+			 int frag_count, int len)
+{
+	skfddi_priv *bp = (skfddi_priv *) & smc->os;
+	struct sk_buff *skb;
+	unsigned char *virt, *cp;
+	unsigned short ri;
+	u_int RifLength;
+
+	PRINTK(KERN_INFO "entering mac_drv_rx_complete (len=%d)\n", len);
+	if (frag_count != 1) {	// This is not allowed to happen.
+
+		printk("fddi: ERROR: Multi-fragment receive!\n");
+		goto RequeueRxd;	// Re-use the given RXD(s).
+
+	}
+	skb = rxd->rxd_os.skb;
+	if (!skb) {
+		PRINTK(KERN_INFO "No skb in rxd\n");
+		smc->os.MacStat.rx_errors++;
+		goto RequeueRxd;
+	}
+	virt = skb->data;
+
+	dump_data(skb->data, len);
+
+	/*
+	 * FDDI Frame format:
+	 * +-------+-------+-------+------------+--------+------------+
+	 * | FC[1] | DA[6] | SA[6] | RIF[0..18] | LLC[3] | Data[0..n] |
+	 * +-------+-------+-------+------------+--------+------------+
+	 *
+	 * FC = Frame Control
+	 * DA = Destination Address
+	 * SA = Source Address
+	 * RIF = Routing Information Field
+	 * LLC = Logical Link Control
+	 */
+
+	// Remove Routing Information Field (RIF), if present.
+
+	if ((virt[1 + 6] & FDDI_RII) == 0)
+		RifLength = 0;
+	else {
+		int n;
+// goos: RIF removal has still to be tested
+		PRINTK(KERN_INFO "RIF found\n");
+		// Get RIF length from Routing Control (RC) field.
+		cp = virt + FDDI_MAC_HDR_LEN;	// Point behind MAC header.
+
+		ri = ntohs(*((unsigned short *) cp));
+		RifLength = ri & FDDI_RCF_LEN_MASK;
+		if (len < (int) (FDDI_MAC_HDR_LEN + RifLength)) {
+			printk("fddi: Invalid RIF.\n");
+			goto RequeueRxd;	// Discard the frame.
+
+		}
+		virt[1 + 6] &= ~FDDI_RII;	// Clear RII bit.
+		// regions overlap
+
+		virt = cp + RifLength;
+		for (n = FDDI_MAC_HDR_LEN; n; n--)
+			*--virt = *--cp;
+		// adjust sbd->data pointer
+		skb_pull(skb, RifLength);
+		len -= RifLength;
+		RifLength = 0;
+	}
+
+	// Count statistics.
+	smc->os.MacStat.rx_packets++;	// Count indicated receive packets.
+	smc->os.MacStat.rx_bytes+=len;	// Count bytes
+
+	// virt points to header again
+	if (virt[1] & 0x01) {	// Check group (multicast) bit.
+
+		smc->os.MacStat.multicast++;
+	}
+
+	// deliver frame to system
+	rxd->rxd_os.skb = NULL;
+	skb_trim(skb, len);
+	skb->protocol = fddi_type_trans(skb, bp->dev);
+	skb->dev = bp->dev;	/* pass up device pointer */
+
+	netif_rx(skb);
+
+	HWM_RX_CHECK(smc, RX_LOW_WATERMARK);
+	return;
+
+      RequeueRxd:
+	PRINTK(KERN_INFO "Rx: re-queue RXD.\n");
+	mac_drv_requeue_rxd(smc, rxd, frag_count);
+	smc->os.MacStat.rx_errors++;	// Count receive packets not indicated.
+
+}				// mac_drv_rx_complete
+
+
+/************************
+ *
+ *	mac_drv_requeue_rxd
+ *
+ *	The hardware module calls this function to request the OS-specific
+ *	module to queue the receive buffer(s) represented by the pointer
+ *	to the RxD and the frag_count into the receive queue again. This
+ *	buffer was filled with an invalid frame or an SMT frame.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	rxd - A pointer to the first RxD which is used by the receive frame.
+ *
+ *	frag_count - Count of RxDs used by the received frame.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+			 int frag_count)
+{
+	volatile struct s_smt_fp_rxd *next_rxd;
+	volatile struct s_smt_fp_rxd *src_rxd;
+	struct sk_buff *skb;
+	int MaxFrameSize;
+	unsigned char *v_addr;
+	unsigned long b_addr;
+
+	if (frag_count != 1)	// This is not allowed to happen.
+
+		printk("fddi: Multi-fragment requeue!\n");
+
+	MaxFrameSize = ((skfddi_priv *) & smc->os)->MaxFrameSize;
+	src_rxd = rxd;
+	for (; frag_count > 0; frag_count--) {
+		next_rxd = src_rxd->rxd_next;
+		rxd = HWM_GET_CURR_RXD(smc);
+
+		skb = src_rxd->rxd_os.skb;
+		if (skb == NULL) {	// this should not happen
+
+			PRINTK("Requeue with no skb in rxd!\n");
+			skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC);
+			if (skb) {
+				// we got a skb
+				rxd->rxd_os.skb = skb;
+				skb_reserve(skb, 3);
+				skb_put(skb, MaxFrameSize);
+				v_addr = skb->data;
+				b_addr = virt_to_bus(v_addr);
+			} else {
+				// no skb available, use local buffer
+				PRINTK("Queueing invalid buffer!\n");
+				rxd->rxd_os.skb = NULL;
+				v_addr = smc->os.LocalRxBuffer;
+				b_addr = virt_to_bus(v_addr);
+			}
+		} else {
+			// we use skb from old rxd
+			rxd->rxd_os.skb = skb;
+			v_addr = skb->data;
+			b_addr = virt_to_bus(v_addr);
+		}
+		hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize,
+			    FIRST_FRAG | LAST_FRAG);
+
+		src_rxd = next_rxd;
+	}
+}				// mac_drv_requeue_rxd
+
+
+/************************
+ *
+ *	mac_drv_fill_rxd
+ *
+ *	The hardware module calls this function at initialization time
+ *	to fill the RxD ring with receive buffers. It is also called by
+ *	mac_drv_rx_complete if rx_free is large enough to queue some new
+ *	receive buffers into the RxD ring. mac_drv_fill_rxd queues new
+ *	receive buffers as long as enough RxDs and receive buffers are
+ *	available.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void mac_drv_fill_rxd(struct s_smc *smc)
+{
+	int MaxFrameSize;
+	unsigned char *v_addr;
+	unsigned long b_addr;
+	struct sk_buff *skb;
+	volatile struct s_smt_fp_rxd *rxd;
+
+	PRINTK(KERN_INFO "entering mac_drv_fill_rxd\n");
+
+	// Walk through the list of free receive buffers, passing receive
+	// buffers to the HWM as long as RXDs are available.
+
+	MaxFrameSize = ((skfddi_priv *) & smc->os)->MaxFrameSize;
+	// Check if there is any RXD left.
+	while (HWM_GET_RX_FREE(smc) > 0) {
+		PRINTK(KERN_INFO ".\n");
+
+		rxd = HWM_GET_CURR_RXD(smc);
+		skb = alloc_skb(MaxFrameSize + 3, GFP_ATOMIC);
+		if (skb) {
+			// we got a skb
+			skb_reserve(skb, 3);
+			skb_put(skb, MaxFrameSize);
+			v_addr = skb->data;
+			b_addr = virt_to_bus(v_addr);
+		} else {
+			// no skb available, use local buffer
+			// System has run out of buffer memory, but we want to
+			// keep the receiver running in hope of better times.
+			// Multiple descriptors may point to this local buffer,
+			// so data in it must be considered invalid.
+			PRINTK("Queueing invalid buffer!\n");
+			v_addr = smc->os.LocalRxBuffer;
+			b_addr = virt_to_bus(v_addr);
+		}
+
+		rxd->rxd_os.skb = skb;
+
+		// Pass receive buffer to HWM.
+		hwm_rx_frag(smc, v_addr, b_addr, MaxFrameSize,
+			    FIRST_FRAG | LAST_FRAG);
+	}
+	PRINTK(KERN_INFO "leaving mac_drv_fill_rxd\n");
+}				// mac_drv_fill_rxd
+
+
+/************************
+ *
+ *	mac_drv_clear_rxd
+ *
+ *	The hardware module calls this function to release unused
+ *	receive buffers.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	rxd - A pointer to the first RxD which is used by the receive buffer.
+ *
+ *	frag_count - Count of RxDs used by the receive buffer.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
+		       int frag_count)
+{
+
+	struct sk_buff *skb;
+
+	PRINTK("entering mac_drv_clear_rxd\n");
+
+	if (frag_count != 1)	// This is not allowed to happen.
+
+		printk("fddi: Multi-fragment clear!\n");
+
+	for (; frag_count > 0; frag_count--) {
+		skb = rxd->rxd_os.skb;
+		if (skb != NULL) {
+			dev_kfree_skb(skb);
+			rxd->rxd_os.skb = NULL;
+		}
+		rxd = rxd->rxd_next;	// Next RXD.
+
+	}
+}				// mac_drv_clear_rxd
+
+
+/************************
+ *
+ *	mac_drv_rx_init
+ *
+ *	The hardware module calls this routine when an SMT or NSA frame of the
+ *	local SMT should be delivered to the LLC layer.
+ *
+ *	It is necessary to have this function, because there is no other way to
+ *	copy the contents of SMT MBufs into receive buffers.
+ *
+ *	mac_drv_rx_init allocates the required target memory for this frame,
+ *	and receives the frame fragment by fragment by calling mac_drv_rx_frag.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	len - The length (in bytes) of the received frame (FC, DA, SA, Data).
+ *
+ *	fc - The Frame Control field of the received frame.
+ *
+ *	look_ahead - A pointer to the lookahead data buffer (may be NULL).
+ *
+ *	la_len - The length of the lookahead data stored in the lookahead
+ *	buffer (may be zero).
+ * Out
+ *	Always returns zero (0).
+ *
+ ************************/
+int mac_drv_rx_init(struct s_smc *smc, int len, int fc,
+		    char *look_ahead, int la_len)
+{
+	struct sk_buff *skb;
+
+	PRINTK("entering mac_drv_rx_init(len=%d)\n", len);
+
+	// "Received" a SMT or NSA frame of the local SMT.
+
+	if (len != la_len || len < FDDI_MAC_HDR_LEN || !look_ahead) {
+		PRINTK("fddi: Discard invalid local SMT frame\n");
+		PRINTK("  len=%d, la_len=%d, (ULONG) look_ahead=%08lXh.\n",
+		       len, la_len, (unsigned long) look_ahead);
+		return (0);
+	}
+	skb = alloc_skb(len + 3, GFP_ATOMIC);
+	if (!skb) {
+		PRINTK("fddi: Local SMT: skb memory exhausted.\n");
+		return (0);
+	}
+	skb_reserve(skb, 3);
+	skb_put(skb, len);
+	memcpy(skb->data, look_ahead, len);
+
+	// deliver frame to system
+	skb->protocol = fddi_type_trans(skb, ((skfddi_priv *) & smc->os)->dev);
+	netif_rx(skb);
+
+	return (0);
+}				// mac_drv_rx_init
+
+
+/************************
+ *
+ *	smt_timer_poll
+ *
+ *	This routine is called periodically by the SMT module to clean up the
+ *	driver.
+ *
+ *	Return any queued frames back to the upper protocol layers if the ring
+ *	is down.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void smt_timer_poll(struct s_smc *smc)
+{
+}				// smt_timer_poll
+
+
+/************************
+ *
+ *	ring_status_indication
+ *
+ *	This function indicates a change of the ring state.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	status - The current ring status.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void ring_status_indication(struct s_smc *smc, u_long status)
+{
+	PRINTK("ring_status_indication( ");
+	if (status & RS_RES15)
+		PRINTK("RS_RES15 ");
+	if (status & RS_HARDERROR)
+		PRINTK("RS_HARDERROR ");
+	if (status & RS_SOFTERROR)
+		PRINTK("RS_SOFTERROR ");
+	if (status & RS_BEACON)
+		PRINTK("RS_BEACON ");
+	if (status & RS_PATHTEST)
+		PRINTK("RS_PATHTEST ");
+	if (status & RS_SELFTEST)
+		PRINTK("RS_SELFTEST ");
+	if (status & RS_RES9)
+		PRINTK("RS_RES9 ");
+	if (status & RS_DISCONNECT)
+		PRINTK("RS_DISCONNECT ");
+	if (status & RS_RES7)
+		PRINTK("RS_RES7 ");
+	if (status & RS_DUPADDR)
+		PRINTK("RS_DUPADDR ");
+	if (status & RS_NORINGOP)
+		PRINTK("RS_NORINGOP ");
+	if (status & RS_VERSION)
+		PRINTK("RS_VERSION ");
+	if (status & RS_STUCKBYPASSS)
+		PRINTK("RS_STUCKBYPASSS ");
+	if (status & RS_EVENT)
+		PRINTK("RS_EVENT ");
+	if (status & RS_RINGOPCHANGE)
+		PRINTK("RS_RINGOPCHANGE ");
+	if (status & RS_RES0)
+		PRINTK("RS_RES0 ");
+	PRINTK("]\n");
+}				// ring_status_indication
+
+
+/************************
+ *
+ *	smt_get_time
+ *
+ *	Gets the current time from the system.
+ * Args
+ *	None.
+ * Out
+ *	The current time in TICKS_PER_SECOND.
+ *
+ *	TICKS_PER_SECOND has the unit 'count of timer ticks per second'. It is
+ *	defined in "targetos.h". The definition of TICKS_PER_SECOND must comply
+ *	to the time returned by smt_get_time().
+ *
+ ************************/
+unsigned long smt_get_time(void)
+{
+	return jiffies;
+}				// smt_get_time
+
+
+/************************
+ *
+ *	smt_stat_counter
+ *
+ *	Status counter update (ring_op, fifo full).
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	stat -	= 0: A ring operational change occurred.
+ *		= 1: The FORMAC FIFO buffer is full / FIFO overflow.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void smt_stat_counter(struct s_smc *smc, int stat)
+{
+//      BOOLEAN RingIsUp ;
+
+	PRINTK(KERN_INFO "smt_stat_counter\n");
+	switch (stat) {
+	case 0:
+		PRINTK(KERN_INFO "Ring operational change.\n");
+		break;
+	case 1:
+		PRINTK(KERN_INFO "Receive fifo overflow.\n");
+		smc->os.MacStat.rx_errors++;
+		break;
+	default:
+		PRINTK(KERN_INFO "Unknown status (%d).\n", stat);
+		break;
+	}
+}				// smt_stat_counter
+
+
+/************************
+ *
+ *	cfm_state_change
+ *
+ *	Sets CFM state in custom statistics.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	c_state - Possible values are:
+ *
+ *		EC0_OUT, EC1_IN, EC2_TRACE, EC3_LEAVE, EC4_PATH_TEST,
+ *		EC5_INSERT, EC6_CHECK, EC7_DEINSERT
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void cfm_state_change(struct s_smc *smc, int c_state)
+{
+#ifdef DRIVERDEBUG
+	char *s;
+
+	switch (c_state) {
+	case SC0_ISOLATED:
+		s = "SC0_ISOLATED";
+		break;
+	case SC1_WRAP_A:
+		s = "SC1_WRAP_A";
+		break;
+	case SC2_WRAP_B:
+		s = "SC2_WRAP_B";
+		break;
+	case SC4_THRU_A:
+		s = "SC4_THRU_A";
+		break;
+	case SC5_THRU_B:
+		s = "SC5_THRU_B";
+		break;
+	case SC7_WRAP_S:
+		s = "SC7_WRAP_S";
+		break;
+	case SC9_C_WRAP_A:
+		s = "SC9_C_WRAP_A";
+		break;
+	case SC10_C_WRAP_B:
+		s = "SC10_C_WRAP_B";
+		break;
+	case SC11_C_WRAP_S:
+		s = "SC11_C_WRAP_S";
+		break;
+	default:
+		PRINTK(KERN_INFO "cfm_state_change: unknown %d\n", c_state);
+		return;
+	}
+	PRINTK(KERN_INFO "cfm_state_change: %s\n", s);
+#endif				// DRIVERDEBUG
+}				// cfm_state_change
+
+
+/************************
+ *
+ *	ecm_state_change
+ *
+ *	Sets ECM state in custom statistics.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	e_state - Possible values are:
+ *
+ *		SC0_ISOLATED, SC1_WRAP_A (5), SC2_WRAP_B (6), SC4_THRU_A (12),
+ *		SC5_THRU_B (7), SC7_WRAP_S (8)
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void ecm_state_change(struct s_smc *smc, int e_state)
+{
+#ifdef DRIVERDEBUG
+	char *s;
+
+	switch (e_state) {
+	case EC0_OUT:
+		s = "EC0_OUT";
+		break;
+	case EC1_IN:
+		s = "EC1_IN";
+		break;
+	case EC2_TRACE:
+		s = "EC2_TRACE";
+		break;
+	case EC3_LEAVE:
+		s = "EC3_LEAVE";
+		break;
+	case EC4_PATH_TEST:
+		s = "EC4_PATH_TEST";
+		break;
+	case EC5_INSERT:
+		s = "EC5_INSERT";
+		break;
+	case EC6_CHECK:
+		s = "EC6_CHECK";
+		break;
+	case EC7_DEINSERT:
+		s = "EC7_DEINSERT";
+		break;
+	default:
+		s = "unknown";
+		break;
+	}
+	PRINTK(KERN_INFO "ecm_state_change: %s\n", s);
+#endif				//DRIVERDEBUG
+}				// ecm_state_change
+
+
+/************************
+ *
+ *	rmt_state_change
+ *
+ *	Sets RMT state in custom statistics.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ *
+ *	r_state - Possible values are:
+ *
+ *		RM0_ISOLATED, RM1_NON_OP, RM2_RING_OP, RM3_DETECT,
+ *		RM4_NON_OP_DUP, RM5_RING_OP_DUP, RM6_DIRECTED, RM7_TRACE
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void rmt_state_change(struct s_smc *smc, int r_state)
+{
+#ifdef DRIVERDEBUG
+	char *s;
+
+	switch (r_state) {
+	case RM0_ISOLATED:
+		s = "RM0_ISOLATED";
+		break;
+	case RM1_NON_OP:
+		s = "RM1_NON_OP - not operational";
+		break;
+	case RM2_RING_OP:
+		s = "RM2_RING_OP - ring operational";
+		break;
+	case RM3_DETECT:
+		s = "RM3_DETECT - detect dupl addresses";
+		break;
+	case RM4_NON_OP_DUP:
+		s = "RM4_NON_OP_DUP - dupl. addr detected";
+		break;
+	case RM5_RING_OP_DUP:
+		s = "RM5_RING_OP_DUP - ring oper. with dupl. addr";
+		break;
+	case RM6_DIRECTED:
+		s = "RM6_DIRECTED - sending directed beacons";
+		break;
+	case RM7_TRACE:
+		s = "RM7_TRACE - trace initiated";
+		break;
+	default:
+		s = "unknown";
+		break;
+	}
+	PRINTK(KERN_INFO "[rmt_state_change: %s]\n", s);
+#endif				// DRIVERDEBUG
+}				// rmt_state_change
+
+
+/************************
+ *
+ *	drv_reset_indication
+ *
+ *	This function is called by the SMT when it has detected a severe
+ *	hardware problem. The driver should perform a reset on the adapter
+ *	as soon as possible, but not from within this function.
+ * Args
+ *	smc - A pointer to the SMT context struct.
+ * Out
+ *	Nothing.
+ *
+ ************************/
+void drv_reset_indication(struct s_smc *smc)
+{
+	PRINTK(KERN_INFO "entering drv_reset_indication\n");
+
+	smc->os.ResetRequested = TRUE;	// Set flag.
+
+}				// drv_reset_indication
+
+
+
+//--------------- functions for use as a module ----------------
+
+#ifdef MODULE
+/************************
+ *
+ * Note now that module autoprobing is allowed under PCI. The
+ * IRQ lines will not be auto-detected; instead I'll rely on the BIOSes
+ * to "do the right thing".
+ *
+ ************************/
+#define LP(a) ((struct s_smc*)(a))
+static struct device *mdev = NULL;
+
+/************************
+ *
+ * init_module
+ *
+ *  If compiled as a module, find
+ *  adapters and initialize them.
+ *
+ ************************/
+int init_module(void)
+{
+	struct device *p;
+
+	PRINTK(KERN_INFO "FDDI init module\n");
+	if ((mdev = insert_device(NULL, skfp_probe)) == NULL)
+		return -ENOMEM;
+
+	for (p = mdev; p != NULL; p = LP(p->priv)->os.next_module) {
+		PRINTK(KERN_INFO "device to register: %s\n", p->name);
+		if (register_netdev(p) != 0) {
+			printk("skfddi init_module failed\n");
+			return -EIO;
+		}
+	}
+
+	PRINTK(KERN_INFO "+++++ exit with success +++++\n");
+	return 0;
+}				// init_module
+
+/************************
+ *
+ * cleanup_module
+ *
+ *  Release all resources claimed by this module.
+ *
+ ************************/
+void cleanup_module(void)
+{
+	PRINTK(KERN_INFO "cleanup_module\n");
+	while (mdev != NULL) {
+		mdev = unlink_modules(mdev);
+	}
+	return;
+}				// cleanup_module
+
+
+/************************
+ *
+ * unlink_modules
+ *
+ *  Unregister devices and release their memory.
+ *
+ ************************/
+static struct device *unlink_modules(struct device *p)
+{
+	struct device *next = NULL;
+
+	if (p->priv) {		/* Private areas allocated? */
+		struct s_smc *lp = (struct s_smc *) p->priv;
+
+		next = lp->os.next_module;
+
+		if (lp->os.SharedMemAddr) {
+			kfree(lp->os.SharedMemAddr);
+		}
+		release_region(p->base_addr, 
+			(lp->os.bus_type == SK_BUS_TYPE_PCI ? FP_IO_LEN : 0));
+	}
+	unregister_netdev(p);
+	printk("%s: unloaded\n", p->name);
+	kfree(p);		/* Free the device structure */
+
+	return next;
+}				// unlink_modules
+
+
+#endif				/* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/smt.c linux.18p8/drivers/net/skfp/smt.c
--- linux.vanilla/drivers/net/skfp/smt.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/smt.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,2225 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smt.c	2.43 98/11/23 (C) SK " ;
+#endif
+
+extern const u_char canonical[256] ;
+
+/*
+ * FC in SMbuf
+ */
+#define m_fc(mb)	((mb)->sm_data[0])
+
+#define SMT_TID_MAGIC	0x1f0a7b3c
+
+#ifdef	DEBUG
+static const char *const smt_type_name[] = {
+	"SMT_00??", "SMT_INFO", "SMT_02??", "SMT_03??",
+	"SMT_04??", "SMT_05??", "SMT_06??", "SMT_07??",
+	"SMT_08??", "SMT_09??", "SMT_0A??", "SMT_0B??",
+	"SMT_0C??", "SMT_0D??", "SMT_0E??", "SMT_NSA"
+} ;
+
+static const char *const smt_class_name[] = {
+	"UNKNOWN","NIF","SIF_CONFIG","SIF_OPER","ECF","RAF","RDF",
+	"SRF","PMF_GET","PMF_SET","ESF"
+} ;
+#endif
+#define LAST_CLASS	(SMT_PMF_SET)
+
+static const struct fddi_addr SMT_Unknown = {
+	{ 0,0,0x1f,0,0,0 }
+} ;
+
+/*
+ * external variables
+ */
+extern const struct fddi_addr fddi_broadcast ;
+
+/*
+ * external functions
+ */
+int pcm_status_twisted() ;
+void pcm_status_state() ;
+int pcm_status_type() ;
+
+extern SMbuf *smt_get_mbuf() ;
+
+#define EXPORT_PMF
+/*
+ * function prototypes
+ */
+u_long smt_get_tid() ;
+EXPORT_PMF SMbuf *smt_build_frame() ;
+EXPORT_PMF void *sm_to_para() ;
+#ifdef	LITTLE_ENDIAN
+static int smt_swap_short() ;
+#endif
+static int mac_index() ;
+static int phy_index() ;
+static int mac_con_resource_index() ;
+static int phy_con_resource_index() ;
+EXPORT_PMF void smt_send_frame() ;
+EXPORT_PMF void smt_set_timestamp() ;
+static void smt_send_rdf() ;
+static void smt_send_nif() ;
+static void smt_send_ecf() ;
+static void smt_echo_test() ;
+static void smt_send_sif_config() ;
+static void smt_send_sif_operation() ;
+EXPORT_PMF void smt_swap_para() ;
+#ifdef LITTLE_ENDIAN
+static void smt_string_swap() ;
+#endif
+static void smt_add_frame_len() ;
+static void smt_fill_una() ;
+static void smt_fill_sde() ;
+static void smt_fill_state() ;
+static void smt_fill_timestamp() ;
+static void smt_fill_policy() ;
+static void smt_fill_latency() ;
+static void smt_fill_neighbor() ;
+static int  smt_fill_path() ;
+static void smt_fill_mac_status() ;
+static void smt_fill_lem() ;
+static void smt_fill_version() ;
+static void smt_fill_fsc() ;
+static void smt_fill_mac_counter() ;
+static void smt_fill_mac_fnc() ;
+static void smt_fill_manufacturer() ;
+static void smt_fill_user() ;
+static void smt_fill_setcount() ;
+static void smt_fill_echo() ;
+int smt_check_para() ;
+
+void smt_clear_una_dna() ;
+static void smt_clear_old_una_dna() ;
+#ifdef	CONCENTRATOR
+static int entity_to_index() ;
+#endif
+static void update_dac() ;
+static int div_ratio() ;
+#ifdef  USE_CAN_ADDR
+void	hwm_conv_can() ;
+#else
+#define		hwm_conv_can(smc,data,len)
+#endif
+
+/*
+ * list of mandatory paras in frames
+ */
+static const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ;
+
+/*
+ * init SMT agent
+ */
+void smt_agent_init(smc)
+struct s_smc *smc ;
+{
+	int		i ;
+
+	/*
+	 * get MAC address
+	 */
+	smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ;
+
+	/*
+	 * get OUI address from driver (bia == built-in-address)
+	 */
+	smc->mib.fddiSMTStationId.sid_oem[0] = 0 ;
+	smc->mib.fddiSMTStationId.sid_oem[1] = 0 ;
+	driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ;
+	for (i = 0 ; i < 6 ; i ++) {
+		smc->mib.fddiSMTStationId.sid_node.a[i] =
+			canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ;
+	}
+	smc->mib.fddiSMTManufacturerData[0] =
+		smc->mib.fddiSMTStationId.sid_node.a[0] ;
+	smc->mib.fddiSMTManufacturerData[1] =
+		smc->mib.fddiSMTStationId.sid_node.a[1] ;
+	smc->mib.fddiSMTManufacturerData[2] =
+		smc->mib.fddiSMTStationId.sid_node.a[2] ;
+	smc->sm.smt_tid = 0 ;
+	smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ;
+	smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ;
+#ifndef	SLIM_SMT
+	smt_clear_una_dna(smc) ;
+	smt_clear_old_una_dna(smc) ;
+#endif
+	for (i = 0 ; i < SMT_MAX_TEST ; i++)
+		smc->sm.pend[i] = 0 ;
+	smc->sm.please_reconnect = 0 ;
+	smc->sm.uniq_ticks = 0 ;
+}
+
+/*
+ * SMT task
+ * forever
+ *	delay 30 seconds
+ *	send NIF
+ *	check tvu & tvd
+ * end
+ */
+void smt_agent_task(smc)
+struct s_smc *smc ;
+{
+	smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L,
+		EV_TOKEN(EVENT_SMT,SM_TIMER)) ;
+	DB_SMT("SMT agent task\n",0,0) ;
+}
+
+void smt_please_reconnect(smc,reconn_time)
+struct s_smc	*smc ;		/* Pointer to SMT context */
+int		reconn_time ;	/* Wait for reconnect time in seconds */
+{
+	/*
+	 * The please reconnect variable is used as a timer.
+	 * It is decremented each time smt_event is called.
+	 * This happens every second or when smt_force_irq is called.
+	 * Note: smt_force_irq () is called on some packet receives and
+	 *       when a multicast address is changed. Since nothing
+	 *       is received during the disconnect and the multicast
+	 *       address changes can be viewed as not very often and
+	 *       the timer runs out close to its given value
+	 *       (reconn_time).
+	 */
+	smc->sm.please_reconnect = reconn_time ;
+}
+
+#ifndef SMT_REAL_TOKEN_CT
+void smt_emulate_token_ct(smc, mac_index)
+struct s_smc	*smc;
+int		mac_index;
+{
+	u_long	count;
+	u_long	time;
+
+
+	time = smt_get_time();
+	count =	((time - smc->sm.last_tok_time[mac_index]) *
+					100)/TICKS_PER_SECOND;
+
+	/*
+	 * Only when ring is up we will have a token count. The
+	 * flag is unfortunatly a single instance value. This
+	 * doesn't matter now, because we currently have only
+	 * one MAC instance.
+	 */
+	if (smc->hw.mac_ring_is_up){
+		smc->mib.m[mac_index].fddiMACToken_Ct += count;
+	}
+
+	/* Remember current time */
+	smc->sm.last_tok_time[mac_index] = time;
+
+}
+#endif
+
+/*ARGSUSED1*/
+void smt_event(smc,event)
+struct s_smc *smc ;
+int event ;
+{
+	u_long		time ;
+#ifndef SMT_REAL_TOKEN_CT
+	int		i ;
+#endif
+
+
+	if (smc->sm.please_reconnect) {
+		smc->sm.please_reconnect -- ;
+		if (smc->sm.please_reconnect == 0) {
+			/* Counted down */
+			queue_event(smc,EVENT_ECM,EC_CONNECT) ;
+		}
+	}
+
+	if (event == SM_FAST)
+		return ;
+
+	/*
+	 * timer for periodic cleanup in driver
+	 * reset and start the watchdog (FM2)
+	 * ESS timer
+	 * SBA timer
+	 */
+	smt_timer_poll(smc) ;
+	smt_start_watchdog(smc) ;
+#ifndef	SLIM_SMT
+#ifndef BOOT
+#ifdef	ESS
+	ess_timer_poll(smc) ;
+#endif
+#endif
+#ifdef	SBA
+	sba_timer_poll(smc) ;
+#endif
+
+	smt_srf_event(smc,0,0,0) ;
+
+#endif	/* no SLIM_SMT */
+
+	time = smt_get_time() ;
+
+	if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) {
+		/*
+		 * Use 8 sec. for the time intervall, it simplifies the
+		 * LER estimation.
+		 */
+		struct fddi_mib_m	*mib ;
+		u_long			upper ;
+		u_long			lower ;
+		int			cond ;
+		int			port;
+		struct s_phy		*phy ;
+		/*
+		 * calculate LEM bit error rate
+		 */
+		sm_lem_evaluate(smc) ;
+		smc->sm.smt_last_lem = time ;
+
+		/*
+		 * check conditions
+		 */
+#ifndef	SLIM_SMT
+		mac_update_counter(smc) ;
+		mib = smc->mib.m ;
+		upper =
+		(mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) +
+		(mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ;
+		lower =
+		(mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) +
+		(mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ;
+		mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ;
+
+		cond =
+			((!mib->fddiMACFrameErrorThreshold &&
+			mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) ||
+			(mib->fddiMACFrameErrorRatio >
+			mib->fddiMACFrameErrorThreshold)) ;
+
+		if (cond != mib->fddiMACFrameErrorFlag)
+			smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR,
+				INDEX_MAC,cond) ;
+
+		upper =
+		(mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ;
+		lower =
+		upper +
+		(mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ;
+		mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ;
+
+		cond =
+			((!mib->fddiMACNotCopiedThreshold &&
+			mib->fddiMACNotCopied_Ct !=
+				mib->fddiMACOld_NotCopied_Ct)||
+			(mib->fddiMACNotCopiedRatio >
+			mib->fddiMACNotCopiedThreshold)) ;
+
+		if (cond != mib->fddiMACNotCopiedFlag)
+			smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED,
+				INDEX_MAC,cond) ;
+
+		/*
+		 * set old values
+		 */
+		mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ;
+		mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ;
+		mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ;
+		mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ;
+		mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ;
+
+		/*
+		 * Check port EBError Condition
+		 */
+		for (port = 0; port < NUMPHYS; port ++) {
+			phy = &smc->y[port] ;
+
+			if (!phy->mib->fddiPORTHardwarePresent) {
+				continue;
+			}
+
+			cond = (phy->mib->fddiPORTEBError_Ct -
+				phy->mib->fddiPORTOldEBError_Ct > 5) ;
+
+			/* If ratio is more than 5 in 8 seconds
+			 * Set the condition.
+			 */
+			smt_srf_event(smc,SMT_COND_PORT_EB_ERROR,
+				(int) (INDEX_PORT+ phy->np) ,cond) ;
+
+			/*
+			 * set old values
+			 */
+			phy->mib->fddiPORTOldEBError_Ct =
+				phy->mib->fddiPORTEBError_Ct ;
+		}
+
+#endif	/* no SLIM_SMT */
+	}
+
+#ifndef	SLIM_SMT
+
+	if (time - smc->sm.smt_last_notify >= (u_long)
+		(smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) {
+		/*
+		 * we can either send an announcement or a request
+		 * a request will trigger a reply so that we can update
+		 * our dna
+		 * note: same tid must be used until reply is received
+		 */
+		if (!smc->sm.pend[SMT_TID_NIF])
+			smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ;
+		smt_send_nif(smc,&fddi_broadcast,FC_SMT_NSA,
+			smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,0) ;
+		smc->sm.smt_last_notify = time ;
+	}
+
+	/*
+	 * check timer
+	 */
+	if (smc->sm.smt_tvu &&
+	    time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) {
+		DB_SMT("SMT : UNA expired\n",0,0) ;
+		smc->sm.smt_tvu = 0 ;
+
+		if (!is_equal(&smc->mib.m[MAC0].fddiMACUpstreamNbr,
+			&SMT_Unknown)){
+			/* Do not update unknown address */
+			smc->mib.m[MAC0].fddiMACOldUpstreamNbr=
+				smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+		}
+		smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
+		smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ;
+		/*
+		 * Make sure the fddiMACUNDA_Flag = FALSE is
+		 * included in the SRF so we don't generate
+		 * a seperate SRF for the deassertion of this
+		 * condition
+		 */
+		update_dac(smc,0) ;
+		smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+			INDEX_MAC,0) ;
+	}
+	if (smc->sm.smt_tvd &&
+	    time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) {
+		DB_SMT("SMT : DNA expired\n",0,0) ;
+		smc->sm.smt_tvd = 0 ;
+		if (!is_equal(&smc->mib.m[MAC0].fddiMACDownstreamNbr,
+			&SMT_Unknown)){
+			/* Do not update unknown address */
+			smc->mib.m[MAC0].fddiMACOldDownstreamNbr=
+				smc->mib.m[MAC0].fddiMACDownstreamNbr ;
+		}
+		smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
+		smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+			INDEX_MAC,0) ;
+	}
+
+#endif	/* no SLIM_SMT */
+
+#ifndef SMT_REAL_TOKEN_CT
+	/*
+	 * Token counter emulation section. If hardware supports the token
+	 * count, the token counter will be updated in mac_update_counter.
+	 */
+	for (i = MAC0; i < NUMMACS; i++ ){
+		if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){
+			smt_emulate_token_ct( smc, i );
+		}
+	}
+#endif
+
+	smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L,
+		EV_TOKEN(EVENT_SMT,SM_TIMER)) ;
+}
+
+static int div_ratio(upper,lower)
+u_long upper ;
+u_long lower ;
+{
+	if ((upper<<16L) < upper)
+		upper = 0xffff0000L ;
+	else
+		upper <<= 16L ;
+	if (!lower)
+		return(0) ;
+	return((int)(upper/lower)) ;
+}
+
+#ifndef	SLIM_SMT
+
+/*
+ * receive packet handler
+ */
+void smt_received_pack(smc,mb,fs)
+struct s_smc *smc ;
+SMbuf *mb ;
+int fs ;			/* frame status */
+{
+	struct smt_header	*sm ;
+	int			local ;
+
+	int			illegal = 0 ;
+
+	switch (m_fc(mb)) {
+	case FC_SMT_INFO :
+	case FC_SMT_LAN_LOC :
+	case FC_SMT_LOC :
+	case FC_SMT_NSA :
+		break ;
+	default :
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+
+	smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ;
+	sm = smtod(mb,struct smt_header *) ;
+	local = ((fs & L_INDICATOR) != 0) ;
+	hwm_conv_can(smc,(char *)sm,12) ;
+
+	/* check destination address */
+	if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) {
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+#if	0		/* for DUP recognition, do NOT filter them */
+	/* ignore loop back packets */
+	if (is_my_addr(smc,&sm->smt_source) && !local) {
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+#endif
+
+	smt_swap_para(sm,(int) mb->sm_len,1) ;
+	DB_SMT("SMT : received packet [%s] at 0x%x\n",
+		smt_type_name[m_fc(mb) & 0xf],sm) ;
+	DB_SMT("SMT : version %d, class %s\n",sm->smt_version,
+		smt_class_name[(sm->smt_class>LAST_CLASS)?0 : sm->smt_class]) ;
+
+#ifdef	SBA
+	/*
+	 * check if NSA frame
+	 */
+	if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF &&
+		(sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) {
+			smc->sba.sm = sm ;
+			sba(smc,NIF) ;
+	}
+#endif
+
+	/*
+	 * ignore any packet with NSA and A-indicator set
+	 */
+	if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) {
+		DB_SMT("SMT : ignoring NSA with A-indicator set from %s\n",
+			addr_to_string(&sm->smt_source),0) ;
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+
+	/*
+	 * ignore frames with illegal length
+	 */
+	if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) ||
+	    ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) {
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+
+	/*
+	 * check SMT version
+	 */
+	switch (sm->smt_class) {
+	case SMT_NIF :
+	case SMT_SIF_CONFIG :
+	case SMT_SIF_OPER :
+	case SMT_ECF :
+		if (sm->smt_version != SMT_VID)
+			illegal = 1;
+		break ;
+	default :
+		if (sm->smt_version != SMT_VID_2)
+			illegal = 1;
+		break ;
+	}
+	if (illegal) {
+		DB_SMT("SMT : version = %d, dest = %s\n",
+			sm->smt_version,addr_to_string(&sm->smt_source)) ;
+		smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_VERSION,local) ;
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+	if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) ||
+	    ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) {
+		DB_SMT("SMT: info length error, len = %d\n",sm->smt_len,0) ;
+		smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,local) ;
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+	switch (sm->smt_class) {
+	case SMT_NIF :
+		if (smt_check_para(smc,sm,plist_nif)) {
+			DB_SMT("SMT: NIF with para problem, ignoring\n",0,0) ;
+			break ;
+		} ;
+		switch (sm->smt_type) {
+		case SMT_ANNOUNCE :
+		case SMT_REQUEST :
+			if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA
+				&& is_broadcast(&sm->smt_dest)) {
+				struct smt_p_state	*st ;
+
+				/* set my UNA */
+				if (!is_equal(
+					&smc->mib.m[MAC0].fddiMACUpstreamNbr,
+					&sm->smt_source)) {
+					DB_SMT("SMT : updated my UNA = %s\n",
+					addr_to_string(&sm->smt_source),0) ;
+					if (!is_equal(&smc->mib.m[MAC0].
+					    fddiMACUpstreamNbr,&SMT_Unknown)){
+					 /* Do not update unknown address */
+					 smc->mib.m[MAC0].fddiMACOldUpstreamNbr=
+					 smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+					}
+
+					smc->mib.m[MAC0].fddiMACUpstreamNbr =
+						sm->smt_source ;
+					smt_srf_event(smc,
+						SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+						INDEX_MAC,0) ;
+					smt_echo_test(smc,0) ;
+				}
+				smc->sm.smt_tvu = smt_get_time() ;
+				st = (struct smt_p_state *)
+					sm_to_para(smc,sm,SMT_P_STATE) ;
+				if (st) {
+					smc->mib.m[MAC0].fddiMACUNDA_Flag =
+					(st->st_dupl_addr & SMT_ST_MY_DUPA) ?
+					TRUE : FALSE ;
+					update_dac(smc,1) ;
+				}
+			}
+			if ((sm->smt_type == SMT_REQUEST) &&
+			    is_individual(&sm->smt_source) &&
+			    ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) ||
+			     (m_fc(mb) != FC_SMT_NSA))) {
+				DB_SMT("SMT : replying to NIF request %s\n",
+					addr_to_string(&sm->smt_source),0) ;
+				smt_send_nif(smc,&sm->smt_source,
+					FC_SMT_INFO,
+					sm->smt_tid,
+					SMT_REPLY,local) ;
+			}
+			break ;
+		case SMT_REPLY :
+			DB_SMT("SMT : received NIF response from %s\n",
+				addr_to_string(&sm->smt_source),0) ;
+			if (fs & A_INDICATOR) {
+				smc->sm.pend[SMT_TID_NIF] = 0 ;
+				DB_SMT("SMT : duplicate address\n",0,0) ;
+				smc->mib.m[MAC0].fddiMACDupAddressTest =
+					DA_FAILED ;
+				smc->r.dup_addr_test = DA_FAILED ;
+				queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
+				smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ;
+				update_dac(smc,1) ;
+				break ;
+			}
+			if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) {
+				smc->sm.pend[SMT_TID_NIF] = 0 ;
+				/* set my DNA */
+				if (!is_equal(
+					&smc->mib.m[MAC0].fddiMACDownstreamNbr,
+					&sm->smt_source)) {
+					DB_SMT("SMT : updated my DNA\n",0,0) ;
+					if (!is_equal(&smc->mib.m[MAC0].
+					 fddiMACDownstreamNbr, &SMT_Unknown)){
+					 /* Do not update unknown address */
+				smc->mib.m[MAC0].fddiMACOldDownstreamNbr =
+					 smc->mib.m[MAC0].fddiMACDownstreamNbr ;
+					}
+
+					smc->mib.m[MAC0].fddiMACDownstreamNbr =
+						sm->smt_source ;
+					smt_srf_event(smc,
+						SMT_EVENT_MAC_NEIGHBOR_CHANGE,
+						INDEX_MAC,0) ;
+					smt_echo_test(smc,1) ;
+				}
+				smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ;
+				update_dac(smc,1) ;
+				smc->sm.smt_tvd = smt_get_time() ;
+				smc->mib.m[MAC0].fddiMACDupAddressTest =
+					DA_PASSED ;
+				if (smc->r.dup_addr_test != DA_PASSED) {
+					smc->r.dup_addr_test = DA_PASSED ;
+					queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ;
+				}
+			}
+			else if (sm->smt_tid ==
+				smc->sm.pend[SMT_TID_NIF_TEST]) {
+				DB_SMT("SMT : NIF test TID ok\n",0,0) ;
+			}
+			else {
+				DB_SMT("SMT : expected TID %lx, got %lx\n",
+				smc->sm.pend[SMT_TID_NIF],sm->smt_tid) ;
+			}
+			break ;
+		default :
+			illegal = 2 ;
+			break ;
+		}
+		break ;
+	case SMT_SIF_CONFIG :	/* station information */
+		if (sm->smt_type != SMT_REQUEST)
+			break ;
+		DB_SMT("SMT : replying to SIF Config request from %s\n",
+			addr_to_string(&sm->smt_source),0) ;
+		smt_send_sif_config(smc,&sm->smt_source,sm->smt_tid,local) ;
+		break ;
+	case SMT_SIF_OPER :	/* station information */
+		if (sm->smt_type != SMT_REQUEST)
+			break ;
+		DB_SMT("SMT : replying to SIF Operation request from %s\n",
+			addr_to_string(&sm->smt_source),0) ;
+		smt_send_sif_operation(smc,&sm->smt_source,sm->smt_tid,local) ;
+		break ;
+	case SMT_ECF :		/* echo frame */
+		switch (sm->smt_type) {
+		case SMT_REPLY :
+			smc->mib.priv.fddiPRIVECF_Reply_Rx++ ;
+			DB_SMT("SMT: received ECF reply from %s\n",
+				addr_to_string(&sm->smt_source),0) ;
+			if (sm_to_para(smc,sm,SMT_P_ECHODATA) == 0) {
+				DB_SMT("SMT: ECHODATA missing\n",0,0) ;
+				break ;
+			}
+			if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) {
+				DB_SMT("SMT : ECF test TID ok\n",0,0) ;
+			}
+			else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) {
+				DB_SMT("SMT : ECF test UNA ok\n",0,0) ;
+			}
+			else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) {
+				DB_SMT("SMT : ECF test DNA ok\n",0,0) ;
+			}
+			else {
+				DB_SMT("SMT : expected TID %lx, got %lx\n",
+					smc->sm.pend[SMT_TID_ECF],
+					sm->smt_tid) ;
+			}
+			break ;
+		case SMT_REQUEST :
+			smc->mib.priv.fddiPRIVECF_Req_Rx++ ;
+			{
+			if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) {
+			DB_SMT("SMT: ECF with para problem,sending RDF\n",0,0) ;
+				smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,
+					local) ;
+				break ;
+			}
+			DB_SMT("SMT - sending ECF reply to %s\n",
+				addr_to_string(&sm->smt_source),0) ;
+
+			/* set destination addr.  & reply */
+			sm->smt_dest = sm->smt_source ;
+			sm->smt_type = SMT_REPLY ;
+			dump_smt(smc,sm,"ECF REPLY") ;
+			smc->mib.priv.fddiPRIVECF_Reply_Tx++ ;
+			smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+			return ;		/* DON'T free mbuf */
+			}
+		default :
+			illegal = 1 ;
+			break ;
+		}
+		break ;
+#ifndef	BOOT
+	case SMT_RAF :		/* resource allocation */
+#ifdef	ESS
+		DB_ESSN(2,"ESS: RAF frame received\n",0,0) ;
+		fs = ess_raf_received_pack(smc,mb,sm,fs) ;
+#endif
+
+#ifdef	SBA
+		DB_SBAN(2,"SBA: RAF frame received\n",0,0) ;
+		sba_raf_received_pack(smc,sm,fs) ;
+#endif
+		break ;
+	case SMT_RDF :		/* request denied */
+		smc->mib.priv.fddiPRIVRDF_Rx++ ;
+		break ;
+	case SMT_ESF :		/* extended service - not supported */
+		if (sm->smt_type == SMT_REQUEST) {
+			DB_SMT("SMT - received ESF, sending RDF\n",0,0) ;
+			smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ;
+		}
+		break ;
+	case SMT_PMF_GET :
+	case SMT_PMF_SET :
+		if (sm->smt_type != SMT_REQUEST)
+			break ;
+		/* update statistics */
+		if (sm->smt_class == SMT_PMF_GET)
+			smc->mib.priv.fddiPRIVPMF_Get_Rx++ ;
+		else
+			smc->mib.priv.fddiPRIVPMF_Set_Rx++ ;
+		/*
+		 * ignore PMF SET with I/G set
+		 */
+		if ((sm->smt_class == SMT_PMF_SET) &&
+			!is_individual(&sm->smt_dest)) {
+			DB_SMT("SMT: ignoring PMF-SET with I/G set\n",0,0) ;
+			break ;
+		}
+		smt_pmf_received_pack(smc,mb, local) ;
+		break ;
+	case SMT_SRF :
+		dump_smt(smc,sm,"SRF received") ;
+		break ;
+	default :
+		if (sm->smt_type != SMT_REQUEST)
+			break ;
+		/*
+		 * For frames with unknown class:
+		 * we need to send a RDF frame according to 8.1.3.1.1,
+		 * only if it is a REQUEST.
+		 */
+		DB_SMT("SMT : class = %d, send RDF to %s\n",
+			sm->smt_class, addr_to_string(&sm->smt_source)) ;
+
+		smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ;
+		break ;
+#endif
+	}
+	if (illegal) {
+		DB_SMT("SMT: discarding illegal frame, reason = %d\n",
+			illegal,0) ;
+	}
+	smt_free_mbuf(smc,mb) ;
+}
+
+static void update_dac(smc,report)
+struct s_smc *smc ;
+int report ;
+{
+	int	cond ;
+
+	cond = ( smc->mib.m[MAC0].fddiMACUNDA_Flag |
+		smc->mib.m[MAC0].fddiMACDA_Flag) != 0 ;
+	if (report && (cond != smc->mib.m[MAC0].fddiMACDuplicateAddressCond))
+		smt_srf_event(smc, SMT_COND_MAC_DUP_ADDR,INDEX_MAC,cond) ;
+	else
+		smc->mib.m[MAC0].fddiMACDuplicateAddressCond = cond ;
+}
+
+/*
+ * send SMT frame
+ *	set source address
+ *	set station ID
+ *	send frame
+ */
+EXPORT_PMF void smt_send_frame(smc,mb,fc,local)
+struct s_smc *smc ;
+SMbuf *mb ;			/* buffer to send */
+int fc ;			/* FC value */
+int local ;
+{
+	struct smt_header	*sm ;
+
+	if (!smc->r.sm_ma_avail && !local) {
+		smt_free_mbuf(smc,mb) ;
+		return ;
+	}
+	sm = smtod(mb,struct smt_header *) ;
+	sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ;
+	sm->smt_sid = smc->mib.fddiSMTStationId ;
+
+	smt_swap_para(sm,(int) mb->sm_len,0) ;		/* swap para & header */
+	hwm_conv_can(smc,(char *)sm,12) ;		/* convert SA and DA */
+	smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ;
+	smt_send_mbuf(smc,mb,local ? FC_SMT_LOC : fc) ;
+}
+
+/*
+ * generate and send RDF
+ */
+static void smt_send_rdf(smc,rej,fc,reason,local)
+struct s_smc *smc ;
+SMbuf	*rej ;			/* mbuf of offending frame */
+int	fc ;			/* FC of denied frame */
+int reason ;			/* reason code */
+int local ;
+{
+	SMbuf	*mb ;
+	struct smt_header	*sm ;	/* header of offending frame */
+	struct smt_rdf	*rdf ;
+	int		len ;
+	int		frame_len ;
+
+	sm = smtod(rej,struct smt_header *) ;
+	if (sm->smt_type != SMT_REQUEST)
+		return ;
+
+	DB_SMT("SMT: sending RDF to %s,reason = 0x%x\n",
+		addr_to_string(&sm->smt_source),reason) ;
+
+
+	/*
+	 * note: get framelength from MAC length, NOT from SMT header
+	 * smt header length is included in sm_len
+	 */
+	frame_len = rej->sm_len ;
+
+	if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf))))
+		return ;
+	rdf = smtod(mb,struct smt_rdf *) ;
+	rdf->smt.smt_tid = sm->smt_tid ;		/* use TID from sm */
+	rdf->smt.smt_dest = sm->smt_source ;		/* set dest = source */
+
+	/* set P12 */
+	rdf->reason.para.p_type = SMT_P_REASON ;
+	rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ;
+	rdf->reason.rdf_reason = reason ;
+
+	/* set P14 */
+	rdf->version.para.p_type = SMT_P_VERSION ;
+	rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ;
+	rdf->version.v_pad = 0 ;
+	rdf->version.v_n = 1 ;
+	rdf->version.v_index = 1 ;
+	rdf->version.v_version[0] = SMT_VID_2 ;
+	rdf->version.v_pad2 = 0 ;
+
+	/* set P13 */
+	if ((unsigned) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) +
+		2*sizeof(struct smt_header))
+		len = frame_len ;
+	else
+		len = SMT_MAX_INFO_LEN - sizeof(*rdf) +
+			2*sizeof(struct smt_header) ;
+	/* make length multiple of 4 */
+	len &= ~3 ;
+	rdf->refused.para.p_type = SMT_P_REFUSED ;
+	/* length of para is smt_frame + ref_fc */
+	rdf->refused.para.p_len = len + 4 ;
+	rdf->refused.ref_fc = fc ;
+
+	/* swap it back */
+	smt_swap_para(sm,frame_len,0) ;
+
+	memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ;
+
+	len -= sizeof(struct smt_header) ;
+	mb->sm_len += len ;
+	rdf->smt.smt_len += len ;
+
+	dump_smt(smc,(struct smt_header *)rdf,"RDF") ;
+	smc->mib.priv.fddiPRIVRDF_Tx++ ;
+	smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+}
+
+/*
+ * generate and send NIF
+ */
+static void smt_send_nif(smc,dest,fc,tid,type,local)
+struct s_smc *smc ;
+struct fddi_addr *dest ;		/* dest address */
+int fc ;				/* frame control */
+u_long tid ;				/* transaction id */
+int type ;				/* frame type */
+int local ;
+{
+	struct smt_nif	*nif ;
+	SMbuf		*mb ;
+
+	if (!(mb = smt_build_frame(smc,SMT_NIF,type,sizeof(struct smt_nif))))
+		return ;
+	nif = smtod(mb, struct smt_nif *) ;
+	smt_fill_una(smc,&nif->una) ;	/* set UNA */
+	smt_fill_sde(smc,&nif->sde) ;	/* set station descriptor */
+	smt_fill_state(smc,&nif->state) ;	/* set state information */
+#ifdef	SMT6_10
+	smt_fill_fsc(smc,&nif->fsc) ;	/* set frame status cap. */
+#endif
+	nif->smt.smt_dest = *dest ;	/* destination address */
+	nif->smt.smt_tid = tid ;	/* transaction ID */
+	dump_smt(smc,(struct smt_header *)nif,"NIF") ;
+	smt_send_frame(smc,mb,fc,local) ;
+}
+
+#ifdef	DEBUG
+/*
+ * send NIF request (test purpose)
+ */
+static void smt_send_nif_request(smc,dest)
+struct s_smc *smc ;
+struct fddi_addr *dest ;
+{
+	smc->sm.pend[SMT_TID_NIF_TEST] = smt_get_tid(smc) ;
+	smt_send_nif(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_NIF_TEST],
+		SMT_REQUEST,0) ;
+}
+
+/*
+ * send ECF request (test purpose)
+ */
+static void smt_send_ecf_request(smc,dest,len)
+struct s_smc *smc ;
+struct fddi_addr *dest ;
+int len ;
+{
+	smc->sm.pend[SMT_TID_ECF] = smt_get_tid(smc) ;
+	smt_send_ecf(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_ECF],
+		SMT_REQUEST,len) ;
+}
+#endif
+
+/*
+ * echo test
+ */
+static void smt_echo_test(smc,dna)
+struct s_smc *smc ;
+int dna ;
+{
+	u_long	tid ;
+
+	smc->sm.pend[dna ? SMT_TID_ECF_DNA : SMT_TID_ECF_UNA] =
+		tid = smt_get_tid(smc) ;
+	smt_send_ecf(smc, dna ?
+		&smc->mib.m[MAC0].fddiMACDownstreamNbr :
+		&smc->mib.m[MAC0].fddiMACUpstreamNbr,
+		FC_SMT_INFO,tid, SMT_REQUEST, (SMT_TEST_ECHO_LEN & ~3)-8) ;
+}
+
+/*
+ * generate and send ECF
+ */
+static void smt_send_ecf(smc,dest,fc,tid,type,len)
+struct s_smc *smc ;
+struct fddi_addr *dest ;		/* dest address */
+int fc ;				/* frame control */
+u_long tid ;				/* transaction id */
+int type ;				/* frame type */
+int len ;				/* frame length */
+{
+	struct smt_ecf	*ecf ;
+	SMbuf		*mb ;
+
+	if (!(mb = smt_build_frame(smc,SMT_ECF,type,SMT_ECF_LEN + len)))
+		return ;
+	ecf = smtod(mb, struct smt_ecf *) ;
+
+	smt_fill_echo(smc,&ecf->ec_echo,tid,len) ;	/* set ECHO */
+	ecf->smt.smt_dest = *dest ;	/* destination address */
+	ecf->smt.smt_tid = tid ;	/* transaction ID */
+	smc->mib.priv.fddiPRIVECF_Req_Tx++ ;
+	smt_send_frame(smc,mb,fc,0) ;
+}
+
+/*
+ * generate and send SIF config response
+ */
+
+static void smt_send_sif_config(smc,dest,tid,local)
+struct s_smc *smc ;
+struct fddi_addr *dest ;		/* dest address */
+u_long tid ;				/* transaction id */
+int local ;
+{
+	struct smt_sif_config	*sif ;
+	SMbuf			*mb ;
+	int			len ;
+	if (!(mb = smt_build_frame(smc,SMT_SIF_CONFIG,SMT_REPLY,
+		SIZEOF_SMT_SIF_CONFIG)))
+		return ;
+
+	sif = smtod(mb, struct smt_sif_config *) ;
+	smt_fill_timestamp(smc,&sif->ts) ;	/* set time stamp */
+	smt_fill_sde(smc,&sif->sde) ;		/* set station descriptor */
+	smt_fill_version(smc,&sif->version) ;	/* set version information */
+	smt_fill_state(smc,&sif->state) ;	/* set state information */
+	smt_fill_policy(smc,&sif->policy) ;	/* set station policy */
+	smt_fill_latency(smc,&sif->latency);	/* set station latency */
+	smt_fill_neighbor(smc,&sif->neighbor);	/* set station neighbor */
+	smt_fill_setcount(smc,&sif->setcount) ;	/* set count */
+	len = smt_fill_path(smc,&sif->path);	/* set station path descriptor*/
+	sif->smt.smt_dest = *dest ;		/* destination address */
+	sif->smt.smt_tid = tid ;		/* transaction ID */
+	smt_add_frame_len(mb,len) ;		/* adjust length fields */
+	dump_smt(smc,(struct smt_header *)sif,"SIF Configuration Reply") ;
+	smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+}
+
+/*
+ * generate and send SIF operation response
+ */
+
+static void smt_send_sif_operation(smc,dest,tid,local)
+struct s_smc *smc ;
+struct fddi_addr *dest ;		/* dest address */
+u_long tid ;				/* transaction id */
+int local ;
+{
+	struct smt_sif_operation *sif ;
+	SMbuf			*mb ;
+	int			ports ;
+	int			i ;
+
+	ports = NUMPHYS ;
+#ifndef	CONCENTRATOR
+	if (smc->s.sas == SMT_SAS)
+		ports = 1 ;
+#endif
+
+	if (!(mb = smt_build_frame(smc,SMT_SIF_OPER,SMT_REPLY,
+		SIZEOF_SMT_SIF_OPERATION+ports*sizeof(struct smt_p_lem))))
+		return ;
+	sif = smtod(mb, struct smt_sif_operation *) ;
+	smt_fill_timestamp(smc,&sif->ts) ;	/* set time stamp */
+	smt_fill_mac_status(smc,&sif->status) ; /* set mac status */
+	smt_fill_mac_counter(smc,&sif->mc) ; /* set mac counter field */
+	smt_fill_mac_fnc(smc,&sif->fnc) ; /* set frame not copied counter */
+	smt_fill_manufacturer(smc,&sif->man) ; /* set manufacturer field */
+	smt_fill_user(smc,&sif->user) ;		/* set user field */
+	smt_fill_setcount(smc,&sif->setcount) ;	/* set count */
+	/*
+	 * set link error mon information
+	 */
+	if (ports == 1) {
+		smt_fill_lem(smc,sif->lem,PS) ;
+	}
+	else {
+		for (i = 0 ; i < ports ; i++) {
+			smt_fill_lem(smc,&sif->lem[i],i) ;
+		}
+	}
+
+	sif->smt.smt_dest = *dest ;	/* destination address */
+	sif->smt.smt_tid = tid ;	/* transaction ID */
+	dump_smt(smc,(struct smt_header *)sif,"SIF Operation Reply") ;
+	smt_send_frame(smc,mb,FC_SMT_INFO,local) ;
+}
+
+/*
+ * get and initialize SMT frame
+ */
+EXPORT_PMF SMbuf *smt_build_frame(smc,class,type,length)
+struct s_smc *smc ;
+int class ;
+int type ;
+int length ;
+{
+	SMbuf			*mb ;
+	struct smt_header	*smt ;
+
+#if	0
+	if (!smc->r.sm_ma_avail) {
+		return(0) ;
+	}
+#endif
+	if (!(mb = smt_get_mbuf(smc)))
+		return(mb) ;
+
+	mb->sm_len = length ;
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_dest = fddi_broadcast ; /* set dest = broadcast */
+	smt->smt_class = class ;
+	smt->smt_type = type ;
+	switch (class) {
+	case SMT_NIF :
+	case SMT_SIF_CONFIG :
+	case SMT_SIF_OPER :
+	case SMT_ECF :
+		smt->smt_version = SMT_VID ;
+		break ;
+	default :
+		smt->smt_version = SMT_VID_2 ;
+		break ;
+	}
+	smt->smt_tid = smt_get_tid(smc) ;	/* set transaction ID */
+	smt->smt_pad = 0 ;
+	smt->smt_len = length - sizeof(struct smt_header) ;
+	return(mb) ;
+}
+
+static void smt_add_frame_len(mb,len)
+SMbuf *mb ;
+int len ;
+{
+	struct smt_header	*smt ;
+
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_len += len ;
+	mb->sm_len += len ;
+}
+
+
+
+/*
+ * fill values in UNA parameter
+ */
+static void smt_fill_una(smc,una)
+struct s_smc *smc ;
+struct smt_p_una *una ;
+{
+	SMTSETPARA(una,SMT_P_UNA) ;
+	una->una_pad = 0 ;
+	una->una_node = smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+}
+
+/*
+ * fill values in SDE parameter
+ */
+static void smt_fill_sde(smc,sde)
+struct s_smc *smc ;
+struct smt_p_sde *sde ;
+{
+	SMTSETPARA(sde,SMT_P_SDE) ;
+	sde->sde_non_master = smc->mib.fddiSMTNonMaster_Ct ;
+	sde->sde_master = smc->mib.fddiSMTMaster_Ct ;
+	sde->sde_mac_count = NUMMACS ;		/* only 1 MAC */
+#ifdef	CONCENTRATOR
+	sde->sde_type = SMT_SDE_CONCENTRATOR ;
+#else
+	sde->sde_type = SMT_SDE_STATION ;
+#endif
+}
+
+/*
+ * fill in values in station state parameter
+ */
+static void smt_fill_state(smc,state)
+struct s_smc *smc ;
+struct smt_p_state *state ;
+{
+	int	top ;
+	int	twist ;
+
+	SMTSETPARA(state,SMT_P_STATE) ;
+	state->st_pad = 0 ;
+
+	/* determine topology */
+	top = 0 ;
+	if (smc->mib.fddiSMTPeerWrapFlag) {
+		top |= SMT_ST_WRAPPED ;		/* state wrapped */
+	}
+#ifdef	CONCENTRATOR
+	if (cfm_status_unattached(smc)) {
+		top |= SMT_ST_UNATTACHED ;	/* unattached concentrator */
+	}
+#endif
+	if ((twist = pcm_status_twisted(smc)) & 1) {
+		top |= SMT_ST_TWISTED_A ;	/* twisted cable */
+	}
+	if (twist & 2) {
+		top |= SMT_ST_TWISTED_B ;	/* twisted cable */
+	}
+#ifdef	OPT_SRF
+	top |= SMT_ST_SRF ;
+#endif
+	if (pcm_rooted_station(smc))
+		top |= SMT_ST_ROOTED_S ;
+	if (smc->mib.a[0].fddiPATHSbaPayload != 0)
+		top |= SMT_ST_SYNC_SERVICE ;
+	state->st_topology = top ;
+	state->st_dupl_addr =
+		((smc->mib.m[MAC0].fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0 ) |
+		 (smc->mib.m[MAC0].fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0)) ;
+}
+
+/*
+ * fill values in timestamp parameter
+ */
+static void smt_fill_timestamp(smc,ts)
+struct s_smc *smc ;
+struct smt_p_timestamp *ts ;
+{
+
+	SMTSETPARA(ts,SMT_P_TIMESTAMP) ;
+	smt_set_timestamp(smc,ts->ts_time) ;
+}
+
+EXPORT_PMF void smt_set_timestamp(smc,p)
+struct s_smc *smc ;
+u_char *p ;
+{
+	u_long	time ;
+	u_long	utime ;
+
+	/*
+	 * timestamp is 64 bits long ; resolution is 80 nS
+	 * our clock resolution is 10mS
+	 * 10mS/80ns = 125000 ~ 2^17 = 131072
+	 */
+	utime = smt_get_time() ;
+	time = utime * 100 ;
+	time /= TICKS_PER_SECOND ;
+	p[0] = 0 ;
+	p[1] = (u_char)((time>>(8+8+8+8-1)) & 1) ;
+	p[2] = (u_char)(time>>(8+8+8-1)) ;
+	p[3] = (u_char)(time>>(8+8-1)) ;
+	p[4] = (u_char)(time>>(8-1)) ;
+	p[5] = (u_char)(time<<1) ;
+	p[6] = (u_char)(smc->sm.uniq_ticks>>8) ;
+	p[7] = (u_char)smc->sm.uniq_ticks ;
+	/*
+	 * make sure we don't wrap: restart whenever the upper digits change
+	 */
+	if (utime != smc->sm.uniq_time) {
+		smc->sm.uniq_ticks = 0 ;
+	}
+	smc->sm.uniq_ticks++ ;
+	smc->sm.uniq_time = utime ;
+}
+
+/*
+ * fill values in station policy parameter
+ */
+static void smt_fill_policy(smc,policy)
+struct s_smc *smc ;
+struct smt_p_policy *policy ;
+{
+	int	i ;
+	u_char	*map ;
+	u_short	in ;
+	u_short	out ;
+
+	/*
+	 * MIB para 101b (fddiSMTConnectionPolicy) coding
+	 * is different from 0005 coding
+	 */
+	static u_char	ansi_weirdness[16] = {
+		0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15
+	} ;
+	SMTSETPARA(policy,SMT_P_POLICY) ;
+
+	out = 0 ;
+	in = smc->mib.fddiSMTConnectionPolicy ;
+	for (i = 0, map = ansi_weirdness ; i < 16 ; i++) {
+		if (in & 1)
+			out |= (1<<*map) ;
+		in >>= 1 ;
+		map++ ;
+	}
+	policy->pl_config = smc->mib.fddiSMTConfigPolicy ;
+	policy->pl_connect = out ;
+}
+
+/*
+ * fill values in latency equivalent parameter
+ */
+static void smt_fill_latency(smc,latency)
+struct s_smc *smc ;
+struct smt_p_latency *latency ;
+{
+	SMTSETPARA(latency,SMT_P_LATENCY) ;
+
+	latency->lt_phyout_idx1 = phy_index(smc,0) ;
+	latency->lt_latency1 = 10 ;	/* in octets (byte clock) */
+	/*
+	 * note: latency has two phy entries by definition
+	 * for a SAS, the 2nd one is null
+	 */
+	if (smc->s.sas == SMT_DAS) {
+		latency->lt_phyout_idx2 = phy_index(smc,1) ;
+		latency->lt_latency2 = 10 ;	/* in octets (byte clock) */
+	}
+	else {
+		latency->lt_phyout_idx2 = 0 ;
+		latency->lt_latency2 = 0 ;
+	}
+}
+
+/*
+ * fill values in MAC neighbors parameter
+ */
+static void smt_fill_neighbor(smc,neighbor)
+struct s_smc *smc ;
+struct smt_p_neighbor *neighbor ;
+{
+	SMTSETPARA(neighbor,SMT_P_NEIGHBORS) ;
+
+	neighbor->nb_mib_index = INDEX_MAC ;
+	neighbor->nb_mac_index = mac_index(smc,1) ;
+	neighbor->nb_una = smc->mib.m[MAC0].fddiMACUpstreamNbr ;
+	neighbor->nb_dna = smc->mib.m[MAC0].fddiMACDownstreamNbr ;
+}
+
+/*
+ * fill values in path descriptor
+ */
+#ifdef	CONCENTRATOR
+#define ALLPHYS	NUMPHYS
+#else
+#define ALLPHYS	((smc->s.sas == SMT_SAS) ? 1 : 2)
+#endif
+
+static int smt_fill_path(smc,path)
+struct s_smc *smc ;
+struct smt_p_path *path ;
+{
+	SK_LOC_DECL(int,type) ;
+	SK_LOC_DECL(int,state) ;
+	SK_LOC_DECL(int,remote) ;
+	SK_LOC_DECL(int,mac) ;
+	int	len ;
+	int	p ;
+	int	physp ;
+	struct smt_phy_rec	*phy ;
+	struct smt_mac_rec	*pd_mac ;
+
+	len =	PARA_LEN +
+		sizeof(struct smt_mac_rec) * NUMMACS +
+		sizeof(struct smt_phy_rec) * ALLPHYS ;
+	path->para.p_type = SMT_P_PATH ;
+	path->para.p_len = len - PARA_LEN ;
+
+	/* PHYs */
+	for (p = 0,phy = path->pd_phy ; p < ALLPHYS ; p++, phy++) {
+		physp = p ;
+#ifndef	CONCENTRATOR
+		if (smc->s.sas == SMT_SAS)
+			physp = PS ;
+#endif
+		pcm_status_state(smc,physp,&type,&state,&remote,&mac) ;
+#ifdef	LITTLE_ENDIAN
+		phy->phy_mib_index = smt_swap_short((u_short)p+INDEX_PORT) ;
+#else
+		phy->phy_mib_index = p+INDEX_PORT ;
+#endif
+		phy->phy_type = type ;
+		phy->phy_connect_state = state ;
+		phy->phy_remote_type = remote ;
+		phy->phy_remote_mac = mac ;
+		phy->phy_resource_idx = phy_con_resource_index(smc,p) ;
+	}
+
+	/* MAC */
+	pd_mac = (struct smt_mac_rec *) phy ;
+	pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ;
+	pd_mac->mac_resource_idx = mac_con_resource_index(smc,1) ;
+	return(len) ;
+}
+
+/*
+ * fill values in mac status
+ */
+static void smt_fill_mac_status(smc,st)
+struct s_smc *smc ;
+struct smt_p_mac_status *st ;
+{
+	SMTSETPARA(st,SMT_P_MAC_STATUS) ;
+
+	st->st_mib_index = INDEX_MAC ;
+	st->st_mac_index = mac_index(smc,1) ;
+
+	mac_update_counter(smc) ;
+	/*
+	 * timer values are represented in SMT as 2's complement numbers
+	 * units :	internal :  2's complement BCLK
+	 */
+	st->st_t_req = smc->mib.m[MAC0].fddiMACT_Req ;
+	st->st_t_neg = smc->mib.m[MAC0].fddiMACT_Neg ;
+	st->st_t_max = smc->mib.m[MAC0].fddiMACT_Max ;
+	st->st_tvx_value = smc->mib.m[MAC0].fddiMACTvxValue ;
+	st->st_t_min = smc->mib.m[MAC0].fddiMACT_Min ;
+
+	st->st_sba = smc->mib.a[PATH0].fddiPATHSbaPayload ;
+	st->st_frame_ct = smc->mib.m[MAC0].fddiMACFrame_Ct ;
+	st->st_error_ct = smc->mib.m[MAC0].fddiMACError_Ct ;
+	st->st_lost_ct = smc->mib.m[MAC0].fddiMACLost_Ct ;
+}
+
+/*
+ * fill values in LEM status
+ */
+
+static void smt_fill_lem(smc,lem,phy)
+struct s_smc *smc ;
+struct smt_p_lem *lem ;
+int phy ;
+{
+	struct fddi_mib_p	*mib ;
+
+	mib = smc->y[phy].mib ;
+
+	SMTSETPARA(lem,SMT_P_LEM) ;
+	lem->lem_mib_index = phy+INDEX_PORT ;
+	lem->lem_phy_index = phy_index(smc,phy) ;
+	lem->lem_pad2 = 0 ;
+	lem->lem_cutoff = mib->fddiPORTLer_Cutoff ;
+	lem->lem_alarm = mib->fddiPORTLer_Alarm ;
+	/* long term bit error rate */
+	lem->lem_estimate = mib->fddiPORTLer_Estimate ;
+	/* # of rejected connections */
+	lem->lem_reject_ct = mib->fddiPORTLem_Reject_Ct ;
+	lem->lem_ct = mib->fddiPORTLem_Ct ;	/* total number of errors */
+}
+
+/*
+ * fill version parameter
+ */
+static void smt_fill_version(smc,vers)
+struct s_smc *smc ;
+struct smt_p_version *vers ;
+{
+	SK_UNUSED(smc) ;
+	SMTSETPARA(vers,SMT_P_VERSION) ;
+	vers->v_pad = 0 ;
+	vers->v_n = 1 ;				/* one version is enough .. */
+	vers->v_index = 1 ;
+	vers->v_version[0] = SMT_VID_2 ;
+	vers->v_pad2 = 0 ;
+}
+
+#ifdef	SMT6_10
+/*
+ * fill frame status capabilities
+ */
+/*
+ * note: this para 200B is NOT in swap table, because it's also set in
+ * PMF add_para
+ */
+static void smt_fill_fsc(smc,fsc)
+struct s_smc *smc ;
+struct smt_p_fsc *fsc ;
+{
+	SK_UNUSED(smc) ;
+	SMTSETPARA(fsc,SMT_P_FSC) ;
+	fsc->fsc_pad0 = 0 ;
+	fsc->fsc_mac_index = INDEX_MAC ;	/* this is MIB ; MIB is NOT
+						 * mac_index ()i !
+						 */
+	fsc->fsc_pad1 = 0 ;
+	fsc->fsc_value = FSC_TYPE0 ;		/* "normal" node */
+#ifdef	LITTLE_ENDIAN
+	fsc->fsc_mac_index = smt_swap_short(INDEX_MAC) ;
+	fsc->fsc_value = smt_swap_short(FSC_TYPE0) ;
+#endif
+}
+#endif
+
+/*
+ * fill mac counter field
+ */
+static void smt_fill_mac_counter(smc,mc)
+struct s_smc *smc ;
+struct smt_p_mac_counter *mc ;
+{
+	SMTSETPARA(mc,SMT_P_MAC_COUNTER) ;
+	mc->mc_mib_index = INDEX_MAC ;
+	mc->mc_index = mac_index(smc,1) ;
+	mc->mc_receive_ct = smc->mib.m[MAC0].fddiMACCopied_Ct ;
+	mc->mc_transmit_ct =  smc->mib.m[MAC0].fddiMACTransmit_Ct ;
+}
+
+/*
+ * fill mac frame not copied counter
+ */
+static void smt_fill_mac_fnc(smc,fnc)
+struct s_smc *smc ;
+struct smt_p_mac_fnc *fnc ;
+{
+	SMTSETPARA(fnc,SMT_P_MAC_FNC) ;
+	fnc->nc_mib_index = INDEX_MAC ;
+	fnc->nc_index = mac_index(smc,1) ;
+	fnc->nc_counter = smc->mib.m[MAC0].fddiMACNotCopied_Ct ;
+}
+
+
+/*
+ * fill manufacturer field
+ */
+static void smt_fill_manufacturer(smc,man)
+struct s_smc *smc ;
+struct smp_p_manufacturer *man ;
+{
+	SMTSETPARA(man,SMT_P_MANUFACTURER) ;
+	memcpy((char *) man->mf_data,
+		(char *) smc->mib.fddiSMTManufacturerData,
+		sizeof(man->mf_data)) ;
+}
+
+/*
+ * fill user field
+ */
+static void smt_fill_user(smc,user)
+struct s_smc *smc ;
+struct smp_p_user *user ;
+{
+	SMTSETPARA(user,SMT_P_USER) ;
+	memcpy((char *) user->us_data,
+		(char *) smc->mib.fddiSMTUserData,
+		sizeof(user->us_data)) ;
+}
+
+
+
+/*
+ * fill set count
+ */
+static void smt_fill_setcount(smc,setcount)
+struct s_smc *smc ;
+struct smt_p_setcount *setcount ;
+{
+	SK_UNUSED(smc) ;
+	SMTSETPARA(setcount,SMT_P_SETCOUNT) ;
+	setcount->count = smc->mib.fddiSMTSetCount.count ;
+	memcpy((char *)setcount->timestamp,
+		(char *)smc->mib.fddiSMTSetCount.timestamp,8) ;
+}
+
+/*
+ * fill echo data
+ */
+static void smt_fill_echo(smc,echo,seed,len)
+struct s_smc *smc ;
+struct smt_p_echo *echo ;
+u_long seed ;
+int len ;
+{
+
+	u_char	*p ;
+
+	SK_UNUSED(smc) ;
+	SMTSETPARA(echo,SMT_P_ECHODATA) ;
+	echo->para.p_len = len ;
+	for (p = echo->ec_data ; len ; len--) {
+		*p++ = (u_char) seed ;
+		seed += 13 ;
+	}
+}
+
+/*
+ * clear DNA and UNA
+ * called from CFM if configuration changes
+ */
+void smt_clear_una_dna(smc)
+struct s_smc *smc ;
+{
+	smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
+	smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
+}
+
+static void smt_clear_old_una_dna(smc)
+struct s_smc *smc ;
+{
+	smc->mib.m[MAC0].fddiMACOldUpstreamNbr = SMT_Unknown ;
+	smc->mib.m[MAC0].fddiMACOldDownstreamNbr = SMT_Unknown ;
+}
+
+u_long smt_get_tid(smc)
+struct s_smc *smc ;
+{
+	u_long	tid ;
+	while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0)
+		;
+	return(tid & 0x3fffffffL) ;
+}
+
+
+/*
+ * table of parameter lengths
+ */
+static const struct smt_pdef {
+	int	ptype ;
+	int	plen ;
+	const char	*pswap ;
+} smt_pdef[] = {
+	{ SMT_P_UNA,	sizeof(struct smt_p_una) ,
+		SWAP_SMT_P_UNA					} ,
+	{ SMT_P_SDE,	sizeof(struct smt_p_sde) ,
+		SWAP_SMT_P_SDE					} ,
+	{ SMT_P_STATE,	sizeof(struct smt_p_state) ,
+		SWAP_SMT_P_STATE				} ,
+	{ SMT_P_TIMESTAMP,sizeof(struct smt_p_timestamp) ,
+		SWAP_SMT_P_TIMESTAMP				} ,
+	{ SMT_P_POLICY,	sizeof(struct smt_p_policy) ,
+		SWAP_SMT_P_POLICY				} ,
+	{ SMT_P_LATENCY,	sizeof(struct smt_p_latency) ,
+		SWAP_SMT_P_LATENCY				} ,
+	{ SMT_P_NEIGHBORS,sizeof(struct smt_p_neighbor) ,
+		SWAP_SMT_P_NEIGHBORS				} ,
+	{ SMT_P_PATH,	sizeof(struct smt_p_path) ,
+		SWAP_SMT_P_PATH					} ,
+	{ SMT_P_MAC_STATUS,sizeof(struct smt_p_mac_status) ,
+		SWAP_SMT_P_MAC_STATUS				} ,
+	{ SMT_P_LEM,	sizeof(struct smt_p_lem) ,
+		SWAP_SMT_P_LEM					} ,
+	{ SMT_P_MAC_COUNTER,sizeof(struct smt_p_mac_counter) ,
+		SWAP_SMT_P_MAC_COUNTER				} ,
+	{ SMT_P_MAC_FNC,sizeof(struct smt_p_mac_fnc) ,
+		SWAP_SMT_P_MAC_FNC				} ,
+	{ SMT_P_PRIORITY,sizeof(struct smt_p_priority) ,
+		SWAP_SMT_P_PRIORITY				} ,
+	{ SMT_P_EB,sizeof(struct smt_p_eb) ,
+		SWAP_SMT_P_EB					} ,
+	{ SMT_P_MANUFACTURER,sizeof(struct smp_p_manufacturer) ,
+		SWAP_SMT_P_MANUFACTURER				} ,
+	{ SMT_P_REASON,	sizeof(struct smt_p_reason) ,
+		SWAP_SMT_P_REASON				} ,
+	{ SMT_P_REFUSED, sizeof(struct smt_p_refused) ,
+		SWAP_SMT_P_REFUSED				} ,
+	{ SMT_P_VERSION, sizeof(struct smt_p_version) ,
+		SWAP_SMT_P_VERSION				} ,
+#ifdef ESS
+	{ SMT_P0015, sizeof(struct smt_p_0015) , SWAP_SMT_P0015 } ,
+	{ SMT_P0016, sizeof(struct smt_p_0016) , SWAP_SMT_P0016 } ,
+	{ SMT_P0017, sizeof(struct smt_p_0017) , SWAP_SMT_P0017 } ,
+	{ SMT_P0018, sizeof(struct smt_p_0018) , SWAP_SMT_P0018 } ,
+	{ SMT_P0019, sizeof(struct smt_p_0019) , SWAP_SMT_P0019 } ,
+	{ SMT_P001A, sizeof(struct smt_p_001a) , SWAP_SMT_P001A } ,
+	{ SMT_P001B, sizeof(struct smt_p_001b) , SWAP_SMT_P001B } ,
+	{ SMT_P001C, sizeof(struct smt_p_001c) , SWAP_SMT_P001C } ,
+	{ SMT_P001D, sizeof(struct smt_p_001d) , SWAP_SMT_P001D } ,
+#endif
+#if	0
+	{ SMT_P_FSC,	sizeof(struct smt_p_fsc) ,
+		SWAP_SMT_P_FSC					} ,
+#endif
+
+	{ SMT_P_SETCOUNT,0,	SWAP_SMT_P_SETCOUNT		} ,
+	{ SMT_P1048,	0,	SWAP_SMT_P1048			} ,
+	{ SMT_P208C,	0,	SWAP_SMT_P208C			} ,
+	{ SMT_P208D,	0,	SWAP_SMT_P208D			} ,
+	{ SMT_P208E,	0,	SWAP_SMT_P208E			} ,
+	{ SMT_P208F,	0,	SWAP_SMT_P208F			} ,
+	{ SMT_P2090,	0,	SWAP_SMT_P2090			} ,
+#ifdef	ESS
+	{ SMT_P320B, sizeof(struct smt_p_320b) , SWAP_SMT_P320B } ,
+	{ SMT_P320F, sizeof(struct smt_p_320f) , SWAP_SMT_P320F } ,
+	{ SMT_P3210, sizeof(struct smt_p_3210) , SWAP_SMT_P3210 } ,
+#endif
+	{ SMT_P4050,	0,	SWAP_SMT_P4050			} ,
+	{ SMT_P4051,	0,	SWAP_SMT_P4051			} ,
+	{ SMT_P4052,	0,	SWAP_SMT_P4052			} ,
+	{ SMT_P4053,	0,	SWAP_SMT_P4053			} ,
+} ;
+
+#define N_SMT_PLEN	(sizeof(smt_pdef)/sizeof(smt_pdef[0]))
+
+int smt_check_para(smc,sm,list)
+struct s_smc *smc ;
+struct smt_header	*sm ;
+const u_short		list[] ;
+{
+	const u_short		*p = list ;
+	while (*p) {
+		if (!sm_to_para(smc,sm,(int) *p)) {
+			DB_SMT("SMT: smt_check_para - missing para %x\n",*p,0);
+			return(-1) ;
+		}
+		p++ ;
+	}
+	return(0) ;
+}
+
+EXPORT_PMF void *sm_to_para(smc,sm,para)
+struct s_smc *smc ;
+struct smt_header	*sm ;
+int para ;
+{
+	char	*p ;
+	int	len ;
+	int	plen ;
+	void	*found = 0 ;
+
+	SK_UNUSED(smc) ;
+
+	len = sm->smt_len ;
+	p = (char *)(sm+1) ;		/* pointer to info */
+	while (len > 0 ) {
+		if (((struct smt_para *)p)->p_type == para)
+			found = (void *) p ;
+		plen = ((struct smt_para *)p)->p_len + PARA_LEN ;
+		p += plen ;
+		len -= plen ;
+		if (len < 0) {
+			DB_SMT("SMT : sm_to_para - length error %d\n",plen,0) ;
+			return(0) ;
+		}
+		if ((plen & 3) && (para != SMT_P_ECHODATA)) {
+			DB_SMT("SMT : sm_to_para - odd length %d\n",plen,0) ;
+			return(0) ;
+		}
+		if (found)
+			return(found) ;
+	}
+	return(0) ;
+}
+
+int is_my_addr(smc,addr)
+struct s_smc *smc ;
+struct fddi_addr *addr ;
+{
+	return(*(short *)(&addr->a[0]) ==
+		*(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[0])
+	  && *(short *)(&addr->a[2]) ==
+		*(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[2])
+	  && *(short *)(&addr->a[4]) ==
+		*(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[4])) ;
+}
+
+int is_zero(addr)
+struct fddi_addr *addr ;
+{
+	return(*(short *)(&addr->a[0]) == 0 &&
+	       *(short *)(&addr->a[2]) == 0 &&
+	       *(short *)(&addr->a[4]) == 0 ) ;
+}
+
+int is_broadcast(addr)
+struct fddi_addr *addr ;
+{
+	return(*(u_short *)(&addr->a[0]) == 0xffff &&
+	       *(u_short *)(&addr->a[2]) == 0xffff &&
+	       *(u_short *)(&addr->a[4]) == 0xffff ) ;
+}
+
+int is_individual(addr)
+struct fddi_addr *addr ;
+{
+	return(!(addr->a[0] & GROUP_ADDR)) ;
+}
+
+int is_equal(addr1,addr2)
+struct fddi_addr *addr1 ;
+struct fddi_addr *addr2 ;
+{
+	return(*(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) &&
+	       *(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) &&
+	       *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]) ) ;
+}
+
+
+#if	0
+/*
+ * send ANTC data test frame
+ */
+void fddi_send_antc(smc,dest)
+struct s_smc *smc ;
+struct fddi_addr *dest ;
+{
+	SK_UNUSED(smc) ;
+	SK_UNUSED(dest) ;
+#if	0
+	SMbuf			*mb ;
+	struct smt_header	*smt ;
+	int			i ;
+	char			*p ;
+
+	mb = smt_get_mbuf() ;
+	mb->sm_len = 3000+12 ;
+	p = smtod(mb, char *) + 12 ;
+	for (i = 0 ; i < 3000 ; i++)
+		*p++ = 1 << (i&7) ;
+
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_dest = *dest ;
+	smt->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ;
+	smt_send_mbuf(smc,mb,FC_ASYNC_LLC) ;
+#endif
+}
+#endif
+
+#ifdef	DEBUG
+#define hextoasc(x)	"0123456789abcdef"[x]
+
+char *addr_to_string(addr)
+struct fddi_addr *addr ;
+{
+	int	i ;
+	static char	string[6*3] = "****" ;
+
+	for (i = 0 ; i < 6 ; i++) {
+		string[i*3] = hextoasc((addr->a[i]>>4)&0xf) ;
+		string[i*3+1] = hextoasc((addr->a[i])&0xf) ;
+		string[i*3+2] = ':' ;
+	}
+	string[5*3+2] = 0 ;
+	return(string) ;
+}
+#endif
+
+#ifdef	AM29K
+smt_ifconfig(argc,argv)
+int argc ;
+char *argv[] ;
+{
+	if (argc >= 2 && !strcmp(argv[0],"opt_bypass") &&
+	    !strcmp(argv[1],"yes")) {
+		smc->mib.fddiSMTBypassPresent = 1 ;
+		return(0) ;
+	}
+	return(amdfddi_config(0,argc,argv)) ;
+}
+#endif
+
+/*
+ * return static mac index
+ */
+static int mac_index(smc,mac)
+struct s_smc *smc ;
+int mac ;
+{
+	SK_UNUSED(mac) ;
+#ifdef	CONCENTRATOR
+	SK_UNUSED(smc) ;
+	return(NUMPHYS+1) ;
+#else
+	return((smc->s.sas == SMT_SAS) ? 2 : 3) ;
+#endif
+}
+
+/*
+ * return static phy index
+ */
+static int phy_index(smc,phy)
+struct s_smc *smc ;
+int phy ;
+{
+	SK_UNUSED(smc) ;
+	return(phy+1);
+}
+
+/*
+ * return dynamic mac connection resource index
+ */
+static int mac_con_resource_index(smc,mac)
+struct s_smc *smc ;
+int mac ;
+{
+#ifdef	CONCENTRATOR
+	SK_UNUSED(smc) ;
+	SK_UNUSED(mac) ;
+	return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_MAC))) ;
+#else
+	SK_UNUSED(mac) ;
+	switch (smc->mib.fddiSMTCF_State) {
+	case SC9_C_WRAP_A :
+	case SC5_THRU_B :
+	case SC11_C_WRAP_S :
+		return(1) ;
+	case SC10_C_WRAP_B :
+	case SC4_THRU_A :
+		return(2) ;
+	}
+	return(smc->s.sas == SMT_SAS ? 2 : 3) ;
+#endif
+}
+
+/*
+ * return dynamic phy connection resource index
+ */
+static int phy_con_resource_index(smc,phy)
+struct s_smc *smc ;
+int phy ;
+{
+#ifdef	CONCENTRATOR
+	return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_PHY(phy)))) ;
+#else
+	switch (smc->mib.fddiSMTCF_State) {
+	case SC9_C_WRAP_A :
+		return(phy == PA ? 3 : 2) ;
+	case SC10_C_WRAP_B :
+		return(phy == PA ? 1 : 3) ;
+	case SC4_THRU_A :
+		return(phy == PA ? 3 : 1) ;
+	case SC5_THRU_B :
+		return(phy == PA ? 2 : 3) ;
+	case SC11_C_WRAP_S :
+		return(2) ;
+	}
+	return(phy) ;
+#endif
+}
+
+#ifdef	CONCENTRATOR
+static int entity_to_index(smc,e)
+struct s_smc *smc ;
+int e ;
+{
+	if (e == ENTITY_MAC)
+		return(mac_index(smc,1)) ;
+	else
+		return(phy_index(smc,e - ENTITY_PHY(0))) ;
+}
+#endif
+
+#ifdef	LITTLE_ENDIAN
+static int smt_swap_short(s)
+u_short s ;
+{
+	return(((s>>8)&0xff)|((s&0xff)<<8)) ;
+}
+
+void smt_swap_para(sm,len,direction)
+struct smt_header *sm ;
+int len ;
+int direction ;			/* 0 encode 1 decode */
+{
+	struct smt_para	*pa ;
+	const  struct smt_pdef	*pd ;
+	char	*p ;
+	int	plen ;
+	int	type ;
+	int	i ;
+
+/*	printf("smt_swap_para sm %x len %d dir %d\n",
+		sm,len,direction) ;
+ */
+	smt_string_swap((char *)sm,SWAP_SMTHEADER,len) ;
+
+	/* swap args */
+	len -= sizeof(struct smt_header) ;
+
+	p = (char *) (sm + 1) ;
+	while (len > 0) {
+		pa = (struct smt_para *) p ;
+		plen = pa->p_len ;
+		type = pa->p_type ;
+		pa->p_type = smt_swap_short(pa->p_type) ;
+		pa->p_len = smt_swap_short(pa->p_len) ;
+		if (direction) {
+			plen = pa->p_len ;
+			type = pa->p_type ;
+		}
+		/*
+		 * note: paras can have 0 length !
+		 */
+		if (plen < 0)
+			break ;
+		plen += PARA_LEN ;
+		for (i = N_SMT_PLEN, pd = smt_pdef; i ; i--,pd++) {
+			if (pd->ptype == type)
+				break ;
+		}
+		if (i && pd->pswap) {
+			smt_string_swap(p+PARA_LEN,pd->pswap,len) ;
+		}
+		len -= plen ;
+		p += plen ;
+	}
+}
+
+static void smt_string_swap(data,format,len)
+char *data ;
+const char *format ;
+int len ;
+{
+	const char	*open_paren = 0 ;
+	int	x ;
+
+	while (len > 0  && *format) {
+		switch (*format) {
+		case '[' :
+			open_paren = format ;
+			break ;
+		case ']' :
+			format = open_paren ;
+			break ;
+		case '1' :
+		case '2' :
+		case '3' :
+		case '4' :
+		case '5' :
+		case '6' :
+		case '7' :
+		case '8' :
+		case '9' :
+			data  += *format - '0' ;
+			len   -= *format - '0' ;
+			break ;
+		case 'c':
+			data++ ;
+			len-- ;
+			break ;
+		case 's' :
+			x = data[0] ;
+			data[0] = data[1] ;
+			data[1] = x ;
+			data += 2 ;
+			len -= 2 ;
+			break ;
+		case 'l' :
+			x = data[0] ;
+			data[0] = data[3] ;
+			data[3] = x ;
+			x = data[1] ;
+			data[1] = data[2] ;
+			data[2] = x ;
+			data += 4 ;
+			len -= 4 ;
+			break ;
+		}
+		format++ ;
+	}
+}
+#else
+void smt_swap_para(sm,len,direction)
+struct smt_header *sm ;
+int len ;
+int direction ;			/* 0 encode 1 decode */
+{
+	SK_UNUSED(sm) ;
+	SK_UNUSED(len) ;
+	SK_UNUSED(direction) ;
+}
+#endif
+
+/*
+ * PMF actions
+ */
+int smt_action(smc,class,code,index)
+struct s_smc *smc ;
+int class ;
+int code ;
+int index ;
+{
+	int	event ;
+	int	port ;
+	DB_SMT("SMT: action %d code %d\n",class,code) ;
+	switch(class) {
+	case SMT_STATION_ACTION :
+		switch(code) {
+		case SMT_STATION_ACTION_CONNECT :
+			smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
+			queue_event(smc,EVENT_ECM,EC_CONNECT) ;
+			break ;
+		case SMT_STATION_ACTION_DISCONNECT :
+			queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+			smc->mib.fddiSMTRemoteDisconnectFlag = TRUE ;
+			RS_SET(smc,RS_DISCONNECT) ;
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_DISCONNECT,
+				smt_get_event_word(smc));
+			break ;
+		case SMT_STATION_ACTION_PATHTEST :
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_SMT_EVENT, (u_long) FDDI_PATH_TEST,
+				smt_get_event_word(smc));
+			break ;
+		case SMT_STATION_ACTION_SELFTEST :
+			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+				FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_SELF_TEST,
+				smt_get_event_word(smc));
+			break ;
+		case SMT_STATION_ACTION_DISABLE_A :
+			if (smc->y[PA].pc_mode == PM_PEER) {
+				RS_SET(smc,RS_EVENT) ;
+				queue_event(smc,EVENT_PCM+PA,PC_DISABLE) ;
+			}
+			break ;
+		case SMT_STATION_ACTION_DISABLE_B :
+			if (smc->y[PB].pc_mode == PM_PEER) {
+				RS_SET(smc,RS_EVENT) ;
+				queue_event(smc,EVENT_PCM+PB,PC_DISABLE) ;
+			}
+			break ;
+		case SMT_STATION_ACTION_DISABLE_M :
+			for (port = 0 ; port <  NUMPHYS ; port++) {
+				if (smc->mib.p[port].fddiPORTMy_Type != TM)
+					continue ;
+				RS_SET(smc,RS_EVENT) ;
+				queue_event(smc,EVENT_PCM+port,PC_DISABLE) ;
+			}
+			break ;
+		default :
+			return(1) ;
+		}
+		break ;
+	case SMT_PORT_ACTION :
+		switch(code) {
+		case SMT_PORT_ACTION_ENABLE :
+			event = PC_ENABLE ;
+			break ;
+		case SMT_PORT_ACTION_DISABLE :
+			event = PC_DISABLE ;
+			break ;
+		case SMT_PORT_ACTION_MAINT :
+			event = PC_MAINT ;
+			break ;
+		case SMT_PORT_ACTION_START :
+			event = PC_START ;
+			break ;
+		case SMT_PORT_ACTION_STOP :
+			event = PC_STOP ;
+			break ;
+		default :
+			return(1) ;
+		}
+		queue_event(smc,EVENT_PCM+index,event) ;
+		break ;
+	default :
+		return(1) ;
+	}
+	return(0) ;
+}
+
+/*
+ * change tneg
+ *	set T_Req in MIB (Path Attribute)
+ *	calculate new values for MAC
+ *	if change required
+ *		disconnect
+ *		set reconnect
+ *	end
+ */
+void smt_change_t_neg(smc,tneg)
+struct s_smc *smc ;
+u_long tneg ;
+{
+	smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ;
+
+	if (smt_set_mac_opvalues(smc)) {
+		RS_SET(smc,RS_EVENT) ;
+		smc->sm.please_reconnect = 1 ;
+		queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
+	}
+}
+
+/*
+ * canonical conversion of <len> bytes beginning form *data
+ */
+#ifdef  USE_CAN_ADDR
+void hwm_conv_can(smc,data,len)
+struct s_smc *smc ;
+char *data ;
+int len ;
+{
+	int i ;
+
+	SK_UNUSED(smc) ;
+
+	for (i = len; i ; i--, data++) {
+		*data = canonical[*(u_char *)data] ;
+	}
+}
+#endif
+
+#endif	/* no SLIM_SMT */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/smtdef.c linux.18p8/drivers/net/skfp/smtdef.c
--- linux.vanilla/drivers/net/skfp/smtdef.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/smtdef.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,371 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT/CMT defaults
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef OEM_USER_DATA
+#define OEM_USER_DATA	"SK-NET FDDI V2.0 Userdata"
+#endif
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smtdef.c	2.53 99/08/11 (C) SK " ;
+#endif
+
+/*
+ * defaults
+ */
+#define TTMS(x)	((u_long)(x)*1000L)
+#define TTS(x)	((u_long)(x)*1000000L)
+#define TTUS(x)	((u_long)(x))
+
+#define DEFAULT_TB_MIN		TTMS(5)
+#define DEFAULT_TB_MAX		TTMS(50)
+#define DEFAULT_C_MIN		TTUS(1600)
+#define DEFAULT_T_OUT		TTMS(100+5)
+#define DEFAULT_TL_MIN		TTUS(30)
+#define DEFAULT_LC_SHORT	TTMS(50+5)
+#define DEFAULT_LC_MEDIUM	TTMS(500+20)
+#define DEFAULT_LC_LONG		TTS(5)+TTMS(50)
+#define DEFAULT_LC_EXTENDED	TTS(50)+TTMS(50)
+#define DEFAULT_T_NEXT_9	TTMS(200+10)
+#define DEFAULT_NS_MAX		TTUS(1310)
+#define DEFAULT_I_MAX		TTMS(25)
+#define DEFAULT_IN_MAX		TTMS(40)
+#define DEFAULT_TD_MIN		TTMS(5)
+#define DEFAULT_T_NON_OP	TTS(1)
+#define DEFAULT_T_STUCK		TTS(8)
+#define DEFAULT_T_DIRECT	TTMS(370)
+#define DEFAULT_T_JAM		TTMS(370)
+#define DEFAULT_T_ANNOUNCE	TTMS(2500)
+#define DEFAULT_D_MAX		TTUS(1617)
+#define DEFAULT_LEM_ALARM	(8)
+#define DEFAULT_LEM_CUTOFF	(7)
+#define DEFAULT_TEST_DONE	TTS(1)
+#define DEFAULT_CHECK_POLL	TTS(1)
+#define DEFAULT_POLL		TTMS(50)
+
+/*
+ * LCT errors threshold
+ */
+#define DEFAULT_LCT_SHORT	1
+#define DEFAULT_LCT_MEDIUM	3
+#define DEFAULT_LCT_LONG	5
+#define DEFAULT_LCT_EXTEND	50
+
+/* Forward declarations */
+extern  void	smt_reset_defaults ();
+static	void	smt_init_mib ();
+
+static int set_min_max() ;
+
+void smt_set_defaults(smc)
+struct s_smc *smc ;
+{
+	smt_reset_defaults(smc,0) ;
+}
+
+#define MS2BCLK(x)	((x)*12500L)
+#define US2BCLK(x)	((x)*1250L)
+
+void smt_reset_defaults(smc,level)
+struct s_smc *smc ;
+int level ;
+{
+	struct smt_config	*smt ;
+	int			i ;
+	u_long			smt_boot_time;
+
+
+	smt_init_mib(smc,level) ;
+
+	smc->os.smc_version = SMC_VERSION ;
+	smt_boot_time = smt_get_time();
+	for( i = 0; i < NUMMACS; i++ )
+		smc->sm.last_tok_time[i] = smt_boot_time ;
+	smt = &smc->s ;
+	smt->attach_s = 0 ;
+	smt->build_ring_map = 1 ;
+	smt->sas = SMT_DAS ;
+	smt->numphys = NUMPHYS ;
+	smt->pcm_tb_min = DEFAULT_TB_MIN ;
+	smt->pcm_tb_max = DEFAULT_TB_MAX ;
+	smt->pcm_c_min = DEFAULT_C_MIN ;
+	smt->pcm_t_out = DEFAULT_T_OUT ;
+	smt->pcm_tl_min = DEFAULT_TL_MIN ;
+	smt->pcm_lc_short = DEFAULT_LC_SHORT ;
+	smt->pcm_lc_medium = DEFAULT_LC_MEDIUM ;
+	smt->pcm_lc_long = DEFAULT_LC_LONG ;
+	smt->pcm_lc_extended = DEFAULT_LC_EXTENDED ;
+	smt->pcm_t_next_9 = DEFAULT_T_NEXT_9 ;
+	smt->pcm_ns_max = DEFAULT_NS_MAX ;
+	smt->ecm_i_max = DEFAULT_I_MAX ;
+	smt->ecm_in_max = DEFAULT_IN_MAX ;
+	smt->ecm_td_min = DEFAULT_TD_MIN ;
+	smt->ecm_test_done = DEFAULT_TEST_DONE ;
+	smt->ecm_check_poll = DEFAULT_CHECK_POLL ;
+	smt->rmt_t_non_op = DEFAULT_T_NON_OP ;
+	smt->rmt_t_stuck = DEFAULT_T_STUCK ;
+	smt->rmt_t_direct = DEFAULT_T_DIRECT ;
+	smt->rmt_t_jam = DEFAULT_T_JAM ;
+	smt->rmt_t_announce = DEFAULT_T_ANNOUNCE ;
+	smt->rmt_t_poll = DEFAULT_POLL ;
+        smt->rmt_dup_mac_behavior = FALSE ;  /* See Struct smt_config */
+	smt->mac_d_max = DEFAULT_D_MAX ;
+
+	smt->lct_short = DEFAULT_LCT_SHORT ;
+	smt->lct_medium = DEFAULT_LCT_MEDIUM ;
+	smt->lct_long = DEFAULT_LCT_LONG ;
+	smt->lct_extended = DEFAULT_LCT_EXTEND ;
+
+#ifndef	SLIM_SMT
+#ifdef	ESS
+	if (level == 0) {
+		smc->ess.sync_bw_available = FALSE ;
+		smc->mib.fddiESSPayload = 0 ;
+		smc->mib.fddiESSOverhead = 0 ;
+		smc->mib.fddiESSMaxTNeg = (u_long)(- MS2BCLK(25)) ;
+		smc->mib.fddiESSMinSegmentSize = 1 ;
+		smc->mib.fddiESSCategory = SB_STATIC ;
+		smc->mib.fddiESSSynchTxMode = FALSE ;
+		smc->ess.raf_act_timer_poll = FALSE ;
+		smc->ess.timer_count = 7 ; 	/* first RAF alc req after 3s */
+	}
+	smc->ess.local_sba_active = FALSE ;
+	smc->ess.sba_reply_pend = NULL ;
+#endif
+#ifdef	SBA
+	smt_init_sba(smc,level) ;
+#endif
+#endif	/* no SLIM_SMT */
+#ifdef	TAG_MODE
+	if (level == 0) {
+		smc->hw.pci_fix_value = 0 ;
+	}
+#endif
+}
+
+/*
+ * manufacturer data
+ */
+static const char man_data[32] =
+/*	 01234567890123456789012345678901	*/
+	"xxxSK-NET FDDI SMT 7.3 - V2.8.8" ;
+
+static void smt_init_mib(smc,level)
+struct s_smc *smc ;
+int level ;
+{
+	struct fddi_mib		*mib ;
+	struct fddi_mib_p	*pm ;
+	int			port ;
+	int			path ;
+
+	mib = &smc->mib ;
+	if (level == 0) {
+		/*
+		 * set EVERYTHING to ZERO
+		 * EXCEPT hw and os
+		 */
+		memset(((char *)smc)+
+			sizeof(struct s_smt_os)+sizeof(struct s_smt_hw), 0,
+			sizeof(struct s_smc) -
+			sizeof(struct s_smt_os) - sizeof(struct s_smt_hw)) ;
+	}
+	else {
+		mib->fddiSMTRemoteDisconnectFlag = 0 ;
+		mib->fddiSMTPeerWrapFlag = 0 ;
+	}
+
+	mib->fddiSMTOpVersionId = 2 ;
+	mib->fddiSMTHiVersionId = 2 ;
+	mib->fddiSMTLoVersionId = 2 ;
+	memcpy((char *) mib->fddiSMTManufacturerData,man_data,32) ;
+	if (level == 0) {
+		strcpy(mib->fddiSMTUserData,OEM_USER_DATA) ;
+	}
+	mib->fddiSMTMIBVersionId = 1 ;
+	mib->fddiSMTMac_Ct = NUMMACS ;
+	mib->fddiSMTConnectionPolicy = POLICY_MM | POLICY_AA | POLICY_BB ;
+
+	/*
+	 * fddiSMTNonMaster_Ct and fddiSMTMaster_Ct are set in smt_fixup_mib
+	 * s.sas is not set yet (is set in init driver)
+	 */
+	mib->fddiSMTAvailablePaths = MIB_PATH_P | MIB_PATH_S ;
+
+	mib->fddiSMTConfigCapabilities = 0 ;	/* no hold,no wrap_ab*/
+	mib->fddiSMTTT_Notify = 10 ;
+	mib->fddiSMTStatRptPolicy = TRUE ;
+	mib->fddiSMTTrace_MaxExpiration = SEC2MIB(7) ;
+	mib->fddiSMTMACIndexes = INDEX_MAC ;
+	mib->fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ;	/* seperated */
+
+	mib->m[MAC0].fddiMACIndex = INDEX_MAC ;
+	mib->m[MAC0].fddiMACFrameStatusFunctions = FSC_TYPE0 ;
+	mib->m[MAC0].fddiMACRequestedPaths =
+		MIB_P_PATH_LOCAL |
+		MIB_P_PATH_SEC_ALTER |
+		MIB_P_PATH_PRIM_ALTER ;
+	mib->m[MAC0].fddiMACAvailablePaths = MIB_PATH_P ;
+	mib->m[MAC0].fddiMACCurrentPath = MIB_PATH_PRIMARY ;
+	mib->m[MAC0].fddiMACT_MaxCapabilitiy = (u_long)(- MS2BCLK(165)) ;
+	mib->m[MAC0].fddiMACTVXCapabilitiy = (u_long)(- US2BCLK(52)) ;
+	if (level == 0) {
+		mib->m[MAC0].fddiMACTvxValue = (u_long)(- US2BCLK(27)) ;
+		mib->m[MAC0].fddiMACTvxValueMIB = (u_long)(- US2BCLK(27)) ;
+		mib->m[MAC0].fddiMACT_Req = (u_long)(- MS2BCLK(165)) ;
+		mib->m[MAC0].fddiMACT_ReqMIB = (u_long)(- MS2BCLK(165)) ;
+		mib->m[MAC0].fddiMACT_Max = (u_long)(- MS2BCLK(165)) ;
+		mib->m[MAC0].fddiMACT_MaxMIB = (u_long)(- MS2BCLK(165)) ;
+		mib->m[MAC0].fddiMACT_Min = (u_long)(- MS2BCLK(4)) ;
+	}
+	mib->m[MAC0].fddiMACHardwarePresent = TRUE ;
+	mib->m[MAC0].fddiMACMA_UnitdataEnable = TRUE ;
+	mib->m[MAC0].fddiMACFrameErrorThreshold = 1 ;
+	mib->m[MAC0].fddiMACNotCopiedThreshold = 1 ;
+	/*
+	 * Path attributes
+	 */
+	for (path = 0 ; path < NUMPATHS ; path++) {
+		mib->a[path].fddiPATHIndex = INDEX_PATH + path ;
+		if (level == 0) {
+			mib->a[path].fddiPATHTVXLowerBound =
+				(u_long)(- US2BCLK(27)) ;
+			mib->a[path].fddiPATHT_MaxLowerBound =
+				(u_long)(- MS2BCLK(165)) ;
+			mib->a[path].fddiPATHMaxT_Req =
+				(u_long)(- MS2BCLK(165)) ;
+		}
+	}
+
+
+	/*
+	 * Port attributes
+	 */
+	pm = mib->p ;
+	for (port = 0 ; port <  NUMPHYS ; port++) {
+		/*
+		 * set MIB pointer in phy
+		 */
+		/* Attention: don't initialize mib pointer here! */
+		/*  It must be initialized during phase 2 */
+		smc->y[port].mib = 0 ;
+		mib->fddiSMTPORTIndexes[port] = port+INDEX_PORT ;
+
+		pm->fddiPORTIndex = port+INDEX_PORT ;
+		pm->fddiPORTHardwarePresent = TRUE ;
+		if (level == 0) {
+			pm->fddiPORTLer_Alarm = DEFAULT_LEM_ALARM ;
+			pm->fddiPORTLer_Cutoff = DEFAULT_LEM_CUTOFF ;
+		}
+		/*
+		 * fddiPORTRequestedPaths are set in pcmplc.c
+		 * we don't know the port type yet !
+		 */
+		pm->fddiPORTRequestedPaths[1] = 0 ;
+		pm->fddiPORTRequestedPaths[2] = 0 ;
+		pm->fddiPORTRequestedPaths[3] = 0 ;
+		pm->fddiPORTAvailablePaths = MIB_PATH_P ;
+		pm->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ;
+		pm++ ;
+	}
+
+	(void) smt_set_mac_opvalues(smc) ;
+}
+
+int smt_set_mac_opvalues(smc)
+struct s_smc *smc ;
+{
+	int	st ;
+	int	st2 ;
+
+	st = set_min_max(1,smc->mib.m[MAC0].fddiMACTvxValueMIB,
+		smc->mib.a[PATH0].fddiPATHTVXLowerBound,
+		&smc->mib.m[MAC0].fddiMACTvxValue) ;
+	st |= set_min_max(0,smc->mib.m[MAC0].fddiMACT_MaxMIB,
+		smc->mib.a[PATH0].fddiPATHT_MaxLowerBound,
+		&smc->mib.m[MAC0].fddiMACT_Max) ;
+	st |= (st2 = set_min_max(0,smc->mib.m[MAC0].fddiMACT_ReqMIB,
+		smc->mib.a[PATH0].fddiPATHMaxT_Req,
+		&smc->mib.m[MAC0].fddiMACT_Req)) ;
+	if (st2) {
+		/* Treq attribute changed remotely. So send an AIX_EVENT to the
+		 * user
+		 */
+		AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
+			FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_T_REQ,
+			smt_get_event_word(smc));
+	}
+	return(st) ;
+}
+
+void smt_fixup_mib(smc)
+struct s_smc *smc ;
+{
+#ifdef	CONCENTRATOR
+	switch (smc->s.sas) {
+	case SMT_SAS :
+		smc->mib.fddiSMTNonMaster_Ct = 1 ;
+		break ;
+	case SMT_DAS :
+		smc->mib.fddiSMTNonMaster_Ct = 2 ;
+		break ;
+	case SMT_NAC :
+		smc->mib.fddiSMTNonMaster_Ct = 0 ;
+		break ;
+	}
+	smc->mib.fddiSMTMaster_Ct = NUMPHYS - smc->mib.fddiSMTNonMaster_Ct ;
+#else
+	switch (smc->s.sas) {
+	case SMT_SAS :
+		smc->mib.fddiSMTNonMaster_Ct = 1 ;
+		break ;
+	case SMT_DAS :
+		smc->mib.fddiSMTNonMaster_Ct = 2 ;
+		break ;
+	}
+	smc->mib.fddiSMTMaster_Ct = 0 ;
+#endif
+}
+
+/*
+ * determine new setting for operational value
+ * if limit is lower than mib
+ *	use limit
+ * else
+ *	use mib
+ * NOTE : numbers are negative, negate comparison !
+ */
+static int set_min_max(maxflag,mib,limit,oper)
+int maxflag ;
+u_long mib ;
+u_long limit ;
+u_long *oper ;
+{
+	u_long	old ;
+	old = *oper ;
+	if ((limit > mib) ^ maxflag)
+		*oper = limit ;
+	else
+		*oper = mib ;
+	return(old != *oper) ;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/smtinit.c linux.18p8/drivers/net/skfp/smtinit.c
--- linux.vanilla/drivers/net/skfp/smtinit.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/smtinit.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	Init SMT
+	call all module level initialization routines
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smtinit.c	1.15 97/05/06 (C) SK " ;
+#endif
+
+extern void init_fddi_driver() ;
+
+/* define global debug variable */
+#if defined(DEBUG) && !defined(DEBUG_BRD)
+struct smt_debug debug;
+#endif
+
+#ifndef MULT_OEM
+#define OEMID(smc,i)	oem_id[i]
+	extern u_char	oem_id[] ;
+#else	/* MULT_OEM */
+#define OEMID(smc,i)	smc->hw.oem_id->oi_mark[i]
+	extern struct s_oem_ids	oem_ids[] ;
+#endif	/* MULT_OEM */
+
+/*
+ * Set OEM specific values
+ *
+ * Can not be called in smt_reset_defaults, because it is not sure that
+ * the OEM ID is already defined.
+ */
+static void set_oem_spec_val(smc)
+struct s_smc *smc ;
+{
+	struct fddi_mib *mib ;
+
+	mib = &smc->mib ;
+
+	/*
+	 * set IBM specific values
+	 */
+	if (OEMID(smc,0) == 'I') {
+		mib->fddiSMTConnectionPolicy = POLICY_MM ;
+	}
+}
+
+/*
+ * Init SMT
+ */
+int init_smt(smc,mac_addr)
+struct s_smc *smc ;
+u_char *mac_addr ;		/* canonical address or NULL */
+{
+	int	p ;
+
+#if defined(DEBUG) && !defined(DEBUG_BRD)
+	debug.d_smt = 0 ;
+	debug.d_smtf = 0 ;
+	debug.d_rmt = 0 ;
+	debug.d_ecm = 0 ;
+	debug.d_pcm = 0 ;
+	debug.d_cfm = 0 ;
+
+	debug.d_plc = 0 ;
+#ifdef	ESS
+	debug.d_ess = 0 ;
+#endif
+#ifdef	SBA
+	debug.d_sba = 0 ;
+#endif
+#endif	/* DEBUG && !DEBUG_BRD */
+
+	/* First initialize the ports mib->pointers */
+	for ( p = 0; p < NUMPHYS; p ++ ) {
+		smc->y[p].mib = & smc->mib.p[p] ;
+	}
+
+	set_oem_spec_val(smc) ;	
+	(void) smt_set_mac_opvalues(smc) ;
+	init_fddi_driver(smc,mac_addr) ;	/* HW driver */
+	smt_fixup_mib(smc) ;		/* update values that depend on s.sas */
+
+	ev_init(smc) ;			/* event queue */
+#ifndef	SLIM_SMT
+	smt_init_evc(smc) ;		/* evcs in MIB */
+#endif	/* no SLIM_SMT */
+	smt_timer_init(smc) ;		/* timer package */
+	smt_agent_init(smc) ;		/* SMT frame manager */
+
+	pcm_init(smc) ;			/* PCM state machine */
+	ecm_init(smc) ;			/* ECM state machine */
+	cfm_init(smc) ;			/* CFM state machine */
+	rmt_init(smc) ;			/* RMT state machine */
+
+	for (p = 0 ; p < NUMPHYS ; p++) {
+		pcm(smc,p,0) ;		/* PCM A state machine */
+	}
+	ecm(smc,0) ;			/* ECM state machine */
+	cfm(smc,0) ;			/* CFM state machine */
+	rmt(smc,0) ;			/* RMT state machine */
+
+	smt_agent_task(smc) ;		/* NIF FSM etc */
+
+        PNMI_INIT(smc) ;                /* PNMI initialization */
+
+	return(0) ;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/smtparse.c linux.18p8/drivers/net/skfp/smtparse.c
--- linux.vanilla/drivers/net/skfp/smtparse.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/smtparse.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,475 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+
+/*
+	parser for SMT parameters
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smtparse.c	1.12 98/10/06 (C) SK " ;
+#endif
+
+#ifdef	sun
+#define _far
+#endif
+
+/*
+ * convert to BCLK units
+ */
+#define MS2BCLK(x)      ((x)*12500L)
+#define US2BCLK(x)      ((x/10)*125L)
+
+/*
+ * parameter table
+ */
+static struct s_ptab {
+	char	*pt_name ;
+	u_short	pt_num ;
+	u_short	pt_type ;
+	u_long	pt_min ;
+	u_long	pt_max ;
+} ptab[] = {
+	{ "PMFPASSWD",0,	0 } ,
+	{ "USERDATA",1,		0 } ,
+	{ "LERCUTOFFA",2,	1,	4,	15	} ,
+	{ "LERCUTOFFB",3,	1,	4,	15	} ,
+	{ "LERALARMA",4,	1,	4,	15	} ,
+	{ "LERALARMB",5,	1,	4,	15	} ,
+	{ "TMAX",6,		1,	5,	165	} ,
+	{ "TMIN",7,		1,	5,	165	} ,
+	{ "TREQ",8,		1,	5,	165	} ,
+	{ "TVX",9,		1,	2500,	10000	} ,
+#ifdef ESS
+	{ "SBAPAYLOAD",10,	1,	0,	1562	} ,
+	{ "SBAOVERHEAD",11,	1,	50,	5000	} ,
+	{ "MAXTNEG",12,		1,	5,	165	} ,
+	{ "MINSEGMENTSIZE",13,	1,	0,	4478	} ,
+	{ "SBACATEGORY",14,	1,	0,	0xffff	} ,
+	{ "SYNCHTXMODE",15,	0 } ,
+#endif
+#ifdef SBA
+	{ "SBACOMMAND",16,	0 } ,
+	{ "SBAAVAILABLE",17,	1,	0,	100	} ,
+#endif
+	{ 0 }
+} ;
+
+/* Define maximum string size for values and keybuffer */
+#define MAX_VAL	40
+
+/*
+ * local function declarations
+ */
+static u_long parse_num() ;
+static int parse_word() ;
+
+#ifdef SIM
+#define DB_MAIN(a,b,c)	printf(a,b,c)
+#else
+#define DB_MAIN(a,b,c)
+#endif
+
+/*
+ * BEGIN_MANUAL_ENTRY()
+ *
+ *	int smt_parse_arg(struct s_smc *,char _far *keyword,int type,
+		char _far *value)
+ *
+ *	parse SMT parameter
+ *	*keyword
+ *		pointer to keyword, must be \0, \n or \r terminated
+ *	*value	pointer to value, either char * or u_long *
+ *		if char *
+ *			pointer to value, must be \0, \n or \r terminated
+ *		if u_long *
+ *			contains binary value
+ *
+ *	type	0: integer
+ *		1: string
+ *	return
+ *		0	parameter parsed ok
+ *		!= 0	error
+ *	NOTE:
+ *		function can be called with DS != SS
+ *
+ *
+ * END_MANUAL_ENTRY()
+ */
+int smt_parse_arg(smc,keyword,type,value)
+struct s_smc *smc ;
+char _far *keyword ;
+int type ;
+char _far *value ;
+{
+	char		keybuf[MAX_VAL+1];
+	char		valbuf[MAX_VAL+1];
+	char		c ;
+	char 		*p ;
+	char		*v ;
+	char		*d ;
+	u_long		val = 0 ;
+	struct s_ptab	*pt ;
+	int		st ;
+	int		i ;
+
+	/*
+	 * parse keyword
+	 */
+	if ((st = parse_word(keybuf,keyword)))
+		return(st) ;
+	/*
+	 * parse value if given as string
+	 */
+	if (type == 1) {
+		if ((st = parse_word(valbuf,value)))
+			return(st) ;
+	}
+	/*
+	 * search in table
+	 */
+	st = 0 ;
+	for (pt = ptab ; (v = pt->pt_name) ; pt++) {
+		for (p = keybuf ; (c = *p) ; p++,v++) {
+			if (c != *v)
+				break ;
+		}
+		if (!c && !*v)
+			break ;
+	}
+	if (!v)
+		return(-1) ;
+#if	0
+	printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ;
+#endif
+	/*
+	 * set value in MIB
+	 */
+	if (pt->pt_type)
+		val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ;
+	switch (pt->pt_num) {
+	case 0 :
+		v = valbuf ;
+		d = (char *) smc->mib.fddiPRPMFPasswd ;
+		for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++)
+			*d++ = *v++ ;
+		DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ;
+		break ;
+	case 1 :
+		v = valbuf ;
+		d = (char *) smc->mib.fddiSMTUserData ;
+		for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++)
+			*d++ = *v++ ;
+		DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ;
+		break ;
+	case 2 :
+		smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ;
+		DB_MAIN("SET %s = %d\n",
+			pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ;
+		break ;
+	case 3 :
+		smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ;
+		DB_MAIN("SET %s = %d\n",
+			pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ;
+		break ;
+	case 4 :
+		smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ;
+		DB_MAIN("SET %s = %d\n",
+			pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ;
+		break ;
+	case 5 :
+		smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ;
+		DB_MAIN("SET %s = %d\n",
+			pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ;
+		break ;
+	case 6 :			/* TMAX */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.a[PATH0].fddiPATHT_MaxLowerBound =
+			(u_long) -MS2BCLK((long)val) ;
+		break ;
+	case 7 :			/* TMIN */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.m[MAC0].fddiMACT_Min =
+			(u_long) -MS2BCLK((long)val) ;
+		break ;
+	case 8 :			/* TREQ */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.a[PATH0].fddiPATHMaxT_Req =
+			(u_long) -MS2BCLK((long)val) ;
+		break ;
+	case 9 :			/* TVX */
+		DB_MAIN("SET %s = %d \n",pt->pt_name,val) ;
+		smc->mib.a[PATH0].fddiPATHTVXLowerBound =
+			(u_long) -US2BCLK((long)val) ;
+		break ;
+#ifdef	ESS
+	case 10 :			/* SBAPAYLOAD */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		if (smc->mib.fddiESSPayload != val) {
+			smc->ess.raf_act_timer_poll = TRUE ;
+			smc->mib.fddiESSPayload = val ;
+		}
+		break ;
+	case 11 :			/* SBAOVERHEAD */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiESSOverhead = val ;
+		break ;
+	case 12 :			/* MAXTNEG */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ;
+		break ;
+	case 13 :			/* MINSEGMENTSIZE */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiESSMinSegmentSize = val ;
+		break ;
+	case 14 :			/* SBACATEGORY */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiESSCategory =
+			(smc->mib.fddiESSCategory & 0xffff) |
+			((u_long)(val << 16)) ;
+		break ;
+	case 15 :			/* SYNCHTXMODE */
+		/* do not use memcmp(valbuf,"ALL",3) because DS != SS */
+		if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') {
+			smc->mib.fddiESSSynchTxMode = TRUE ;
+			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+		}
+		/* if (!memcmp(valbuf,"SPLIT",5)) { */
+		if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' &&
+			valbuf[3] == 'I' && valbuf[4] == 'T') {
+			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+			smc->mib.fddiESSSynchTxMode = FALSE ;
+		}
+		break ;
+#endif
+#ifdef	SBA
+	case 16 :			/* SBACOMMAND */
+		/* if (!memcmp(valbuf,"START",5)) { */
+		if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' &&
+			valbuf[3] == 'R' && valbuf[4] == 'T') {
+			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+			smc->mib.fddiSBACommand = SB_START ;
+		}
+		/* if (!memcmp(valbuf,"STOP",4)) { */
+		if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' &&
+			valbuf[3] == 'P') {
+			DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
+			smc->mib.fddiSBACommand = SB_STOP ;
+		}
+		break ;
+	case 17 :			/* SBAAVAILABLE */
+		DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
+		smc->mib.fddiSBAAvailable = (u_char) val ;
+		break ;
+#endif
+	}
+	return(0) ;
+}
+
+static int parse_word(buf,text)
+char *buf ;
+char _far *text ;
+{
+	char		c ;
+	char 		*p ;
+	int		p_len ;
+	int		quote ;
+	int		i ;
+	int		ok ;
+
+	/*
+	 * skip leading white space
+	 */
+	p = buf ;
+	for (i = 0 ; i < MAX_VAL ; i++)
+		*p++ = 0 ;
+	p = buf ;
+	p_len = 0 ;
+	ok = 0 ;
+	while ( (c = *text++) && (c != '\n') && (c != '\r')) {
+		if ((c != ' ') && (c != '\t')) {
+			ok = 1 ;
+			break ;
+		}
+	}
+	if (!ok)
+		return(-1) ;
+	if (c == '"') {
+		quote = 1 ;
+	}
+	else {
+		quote = 0 ;
+		text-- ;
+	}
+	/*
+	 * parse valbuf
+	 */
+	ok = 0 ;
+	while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n')
+		&& (c != '\r')) {
+		switch (quote) {
+		case 0 :
+			if ((c == ' ') || (c == '\t') || (c == '=')) {
+				ok = 1 ;
+				break ;
+			}
+			*p++ = c ;
+			p_len++ ;
+			break ;
+		case 2 :
+			*p++ = c ;
+			p_len++ ;
+			quote = 1 ;
+			break ;
+		case 1 :
+			switch (c) {
+			case '"' :
+				ok = 1 ;
+				break ;
+			case '\\' :
+				quote = 2 ;
+				break ;
+			default :
+				*p++ = c ;
+				p_len++ ;
+			}
+		}
+	}
+	*p++ = 0 ;
+	for (p = buf ; (c = *p) ; p++) {
+		if (c >= 'a' && c <= 'z')
+			*p = c + 'A' - 'a' ;
+	}
+	return(0) ;
+}
+
+static u_long parse_num(type,value,v,mn,mx,scale)
+int type ;
+char _far *value ;
+char *v ;
+u_long mn ;
+u_long mx ;
+int scale ;
+{
+	u_long	x = 0 ;
+	char	c ;
+
+	if (type == 0) {		/* integer */
+		u_long _far	*l ;
+		u_long		u1 ;
+
+		l = (u_long _far *) value ;
+		u1 = *l ;
+		/*
+		 * if the value is negative take the lower limit
+		 */
+		if ((long)u1 < 0) {
+			if (- ((long)u1) > (long) mx) {
+				u1 = 0 ;
+			}
+			else {
+				u1 = (u_long) - ((long)u1) ;
+			}
+		}
+		x = u1 ;
+	}
+	else {				/* string */
+		int	sign = 0 ;
+
+		if (*v == '-') {
+			sign = 1 ;
+		}
+		while ((c = *v++) && (c >= '0') && (c <= '9')) {
+			x = x * 10 + c - '0' ;
+		}
+		if (scale == 10) {
+			x *= 10 ;
+			if (c == '.') {
+				if ((c = *v++) && (c >= '0') && (c <= '9')) {
+					x += c - '0' ;
+				}
+			}
+		}
+		if (sign)
+			x = (u_long) - ((long)x) ;
+	}
+	/*
+	 * if the value is negative
+	 *	and the absolute value is outside the limits
+	 *		take the lower limit
+	 *	else
+	 *		take the absoute value
+	 */
+	if ((long)x < 0) {
+		if (- ((long)x) > (long) mx) {
+			x = 0 ;
+		}
+		else {
+			x = (u_long) - ((long)x) ;
+		}
+	}
+	if (x < mn)
+		return(mn) ;
+	else if (x > mx)
+		return(mx) ;
+	return(x) ;
+}
+
+#if 0
+struct	s_smc	SMC ;
+main()
+{
+	char	*p ;
+	char	*v ;
+	char	buf[100] ;
+	int	toggle = 0 ;
+
+	while (gets(buf)) {
+		p = buf ;
+		while (*p && ((*p == ' ') || (*p == '\t')))
+			p++ ;
+
+		while (*p && ((*p != ' ') && (*p != '\t')))
+			p++ ;
+
+		v = p ;
+		while (*v && ((*v == ' ') || (*v == '\t')))
+			v++ ;
+		if ((*v >= '0') && (*v <= '9')) {
+			toggle = !toggle ;
+			if (toggle) {
+				u_long	l ;
+				l = atol(v) ;
+				smt_parse_arg(&SMC,buf,0,(char _far *)&l) ;
+			}
+			else
+				smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
+		}
+		else {
+			smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
+		}
+	}
+	exit(0) ;
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/smttimer.c linux.18p8/drivers/net/skfp/smttimer.c
--- linux.vanilla/drivers/net/skfp/smttimer.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/smttimer.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,173 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT timer
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)smttimer.c	2.4 97/08/04 (C) SK " ;
+#endif
+
+/*
+ * external function declarations
+ */
+extern u_long hwt_read() ;
+extern void hwt_stop() ;
+extern void hwt_start() ;
+
+static void timer_done() ;
+
+
+void smt_timer_init(smc)
+struct s_smc *smc ;
+{
+	smc->t.st_queue = 0 ;
+	smc->t.st_fast.tm_active = FALSE ;
+	smc->t.st_fast.tm_next = 0 ;
+	hwt_init(smc) ;
+}
+
+void smt_timer_stop(smc,timer)
+struct s_smc *smc ;
+struct smt_timer *timer ;
+{
+	struct smt_timer	**prev ;
+	struct smt_timer	*tm ;
+
+	/*
+	 * remove timer from queue
+	 */
+	timer->tm_active = FALSE ;
+	if (smc->t.st_queue == timer && !timer->tm_next) {
+		hwt_stop(smc) ;
+	}
+	for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
+		if (tm == timer) {
+			*prev = tm->tm_next ;
+			if (tm->tm_next) {
+				tm->tm_next->tm_delta += tm->tm_delta ;
+			}
+			return ;
+		}
+	}
+}
+
+void smt_timer_start(smc,timer,time,token)
+struct s_smc *smc ;
+struct smt_timer *timer ;
+u_long		time ;
+u_long		token ;
+{
+	struct smt_timer	**prev ;
+	struct smt_timer	*tm ;
+	u_long			delta = 0 ;
+
+	time /= 16 ;		/* input is uS, clock ticks are 16uS */
+	if (!time)
+		time = 1 ;
+	smt_timer_stop(smc,timer) ;
+	timer->tm_smc = smc ;
+	timer->tm_token = token ;
+	timer->tm_active = TRUE ;
+	if (!smc->t.st_queue) {
+		smc->t.st_queue = timer ;
+		timer->tm_next = 0 ;
+		timer->tm_delta = time ;
+		hwt_start(smc,time) ;
+		return ;
+	}
+	/*
+	 * timer correction
+	 */
+	timer_done(smc,0) ;
+
+	/*
+	 * find position in queue
+	 */
+	delta = 0 ;
+	for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
+		if (delta + tm->tm_delta > time) {
+			break ;
+		}
+		delta += tm->tm_delta ;
+	}
+	/* insert in queue */
+	*prev = timer ;
+	timer->tm_next = tm ;
+	timer->tm_delta = time - delta ;
+	if (tm)
+		tm->tm_delta -= timer->tm_delta ;
+	/*
+	 * start new with first
+	 */
+	hwt_start(smc,smc->t.st_queue->tm_delta) ;
+}
+
+void smt_force_irq(smc)
+struct s_smc *smc ;
+{
+	smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); 
+}
+
+void smt_timer_done(smc)
+struct s_smc *smc ;
+{
+	timer_done(smc,1) ;
+}
+
+static void timer_done(smc,restart)
+struct s_smc *smc ;
+int restart ;
+{
+	u_long			delta ;
+	struct smt_timer	*tm ;
+	struct smt_timer	*next ;
+	struct smt_timer	**last ;
+	int			done = 0 ;
+
+	delta = hwt_read(smc) ;
+	last = &smc->t.st_queue ;
+	tm = smc->t.st_queue ;
+	while (tm && !done) {
+		if (delta >= tm->tm_delta) {
+			tm->tm_active = FALSE ;
+			delta -= tm->tm_delta ;
+			last = &tm->tm_next ;
+			tm = tm->tm_next ;
+		}
+		else {
+			tm->tm_delta -= delta ;
+			delta = 0 ;
+			done = 1 ;
+		}
+	}
+	*last = 0 ;
+	next = smc->t.st_queue ;
+	smc->t.st_queue = tm ;
+
+	for ( tm = next ; tm ; tm = next) {
+		next = tm->tm_next ;
+		timer_event(smc,tm->tm_token) ;
+	}
+
+	if (restart && smc->t.st_queue)
+		hwt_start(smc,smc->t.st_queue->tm_delta) ;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/skfp/srf.c linux.18p8/drivers/net/skfp/srf.c
--- linux.vanilla/drivers/net/skfp/srf.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/net/skfp/srf.c	Fri Sep  1 13:48:23 2000
@@ -0,0 +1,441 @@
+/******************************************************************************
+ *
+ *	(C)Copyright 1998,1999 SysKonnect,
+ *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
+ *
+ *	See the file "skfddi.c" for further information.
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ ******************************************************************************/
+
+/*
+	SMT 7.2 Status Response Frame Implementation
+	SRF state machine and frame generation
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+#include "h/smt_p.h"
+
+#define KERNEL
+#include "h/smtstate.h"
+
+#ifndef	SLIM_SMT
+#ifndef	BOOT
+
+#ifndef	lint
+static const char ID_sccs[] = "@(#)srf.c	1.18 97/08/04 (C) SK " ;
+#endif
+
+
+/*
+ * function declarations
+ */
+static void clear_all_rep() ;
+static void clear_reported() ;
+static void smt_send_srf() ;
+static struct s_srf_evc *smt_get_evc() ;
+
+#define MAX_EVCS	(sizeof(smc->evcs)/sizeof(smc->evcs[0]))
+
+struct evc_init {
+	u_char code ;
+	u_char index ;
+	u_char n ;
+	u_short	para ;
+}  ;
+
+static const struct evc_init evc_inits[] = {
+	{ SMT_COND_SMT_PEER_WRAP,		0,1,SMT_P1048	} ,
+
+	{ SMT_COND_MAC_DUP_ADDR,		INDEX_MAC, NUMMACS,SMT_P208C } ,
+	{ SMT_COND_MAC_FRAME_ERROR,		INDEX_MAC, NUMMACS,SMT_P208D } ,
+	{ SMT_COND_MAC_NOT_COPIED,		INDEX_MAC, NUMMACS,SMT_P208E } ,
+	{ SMT_EVENT_MAC_NEIGHBOR_CHANGE,	INDEX_MAC, NUMMACS,SMT_P208F } ,
+	{ SMT_EVENT_MAC_PATH_CHANGE,		INDEX_MAC, NUMMACS,SMT_P2090 } ,
+
+	{ SMT_COND_PORT_LER,			INDEX_PORT,NUMPHYS,SMT_P4050 } ,
+	{ SMT_COND_PORT_EB_ERROR,		INDEX_PORT,NUMPHYS,SMT_P4052 } ,
+	{ SMT_EVENT_PORT_CONNECTION,		INDEX_PORT,NUMPHYS,SMT_P4051 } ,
+	{ SMT_EVENT_PORT_PATH_CHANGE,		INDEX_PORT,NUMPHYS,SMT_P4053 } ,
+} ;
+
+#define MAX_INIT_EVC	(sizeof(evc_inits)/sizeof(evc_inits[0]))
+
+void smt_init_evc(smc)
+struct s_smc *smc ;
+{
+	struct s_srf_evc	*evc ;
+	const struct evc_init 	*init ;
+	int			i ;
+	int			index ;
+	int			offset ;
+
+	static u_char		fail_safe = FALSE ;
+
+	memset((char *)smc->evcs,0,sizeof(smc->evcs)) ;
+
+	evc = smc->evcs ;
+	init = evc_inits ;
+
+	for (i = 0 ; (unsigned) i < MAX_INIT_EVC ; i++) {
+		for (index = 0 ; index < init->n ; index++) {
+			evc->evc_code = init->code ;
+			evc->evc_para = init->para ;
+			evc->evc_index = init->index + index ;
+#ifndef	DEBUG
+			evc->evc_multiple = &fail_safe ;
+			evc->evc_cond_state = &fail_safe ;
+#endif
+			evc++ ;
+		}
+		init++ ;
+	}
+
+	if ((unsigned) (evc - smc->evcs) > MAX_EVCS) {
+		SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ;
+	}
+
+	/*
+	 * conditions
+	 */
+	smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ;
+	smc->evcs[1].evc_cond_state =
+		&smc->mib.m[MAC0].fddiMACDuplicateAddressCond ;
+	smc->evcs[2].evc_cond_state =
+		&smc->mib.m[MAC0].fddiMACFrameErrorFlag ;
+	smc->evcs[3].evc_cond_state =
+		&smc->mib.m[MAC0].fddiMACNotCopiedFlag ;
+
+	/*
+	 * events
+	 */
+	smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ;
+	smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ;
+
+	offset = 6 ;
+	for (i = 0 ; i < NUMPHYS ; i++) {
+		/*
+		 * conditions
+		 */
+		smc->evcs[offset + 0*NUMPHYS].evc_cond_state =
+			&smc->mib.p[i].fddiPORTLerFlag ;
+		smc->evcs[offset + 1*NUMPHYS].evc_cond_state =
+			&smc->mib.p[i].fddiPORTEB_Condition ;
+
+		/*
+		 * events
+		 */
+		smc->evcs[offset + 2*NUMPHYS].evc_multiple =
+			&smc->mib.p[i].fddiPORTMultiple_U ;
+		smc->evcs[offset + 3*NUMPHYS].evc_multiple =
+			&smc->mib.p[i].fddiPORTMultiple_P ;
+		offset++ ;
+	}
+#ifdef	DEBUG
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		if (SMT_IS_CONDITION(evc->evc_code)) {
+			if (!evc->evc_cond_state) {
+				SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ;
+			}
+			evc->evc_multiple = &fail_safe ;
+		}
+		else {
+			if (!evc->evc_multiple) {
+				SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ;
+			}
+			evc->evc_cond_state = &fail_safe ;
+		}
+	}
+#endif
+	smc->srf.TSR = smt_get_time() ;
+	smc->srf.sr_state = SR0_WAIT ;
+}
+
+static struct s_srf_evc *smt_get_evc(smc,code,index)
+struct s_smc *smc ;
+int code ;
+int index ;
+{
+	int			i ;
+	struct s_srf_evc	*evc ;
+
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		if (evc->evc_code == code && evc->evc_index == index)
+			return(evc) ;
+	}
+	return(0) ;
+}
+
+#define THRESHOLD_2	(2*TICKS_PER_SECOND)
+#define THRESHOLD_32	(32*TICKS_PER_SECOND)
+
+#ifdef	DEBUG
+static const char * const srf_names[] = {
+	"None","MACPathChangeEvent",	"MACNeighborChangeEvent",
+	"PORTPathChangeEvent",		"PORTUndesiredConnectionAttemptEvent",
+	"SMTPeerWrapCondition",		"SMTHoldCondition",
+	"MACFrameErrorCondition",	"MACDuplicateAddressCondition",
+	"MACNotCopiedCondition",	"PORTEBErrorCondition",
+	"PORTLerCondition"
+} ;
+#endif
+
+void smt_srf_event(smc,code,index,cond)
+struct s_smc *smc ;
+int code ;
+int index ;
+int cond ;
+{
+	struct s_srf_evc	*evc ;
+	int			cond_asserted = 0 ;
+	int			cond_deasserted = 0 ;
+	int			event_occured = 0 ;
+	int			tsr ;
+	int			T_Limit = 2*TICKS_PER_SECOND ;
+
+	if (code == SMT_COND_MAC_DUP_ADDR && cond) {
+		RS_SET(smc,RS_DUPADDR) ;
+	}
+
+	if (code) {
+		DB_SMT("SRF: %s index %d\n",srf_names[code],index) ;
+
+		if (!(evc = smt_get_evc(smc,code,index))) {
+			DB_SMT("SRF : smt_get_evc() failed\n",0,0) ;
+			return ;
+		}
+		/*
+		 * ignore condition if no change
+		 */
+		if (SMT_IS_CONDITION(code)) {
+			if (*evc->evc_cond_state == cond)
+				return ;
+		}
+
+		/*
+		 * set transition time stamp
+		 */
+		smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ;
+		if (SMT_IS_CONDITION(code)) {
+			DB_SMT("SRF: condition is %s\n",cond ? "ON":"OFF",0) ;
+			if (cond) {
+				*evc->evc_cond_state = TRUE ;
+				evc->evc_rep_required = TRUE ;
+				smc->srf.any_report = TRUE ;
+				cond_asserted = TRUE ;
+			}
+			else {
+				*evc->evc_cond_state = FALSE ;
+				cond_deasserted = TRUE ;
+			}
+		}
+		else {
+			if (evc->evc_rep_required) {
+				*evc->evc_multiple  = TRUE ;
+			}
+			else {
+				evc->evc_rep_required = TRUE ;
+				*evc->evc_multiple  = FALSE ;
+			}
+			smc->srf.any_report = TRUE ;
+			event_occured = TRUE ;
+		}
+#ifdef	FDDI_MIB
+		snmp_srf_event(smc,evc) ;
+#endif	/* FDDI_MIB */
+	}
+	tsr = smt_get_time() - smc->srf.TSR ;
+
+	switch (smc->srf.sr_state) {
+	case SR0_WAIT :
+		/* SR01a */
+		if (cond_asserted && tsr < T_Limit) {
+			smc->srf.SRThreshold = THRESHOLD_2 ;
+			smc->srf.sr_state = SR1_HOLDOFF ;
+			break ;
+		}
+		/* SR01b */
+		if (cond_deasserted && tsr < T_Limit) {
+			smc->srf.sr_state = SR1_HOLDOFF ;
+			break ;
+		}
+		/* SR01c */
+		if (event_occured && tsr < T_Limit) {
+			smc->srf.sr_state = SR1_HOLDOFF ;
+			break ;
+		}
+		/* SR00b */
+		if (cond_asserted && tsr >= T_Limit) {
+			smc->srf.SRThreshold = THRESHOLD_2 ;
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR00c */
+		if (cond_deasserted && tsr >= T_Limit) {
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR00d */
+		if (event_occured && tsr >= T_Limit) {
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR00e */
+		if (smc->srf.any_report && (u_long) tsr >=
+			smc->srf.SRThreshold) {
+			smc->srf.SRThreshold *= 2 ;
+			if (smc->srf.SRThreshold > THRESHOLD_32)
+				smc->srf.SRThreshold = THRESHOLD_32 ;
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR02 */
+		if (!smc->mib.fddiSMTStatRptPolicy) {
+			smc->srf.sr_state = SR2_DISABLED ;
+			break ;
+		}
+		break ;
+	case SR1_HOLDOFF :
+		/* SR10b */
+		if (tsr >= T_Limit) {
+			smc->srf.sr_state = SR0_WAIT ;
+			smc->srf.TSR = smt_get_time() ;
+			smt_send_srf(smc) ;
+			break ;
+		}
+		/* SR11a */
+		if (cond_asserted) {
+			smc->srf.SRThreshold = THRESHOLD_2 ;
+		}
+		/* SR11b */
+		/* SR11c */
+		/* handled above */
+		/* SR12 */
+		if (!smc->mib.fddiSMTStatRptPolicy) {
+			smc->srf.sr_state = SR2_DISABLED ;
+			break ;
+		}
+		break ;
+	case SR2_DISABLED :
+		if (smc->mib.fddiSMTStatRptPolicy) {
+			smc->srf.sr_state = SR0_WAIT ;
+			smc->srf.TSR = smt_get_time() ;
+			smc->srf.SRThreshold = THRESHOLD_2 ;
+			clear_all_rep(smc) ;
+			break ;
+		}
+		break ;
+	}
+}
+
+static void clear_all_rep(smc)
+struct s_smc *smc ;
+{
+	struct s_srf_evc	*evc ;
+	int			i ;
+
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		evc->evc_rep_required = FALSE ;
+		if (SMT_IS_CONDITION(evc->evc_code))
+			*evc->evc_cond_state = FALSE ;
+	}
+	smc->srf.any_report = FALSE ;
+}
+
+static void clear_reported(smc)
+struct s_smc *smc ;
+{
+	struct s_srf_evc	*evc ;
+	int			i ;
+
+	smc->srf.any_report = FALSE ;
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		if (SMT_IS_CONDITION(evc->evc_code)) {
+			if (*evc->evc_cond_state == FALSE)
+				evc->evc_rep_required = FALSE ;
+			else
+				smc->srf.any_report = TRUE ;
+		}
+		else {
+			evc->evc_rep_required = FALSE ;
+			*evc->evc_multiple = FALSE ;
+		}
+	}
+}
+
+extern SMbuf *smt_build_frame() ;
+
+/*
+ * build and send SMT SRF frame
+ */
+static void smt_send_srf(smc)
+struct s_smc *smc ;
+{
+
+	struct smt_header	*smt ;
+	struct s_srf_evc	*evc ;
+	SK_LOC_DECL(struct s_pcon,pcon) ;
+	SMbuf			*mb ;
+	int			i ;
+
+	static const struct fddi_addr SMT_SRF_DA = {
+		{ 0x80, 0x01, 0x43, 0x00, 0x80, 0x08 }
+	} ;
+
+	/*
+	 * build SMT header
+	 */
+	if (!smc->r.sm_ma_avail)
+		return ;
+	if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0)))
+		return ;
+
+	RS_SET(smc,RS_SOFTERROR) ;
+
+	smt = smtod(mb, struct smt_header *) ;
+	smt->smt_dest = SMT_SRF_DA ;		/* DA == SRF multicast */
+
+	/*
+	 * setup parameter status
+	 */
+	pcon.pc_len = SMT_MAX_INFO_LEN ;	/* max para length */
+	pcon.pc_err = 0 ;			/* no error */
+	pcon.pc_badset = 0 ;			/* no bad set count */
+	pcon.pc_p = (void *) (smt + 1) ;	/* paras start here */
+
+	smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ;
+	smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ;
+
+	for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) {
+		if (evc->evc_rep_required) {
+			smt_add_para(smc,&pcon,evc->evc_para,
+				(int)evc->evc_index,0) ;
+		}
+	}
+	smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
+	mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
+
+	DB_SMT("SRF: sending SRF at %x, len %d \n",smt,mb->sm_len) ;
+	DB_SMT("SRF: state SR%d Threshold %d\n",
+		smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ;
+#ifdef	DEBUG
+	dump_smt(smc,smt,"SRF Send") ;
+#endif
+	smt_send_frame(smc,mb,FC_SMT_INFO,0) ;
+	clear_reported(smc) ;
+}
+
+#endif	/* no BOOT */
+#endif	/* no SLIM_SMT */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/smc9194.c linux.18p8/drivers/net/smc9194.c
--- linux.vanilla/drivers/net/smc9194.c	Sun Jun 11 21:44:15 2000
+++ linux.18p8/drivers/net/smc9194.c	Thu Aug 31 14:28:50 2000
@@ -18,6 +18,8 @@
  .
  . author:
  . 	Erik Stahlman				( erik@vt.edu )
+ . contributors:
+ .      Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  .
  . Hardware multicast code from Peter Cammaert ( pc@denkart.be )
  .
@@ -47,6 +49,7 @@
  .	03/06/96  Erik Stahlman  Added hardware multicast from Peter Cammaert
  .	04/14/00  Heiko Pruessing (SMA Regelsysteme)  Fixed bug in chip memory
  .				 allocation
+ .      08/20/00  Arnaldo Melo   fix kfree(skb) in smc_hardware_send_packet
  ----------------------------------------------------------------------------*/
 
 static const char *version =
@@ -667,7 +670,7 @@
 	if ( packet_no & 0x80 ) {
 		/* or isn't there?  BAD CHIP! */
 		printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n");
-		kfree(skb);
+		kfree_skb(skb);
 		lp->saved_skb = NULL;
 		dev->tbusy = 0;
 		return;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/syncppp.c linux.18p8/drivers/net/syncppp.c
--- linux.vanilla/drivers/net/syncppp.c	Sun Jun 11 21:44:15 2000
+++ linux.18p8/drivers/net/syncppp.c	Wed Sep 13 16:10:27 2000
@@ -517,7 +517,6 @@
 			sppp_ipcp_open (sp);
 			break;
 		case LCP_STATE_OPENED:
-#if 0		
 			/* Remote magic changed -- close session. */
 			sp->lcp.state = LCP_STATE_CLOSED;
 			sp->ipcp.state = IPCP_STATE_CLOSED;
@@ -525,7 +524,6 @@
 			sppp_lcp_open (sp);
 			/* An ACK has already been sent. */
 			sp->lcp.state = LCP_STATE_ACK_SENT;
-#endif			
 			break;
 		}
 		break;
@@ -566,7 +564,7 @@
 				sp->lcp.magic += newmagic;
 			} else
 				sp->lcp.magic = rmagic;
-			}
+		}
 		if (sp->lcp.state != LCP_STATE_ACK_SENT) {
 			/* Go to closed state. */
 			sp->lcp.state = LCP_STATE_CLOSED;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip.c linux.18p8/drivers/net/tulip.c
--- linux.vanilla/drivers/net/tulip.c	Fri Apr 21 12:46:21 2000
+++ linux.18p8/drivers/net/tulip.c	Mon Sep 11 17:58:02 2000
@@ -126,6 +126,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/init.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -320,7 +321,7 @@
 							 long ioaddr, int irq, int chip_idx, int fnd_cnt);
 };
 #ifndef CARDBUS
-static struct pci_id_info pci_tbl[] = {
+static struct pci_id_info pci_tbl[] __initdata = {
   { "Digital DC21040 Tulip",
 	0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
   { "Digital DC21041 Tulip",
@@ -571,7 +572,7 @@
 static struct device *root_tulip_dev = NULL;
 
 #ifndef CARDBUS
-int tulip_probe(struct device *dev)
+int __init tulip_probe(struct device *dev)
 {
 	int cards_found = 0;
 	int pci_index = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/via-rhine.c linux.18p8/drivers/net/via-rhine.c
--- linux.vanilla/drivers/net/via-rhine.c	Sun Jun 11 21:44:15 2000
+++ linux.18p8/drivers/net/via-rhine.c	Mon Sep 11 17:58:02 2000
@@ -77,6 +77,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/init.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -261,7 +262,7 @@
 								 struct device *dev, long ioaddr, int irq,
 								 int chp_idx, int fnd_cnt);
 
-static struct pci_id_info pci_tbl[] = {
+static struct pci_id_info pci_tbl[] __initdata = {
 	{ "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff,
 	  PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
 	{ "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff,
@@ -275,7 +276,7 @@
 struct chip_info {
 	int io_size;
 	int flags;
-} static cap_tbl[] = {
+} static cap_tbl[] __initdata = {
 	{128, CanHaveMII, },
 	{128, CanHaveMII, },
 };
@@ -398,7 +399,7 @@
    well when dynamically adding drivers.  So instead we detect just the
    cards we know about in slot order. */
 
-static int pci_etherdev_probe(struct device *dev, struct pci_id_info pci_tbl[])
+static int __init pci_etherdev_probe(struct device *dev, struct pci_id_info pci_tbl[])
 {
 	int cards_found = 0;
 	int pci_index = 0;
@@ -506,7 +507,7 @@
 }
 
 #ifndef MODULE
-int via_rhine_probe(struct device *dev)
+int __init via_rhine_probe(struct device *dev)
 {
 	static int did_version = 0;
 	if (!did_version++)
@@ -515,7 +516,7 @@
 }
 #endif
 
-static struct device *via_probe1(int pci_bus, int pci_devfn,
+static struct device * __init via_probe1(int pci_bus, int pci_devfn,
 								 struct device *dev, long ioaddr, int irq,
 								 int chip_id, int card_idx)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pci/compat.c linux.18p8/drivers/pci/compat.c
--- linux.vanilla/drivers/pci/compat.c	Fri Apr 21 12:46:24 2000
+++ linux.18p8/drivers/pci/compat.c	Fri Sep  8 17:05:10 2000
@@ -41,3 +41,31 @@
 		}
 	return PCIBIOS_DEVICE_NOT_FOUND;
 }
+
+/* 2.4 compatibility */
+
+unsigned long pci_resource_len (struct pci_dev *dev, int n_base)
+{
+        u32 l, sz;
+        int reg = PCI_BASE_ADDRESS_0 + (n_base << 2);
+
+        /* XXX temporarily disable I/O and memory decoding for this device? */
+
+        pci_read_config_dword (dev, reg, &l);
+        if (l == 0xffffffff)
+                return 0;
+
+        pci_write_config_dword (dev, reg, ~0);
+        pci_read_config_dword (dev, reg, &sz);
+        pci_write_config_dword (dev, reg, l);
+
+        if (!sz || sz == 0xffffffff)
+                return 0;
+        if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+                sz = ~(sz & PCI_BASE_ADDRESS_MEM_MASK);
+        } else {
+                sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff;
+        }
+
+        return sz + 1;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/pci/pcisyms.c linux.18p8/drivers/pci/pcisyms.c
--- linux.vanilla/drivers/pci/pcisyms.c	Fri Apr 21 12:46:24 2000
+++ linux.18p8/drivers/pci/pcisyms.c	Fri Sep  8 17:05:10 2000
@@ -40,6 +40,10 @@
 EXPORT_SYMBOL(pcibios_find_class);
 EXPORT_SYMBOL(pcibios_find_device);
 
+/* Forward compatibility */
+
+EXPORT_SYMBOL(pci_resource_len);
+
 /* Quirk info */
 
 #ifdef CONFIG_PCI_QUIRKS
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/rtc.c linux.18p8/drivers/sbus/char/rtc.c
--- linux.vanilla/drivers/sbus/char/rtc.c	Sat Sep  9 18:42:40 2000
+++ linux.18p8/drivers/sbus/char/rtc.c	Sun Sep 10 14:49:10 2000
@@ -1,4 +1,4 @@
-/* $Id: rtc.c,v 1.13 1998/08/26 10:29:44 davem Exp $
+/* $Id: rtc.c,v 1.13.2.1 2000/08/18 23:40:04 davem Exp $
  *
  * Linux/SPARC Real Time Clock Driver
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ChangeLog.ips linux.18p8/drivers/scsi/ChangeLog.ips
--- linux.vanilla/drivers/scsi/ChangeLog.ips	Sun Jun 11 21:44:15 2000
+++ linux.18p8/drivers/scsi/ChangeLog.ips	Tue Sep  5 21:54:35 2000
@@ -1,7 +1,22 @@
 IBM ServeRAID driver Change Log
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        4.20.14  - Update patch files for kernel 2.4.0-test5
+
+        4.20.13  - Fix some failure cases / reset code
+                 - Hook into the reboot_notifier to flush the controller
+                   cache
+
+        4.20.03 - Rename version to coincide with new release schedules
+                - Performance fixes
+                - Fix truncation of /proc files with cat
+                - Merge in changes through kernel 2.4.0test1ac21
+
+        4.10.13 - Fix for dynamic unload and proc file system
+
+        4.10.00 - Add support for ServeRAID 4M/4L
+
         4.00.06 - Fix timeout with initial FFDC command
-	
+
         4.00.05 - Remove wish_block from init routine
                 - Use linux/spinlock.h instead of asm/spinlock.h for kernels
                   2.3.18 and later
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ChangeLog.ncr53c8xx linux.18p8/drivers/scsi/ChangeLog.ncr53c8xx
--- linux.vanilla/drivers/scsi/ChangeLog.ncr53c8xx	Fri Apr 21 12:46:28 2000
+++ linux.18p8/drivers/scsi/ChangeLog.ncr53c8xx	Sat Sep  2 19:38:56 2000
@@ -1,12 +1,146 @@
-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
-
-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.
+Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version ncr53c8xx-3.4.1
+	- Provide OpenFirmare path through the proc FS on PPC.
+	- Remove trailing argument #2 from a couple of #undefs.
+
+Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version ncr53c8xx-3.4.0
+	- Remove the PROFILE C and SCRIPTS code.
+	  This facility was not this useful and thus was not longer 
+	  desirable given the increasing complexity of the driver code.
+	- Merges from FreeBSD sym-1.6.2 driver:
+	  * Clarify memory barriers needed by the driver for architectures 
+	    that implement a weak memory ordering.
+	- General cleanup:
+	  Move definitions for barriers and IO/MMIO operations to the 
+	  sym53c8xx_defs.h header files. They are now shared by the 
+	  both drivers.
+	  Use SCSI_NCR_IOMAPPED instead of NCR_IOMAPPED.
+
+Thu May 11   12:30 2000 Pam Delaney (pam.delaney@lsil.com)
+	* revision 3.3b
+ 
+Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2i
+	- Return value 1 (instead of 0) from the driver setup routine.
+	- Let the driver also attach controllers that have been set to 
+	  OFF in the NVRAM as it did prior to revision 3.2g.
+
+Sat Apr 1  12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2h
+	- Fix a compilation problem on Alpha introduced in version 3.2g.
+          (`port' changed to `base_io').
+	- Move from `sym' to this driver a tiny change for __sparc__ that 
+	  applies to cache line size (? Probably from David S Miller).
+	- Make sure no data transfer will happen for Scsi_Cmnd requests 
+	  that supply SCSI_DATA_NONE direction (this avoids some BUG() 
+	  statement in the PCI code when a data buffer is also supplied).
+
+Thu Mar 16   9:30 2000 Pam Delaney (pam.delaney@lsil.com)
+	* revision 3.3b-3
+ 	- Added exclusion for the 53C1010 and 53C1010_66 chips
+	  to the driver (change to sym53c8xx_comm.h).
+
+Mon March 6  23:15 2000 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2g
+	- Add the file sym53c8xx_comm.h that collects code that should 
+	  be shared by sym53c8xx and ncr53c8xx drivers. For now, it is  
+	  a header file that is only included by the ncr53c8xx driver, 
+	  but things will be cleaned up later. This code addresses 
+	  notably:
+	  * Chip detection and PCI related initialisations
+	  * NVRAM detection and reading
+	  * DMA mapping
+	  * Boot setup command
+	  * And some other ...
+	- Add support for the new dynamic dma mapping kernel interface.
+	  Requires Linux-2.3.47 (tested with pre-2.3.47-6).
+	- Get data transfer direction from the scsi command structure 
+	  (Scsi_Cmnd) when this information is available.
+
+Mon March 6  23:15 2000 Gerard Roudier (groudier@club-internet.fr)
+        * revision 3.2g
+        - Add the file sym53c8xx_comm.h that collects code that should
+          be shared by sym53c8xx and ncr53c8xx drivers. For now, it is
+          a header file that is only included by the ncr53c8xx driver,
+          but things will be cleaned up later. This code addresses
+          notably:
+          * Chip detection and PCI related initialisations
+          * NVRAM detection and reading
+          * DMA mapping
+          * Boot setup command
+          * And some other ...
+        - Add support for the new dynamic dma mapping kernel interface.
+          Requires Linux-2.3.47 (tested with pre-2.3.47-6).
+        - Get data transfer direction from the scsi command structure
+          (Scsi_Cmnd) when this information is available.
+
+Fri Jan 14 14:00 2000 Pam Delaney (pam.delaney@lsil.com)
+	* revision pre-3.3b-1
+	- Merge parallel driver series 3.31 and 3.2e 
+
+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.  
+	- Built off of version 3.30
+
+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.
+	- Built off of version 3.2c
+
+Sat Jan 8  22:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2e
+	- Add year 2000 copyright.
+	- Display correctly bus signals when bus is detected wrong.
+	- Remove the dead code that broke driver 3.2d.
+
+Mon Dec 6  22:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2d
+	- Change messages written by the driver at initialisation and 
+	  through the /proc FS (rather cosmetic changes that consist in
+	  printing out the PCI bus number and device/function).
+	- Get rid of the old PCI bios interface, but preserve kernel 2.0 
+	  compatibility from a simple wrapper.
+	- Remove the compilation condition about having to acquire the 
+	  io_request_lock since it seems to be a definite feature now.:)
+	- proc_dir structure no longer needed for kernel >= 2.3.27.
+	- Change the driver detection code by the sym53c8xx one, modulo 
+	  some minor changes. The driver can now attach any number of 
+	  controllers (>40) and does no longer hoger stack space at 
+	  initialisation.
+	- Definitely disable overlapped PCI arbitration for all dual 
+	  function chips, since I cannot make sure for what chip revisions 
+	  it is actually safe.
+	- Add support for the SYM53C1510D.
+	- Update the poor Tekram sync factor table.
+	- Remove the compilation condition about having to acquire the 
+	  io_request_lock since it seems to be a definite feature now.:)
+	- proc_dir structure no longer needed for kernel >= 2.3.27.
+
+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
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ChangeLog.sym53c8xx linux.18p8/drivers/scsi/ChangeLog.sym53c8xx
--- linux.vanilla/drivers/scsi/ChangeLog.sym53c8xx	Fri Apr 21 12:46:28 2000
+++ linux.18p8/drivers/scsi/ChangeLog.sym53c8xx	Sat Sep  2 19:38:56 2000
@@ -1,23 +1,279 @@
-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.   
+Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.1
+	- Provide OpenFirmare path through the proc FS on PPC.
+	- Download of on-chip SRAM using memcpy_toio() doesn't work 
+	  on PPC. Restore previous method (MEMORY MOVE from SCRIPTS).
+	- Remove trailing argument #2 from a couple of #undefs.
 
-Sun May 9  15:00 1999 Gerard Roudier (groudier@club-internet.fr)
-	* version sym53c8xx-1.3f
+Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.7.0
+	- Remove the PROFILE C and SCRIPTS code.
+	  This facility was not this useful and thus was not longer 
+	  desirable given the increasing complexity of the driver code.
+	- Merges from FreeBSD sym-1.6.2 driver:
+	  * Clarify memory barriers needed by the driver for architectures 
+	    that implement a weak memory ordering.
+	  * Simpler handling of illegal phases and data overrun from 
+	    SCRIPTS. These errors are now immediately reported to 
+	    the C code by an interrupt.
+	  * Sync the residual handling code with sym-1.6.2 and now 
+	    report `resid' to user for linux version >= 2.3.99 
+	- General cleanup:
+	  Move definitions for barriers and IO/MMIO operations to the 
+	  sym53c8xx_defs.h header files. They are now shared by the 
+	  both drivers.
+	  Remove unused options that claimed to optimize for the 896.
+	  If fact, they were not this clever. :)
+	  Use SCSI_NCR_IOMAPPED instead of NCR_IOMAPPED.
+	  Remove a couple of unused fields from data structures.
+
+Thu May 11 12:40 2000 Pam Delaney (pam.delaney@lsil.com)
+	* version sym53c8xx-1.6b
+	- Merged version.
+
+Mon Apr 24 12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5m
+	- Return value 1 (instead of 0) from the driver setup routine.
+	- Donnot enable PCI DAC cycles. This just broke support for 
+	  SYM534C896 on sparc64. Problem fixed by David S. Miller.
+
+Fri Apr 14 9:00 2000 Pam Delaney (pam.delaney@lsil.com)
+	* version sym53c8xx-1.6b-9
+	- Added 53C1010_66 support.
+	- Small fix to integrity checking code.
+	- Removed requirement for integrity checking if want to run
+	  at ultra 3.
+ 
+Sat Apr 1  12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5l
+	- Tiny change for __sparc__ appeared in 2.3.99-pre4.1 that 
+	  applies to cache line size (? Probably from David S Miller).
+	- Make sure no data transfer will happen for Scsi_Cmnd requests 
+	  that supply SCSI_DATA_NONE direction (this avoids some BUG() 
+	  statement in the PCI code when a data buffer is also supplied).
+
+Sat Mar 11 12:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.6b-5
+	- Test against expected data transfer direction from SCRIPTS.
+	- Add support for the new dynamic dma mapping kernel interface.
+	  Requires Linux-2.3.47 (tested with pre-2.3.47-6).
+	  Many thanks to David S. Miller for his preliminary changes 
+	  that have been useful guidelines.
+	- Get data transfer direction from the scsi command structure 
+	  (Scsi_Cmnd) with kernels that provide this information.
+
+Mon Mar  6 23:30 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5k
+	- Test against expected data transfer direction from SCRIPTS.
+	- Revert the change in 'ncr_flush_done_cmds()' but unmap the 
+	  scsi dma buffer prior to queueing the command to our done 
+	  list.
+	- Miscellaneous (minor) fixes in the code added in driver 
+	  version 1.5j.
+
+Mon Feb 14 4:00 2000 Pam Delaney (pam.delaney@lsil.com)
+ 	* version sym53c8xx-pre-1.6b-2.
+	- Updated the SCRIPTS error handling of the SWIDE
+	  condition - to remove any reads of the sbdl
+	  register. Changes needed because the 896 and 1010
+	  chips will check parity in some special circumstances.
+	  This will cause a parity error interrupt if not in
+	  data phase.  Changes based on those made in the
+	  FreeBSD driver version 1.3.2.
+
+Sun Feb 20 11:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5j
+	- Add support for the new dynamic dma mapping kernel interface.
+	  Requires Linux-2.3.47 (tested with pre-2.3.47-6).
+	  Many thanks to David S. Miller for his preliminary changes 
+	  that have been useful guidelines, for having reviewed the 
+	  code and having tested this driver version on Ultra-Sparc.
+	- 2 tiny bugs fixed in the PCI wrapper that provides support 
+	  for early kernels without pci device structure.
+	- Get data transfer direction from the scsi command structure 
+	  (Scsi_Cmnd) with kernels that provide this information.
+	- Fix an old bug that only affected 896 rev. 1 when driver 
+	  profile support option was set in kernel configuration.
+
+Fri Jan 14 14:00 2000 Pam Delaney (pam.delaney@lsil.com)
+ 	* version sym53c8xx-pre-1.6b-1.
+	- Merge parallel driver series 1.61 and 1.5e 
+
+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.
+	- Based off of 1.60
+
+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.
+	- Based off of 1.5f
+
+Sat Jan 8  22:00 2000 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5h
+	- Add year 2000 copyright.
+	- Display correctly bus signals when bus is detected wrong.
+	- Some fix for Sparc from DSM that went directly to kernel tree.
+
+Mon Dec 6  22:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5g
+	- Change messages written by the driver at initialisation and 
+	  through the /proc FS (rather cosmetic changes that consist in
+	  printing out the PCI bus number and PCI device/function).
+	- Ensure the SCRIPTS processor is stopped while calibrating the 
+	  SCSI clock (the initialisation code has been a bit reworked).
+	  Change moved to the FreeBSD sym_hipd driver).
+	- Some fixes in the MODIFY_DP/IGN_RESIDUE code and residual 
+	  calculation (moved from FreeBSD sym_hipd driver).
+	- Add NVRAM support for Tekram boards that use 24C16 EEPROM.
+	  Code moved from the FreeBSD sym_hipd driver, since it has 
+	  been that one that got this feature first.
+	- Definitely disable overlapped PCI arbitration for all dual 
+	  function chips, since I cannot make sure for what chip revisions 
+	  it is actually safe.
+	- Add support for the SYM53C1510D (also for ncr53c8xx).
+	- Fix up properly the PCI latency timer when needed or asked for.
+	- Get rid of the old PCI bios interface, but preserve kernel 2.0 
+	  compatibility from a simple wrapper.
+	- Update the poor Tekram sync factor table.
+	- Fix in a tiny 'printk' bug that may oops in case of extended 
+	  errors (unrecovered parity error, data overrun, etc ...)
+	  (Sent by Pamela Delaney from LSILOGIC)
+	- Remove the compilation condition about having to acquire the 
+	  io_request_lock since it seems to be a definite feature now.:)
+	- Change get_pages by GetPages since Linux >= 2.3.27 now wants 
+	  get_pages to ever be used as a kernel symbol (from 2.3.27).
+	- proc_dir structure no longer needed for kernel >= 2.3.27.
+
+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
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/Config.in linux.18p8/drivers/scsi/Config.in
--- linux.vanilla/drivers/scsi/Config.in	Fri Apr 21 12:46:28 2000
+++ linux.18p8/drivers/scsi/Config.in	Sun Sep 10 14:44:08 2000
@@ -94,7 +94,6 @@
     int  '  default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8
     int  '  maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32
     int  '  synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20
-    bool '  enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE
     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
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/Makefile linux.18p8/drivers/scsi/Makefile
--- linux.vanilla/drivers/scsi/Makefile	Fri Apr 21 12:46:30 2000
+++ linux.18p8/drivers/scsi/Makefile	Sun Sep 10 15:14:38 2000
@@ -5,6 +5,10 @@
 # unless it's something special (ie not a .c file).
 #
 
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
 L_TARGET := scsi.a
 L_OBJS   := 
 M_OBJS   := 
@@ -705,3 +709,4 @@
 
 sd_mod.o: sd.o sd_ioctl.o
 	$(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/README.ibmmca linux.18p8/drivers/scsi/README.ibmmca
--- linux.vanilla/drivers/scsi/README.ibmmca	Fri Apr 21 12:46:31 2000
+++ linux.18p8/drivers/scsi/README.ibmmca	Sat Jul 29 18:07:34 2000
@@ -10,10 +10,10 @@
   General Public License. Originally written by Martin Kolinek, December 1995.
          Officially maintained by Michael Lang since January 1999.
 	   
- 	                       Version 3.1e
+ 	                       Version 3.2
 	
 	
-   Last update: 20 February 1999
+   Last update: 29 July 2000
 
 
    Authors of this Driver
@@ -23,7 +23,8 @@
     - Klaus Kudielka (multiple SCSI-host management/detection, adaption to
                       Linux Kernel 2.1.x, module support)
     - Michael Lang (assigning original pun,lun mapping, dynamical ldn 
-                    assignment, this file, patch, official driver maintenance)
+                    assignment, this file, patch, official driver maintenance
+		    and subsequent pains related with the driver :-))
 
    Table of Contents
    -----------------
@@ -51,7 +52,11 @@
      5.3 Bugreports
      5.4 Support WWW-page
    6 References
-   7 Trademarks
+   7 Credits to
+     7.1 People
+     7.2 Sponsors & Supporters
+   8 Trademarks
+   9 Disclaimer
 
                               * * *
 
@@ -64,7 +69,7 @@
    quite outdated. The history of the driver development is also kept inside 
    here. Multiple historical developments have been summarized to shorten the 
    textsize a bit. At the end of this file you can find a small manual for 
-   this driver and hints to get it running even on your machine (hopefully).
+   this driver and hints to get it running on your machine.
 
    2 Driver Description
    --------------------
@@ -74,27 +79,35 @@
    Microchannel-bus support is enabled, as the IBM SCSI-subsystem needs the
    Microchannel. In a next step, a free interrupt is chosen and the main
    interrupt handler is connected to it to handle answers of the SCSI-
-   subsystem(s). In a further step, it is checked, wether there was a forced
-   detection of the adapter via the kernel commandline, where the I/O port
-   and the SCSI-subsystem id can be specified. The next step checks if there
-   is an integrated SCSI-subsystem installed. This register area is fixed 
-   through all IBM PS/2 MCA-machines and appears as something like a virtual 
-   slot 10 of the MCA-bus. If POS-register 2 is not 0xff, there must be a SCSI-
+   subsystem(s). If the F/W SCSI-adapter is forced by the BIOS to use IRQ11
+   instead of IRQ14, IRQ11 is used for the IBM SCSI-2 F/W adapter. In a 
+   further step it is checked, if the adapter gets detected by force from
+   the kernel commandline, where the I/O port and the SCSI-subsystem id can 
+   be specified. The next step checks if there is an integrated SCSI-subsystem
+   installed. This register area is fixed through all IBM PS/2 MCA-machines 
+   and appears as something like a virtual slot 10 of the MCA-bus. On most
+   PS/2 machines, the POS registers of slot 10 are set to 0xff or 0x00 if not
+   integrated SCSI-controller is available. But on certain PS/2s, like model 
+   9595, this slot 10 is used to store other information which at earlier
+   stage confused the driver and resulted in the detection of some ghost-SCSI. 
+   If POS-register 2 and 3 are not 0x00 and not 0xff, but all other POS
+   registers are either 0xff or 0x00, there must be an integrated SCSI-
    subsystem present and it will be registered as IBM Integrated SCSI-
    Subsystem. The next step checks, if there is a slot-adapter installed on 
    the MCA-bus. To get this, the first two POS-registers, that represent the 
    adapter ID are checked. If they fit to one of the ids, stored in the 
-   adapter list, a SCSI-subsystem is assumed to be found and will be 
+   adapter list, a SCSI-subsystem is assumed to be found in a slot and will be 
    registered. This check is done through all possible MCA-bus slots to allow 
    more than one SCSI-adapter to be present in the PS/2-system and this is 
    already the first point of problems. Looking into the technical reference 
    manual for the IBM PS/2 common interfaces, the POS2 register must have 
-   different interpretation of its single bits. While one can assume, that the
-   integrated subsystem has a fix I/O-address at 0x3540 - 0x3547, further
-   installed IBM SCSI-adapters must use a different I/O-address. This is
-   expressed by bit 1 to 3 of POS2 (multiplied by 8 + 0x3540). Bits 2 and 3 
-   are reserved for the integrated subsystem, but not for the adapters! The
-   following list shows, how the bits of POS2 and POS3 should be interpreted.
+   different interpretation of its single bits to avoid overlapping I/O
+   regions. While one can assume, that the integrated subsystem has a fix 
+   I/O-address at 0x3540 - 0x3547, further installed IBM SCSI-adapters must 
+   use a different I/O-address. This is expressed by bit 1 to 3 of POS2 
+   (multiplied by 8 + 0x3540). Bits 2 and 3 are reserved for the integrated 
+   subsystem, but not for the adapters! The following list shows, how the 
+   bits of POS2 and POS3 should be interpreted.
    
    The POS2-register of all PS/2 models' integrated SCSI-subsystems has the 
    following interpretation of bits:
@@ -102,20 +115,25 @@
                            Bit 3 - 2 : Reserved
                            Bit 1     : 8k NVRAM Disabled
                            Bit 0     : Chip Enable (EN-Signal)
-   The POS3-register is interpreted as follows (for ALL IBM SCSI-subsys.):
+   The POS3-register is interpreted as follows (for most IBM SCSI-subsys.):
                            Bit 7 - 5 : SCSI ID
                            Bit 4 - 0 : Reserved = 0
-   (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
-   Interfaces (1991)"). 
-   In short words, this means, that IBM PS/2 machines only support 1 single 
-   subsystem by default. But (additional) slot-adapters must have another 
-   configuration on pos2 in order to be enabled to use more than one IBM SCSI-
-   subsystem, e.g. for a network server. From tests with the IBM SCSI Adapter 
-   w/cache, the POS2-register for slot adapters should be interpreted in the 
-   following way:
-                           Bit 7 - 4 : Chip Revision ID (Release)
-                           Bit 3 - 1 : port offset factor ( * 8 + 0x3540 )
-                           Bit 0     : Chip Enable (EN-Signal)
+   The slot-adapters have different interpretation of these bits. The IBM SCSI
+   adapter (w/Cache) and the IBM SCSI-2 F/W adapter use the following
+   interpretation of the POS2 register:
+                           Bit 7 - 4 : ROM Segment Address Select
+			   Bit 3 - 1 : Adapter I/O Address Select (*8+0x3540)
+			   Bit 0     : Adapter Enable (EN-Signal)
+   and for the POS3 register:
+                           Bit 7 - 5 : SCSI ID 
+			   Bit 4     : Fairness Enable (SCSI ID3 f. F/W)
+			   Bit 3 - 0 : Arbitration Level
+   The most modern product of the series is the IBM SCSI-2 F/W adapter, it 
+   allows dual-bus SCSI and SCSI-wide addressing, which means, PUNs may be
+   between 0 and 15. Here, Bit 4 is the high-order bit of the 4-bit wide
+   adapter PUN expression. In short words, this means, that IBM PS/2 machines 
+   can only support 1 single integrated subsystem by default. Additional
+   slot-adapters get ports assigned by the automatic configuration tool.
 
    One day I found a patch in ibmmca_detect(), forcing the I/O-address to be 
    0x3540 for integrated SCSI-subsystems, there was a remark placed, that on 
@@ -156,12 +174,18 @@
    number or pun, also called the scsi id, this is the number you select
    with hardware jumpers), and each physical unit can have up to 8 
    "logical units" (each identified by logical unit number, or lun, 
-   between 0 and 7). 
+   between 0 and 7). The IBM SCSI-2 F/W adapter offers this on up to two
+   busses and provides support for 30 logical devices at the same time, where
+   in wide-addressing mode you can have 16 puns with 32 luns on each device.
+   This section dexribes you the handling of devices on non-F/W adapters.
+   Just imagine, that you can have 16 * 32 = 512 devices on a F/W adapter
+   which means a lot of possible devices for such a small machine.
 
    Typically the adapter has pun=7, so puns of other physical units
-   are between 0 and 6. Almost all physical units have only one   
-   logical unit, with lun=0. A CD-ROM jukebox would be an example of 
-   a physical unit with more than one logical unit.
+   are between 0 and 6(15). On a wide-adapter a pun higher than 7 is
+   possible, but is normally not used. Almost all physical units have only 
+   one logical unit, with lun=0. A CD-ROM jukebox would be an example of a 
+   physical unit with more than one logical unit.
 
    The embedded microprocessor of the IBM SCSI-subsystem hides the complex
    two-dimensional (pun,lun) organization from the operating system.
@@ -169,7 +193,8 @@
    checks, on its own, all 56 possible (pun,lun) combinations, and the first 
    15 devices found are assigned into a one-dimensional array of so-called 
    "logical devices", identified by "logical device numbers" or ldn. The last 
-   ldn=15 is reserved for the subsystem itself.
+   ldn=15 is reserved for the subsystem itself. Wide adapters may have 
+   to check up to 15 * 8 = 120 pun/lun combinations.
    
    2.3 SCSI-Device Recognition and dynamical ldn Assignment
    --------------------------------------------------------
@@ -177,8 +202,12 @@
    numbers are also hidden. The two possibilities to get around this problem
    is to offer fake pun/lun combinations to the operating system or to 
    delete the whole mapping of the adapter and to reassign the ldns, using
-   the immediate assign command of the SCSI-subsystem. At the beginning of the
-   development of this driver, the following approach was used:
+   the immediate assign command of the SCSI-subsystem for probing through
+   all possible pun/lun combinations. a ldn is a "logical device number"
+   which is used by IBM SCSI-subsystems to access some valid SCSI-device.
+   At the beginning of the development of this driver, the following approach 
+   was used:
+   
    First, the driver checked the ldn's (0 to 6) to find out which ldn's
    have devices assigned. This was done by the functions check_devices() and
    device_exists(). The interrupt handler has a special paragraph of code
@@ -199,7 +228,7 @@
    and later, realizes the device recognition in the following way:
    The physical SCSI-devices on the SCSI-bus are probed via immediate_assign- 
    and device_inquiry-commands, that is all implemented in a completely new
-   made check_devices() subroutine. This delivers a exact map of the physical
+   made check_devices() subroutine. This delivers an exact map of the physical
    SCSI-world that is now stored in the get_scsi[][]-array. This means,
    that the once hidden pun,lun assignment is now known to this driver.
    It no longer believes in default-settings of the subsystem and maps all
@@ -230,7 +259,7 @@
    can be different from the old, faked puns. Therefore, Linux will eventually
    change /dev/sdXXX assignments and prompt you for corrupted superblock
    repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!!
-   You have to reboot (CTRL-D) with a old kernel and set the /etc/fstab-file
+   You have to reboot (CTRL-D) with an old kernel and set the /etc/fstab-file
    entries right. After that, the system should come up as errorfree as before.
    If your boot-partition is not coming up, also edit the /etc/lilo.conf-file
    in a Linux session booted on old kernel and run lilo before reboot. Check
@@ -332,17 +361,19 @@
    ----------------------------------
    The following IBM SCSI-subsystems are supported by this driver:
    
-     - IBM Fast SCSI-2 Adapter
+     - IBM Fast/Wide SCSI-2 Adapter
      - IBM 7568 Industrial Computer SCSI Adapter w/cache
      - IBM Expansion Unit SCSI Controller
      - IBM SCSI Adapter w/Cache
      - IBM SCSI Adapter
      - IBM Integrated SCSI Controller
+     - All clones, 100% compatible with the chipset and subsystem command
+       system of IBM SCSI-adapters (forced detection)
      
    2.14 Linux Kernel Versions
    --------------------------
    The IBM SCSI-subsystem low level driver is prepared to be used with
-   all versions of Linux between 2.0.x and 2.2.x. The compatibility checks
+   all versions of Linux between 2.0.x and 2.4.x. The compatibility checks
    are fully implemented up from version 3.1e of the driver. This means, that
    you just need the latest ibmmca.h and ibmmca.c file and copy it in the
    linux/drivers/scsi directory. The code is automatically adapted during 
@@ -717,18 +748,149 @@
       addition more flexibility.
    - Michael Lang
 
+   Apr 23, 2000 (v3.2pre1)
+   1) During a very long time, I collected a huge amount of bugreports from
+      various people, trying really quite different things on their SCSI-
+      PS/2s. Today, all these bugreports are taken into account and should be
+      mostly solved. The major topics were:
+      - Driver crashes during boottime by no obvious reason.
+      - Driver panics while the midlevel-SCSI-driver is trying to inquire
+        the SCSI-device properties, even though hardware is in perfect state.
+      - Displayed info for the various slot-cards is interpreted wrong.
+      The main reasons for the crashes were two:
+      1) The commands to check for device information like INQUIRY, 
+         TEST_UNIT_READY, REQUEST_SENSE and MODE_SENSE cause the devices
+	 to deliver information of up to 255 bytes. Midlevel drivers offer
+	 1024 bytes of space for the answer, but the IBM-SCSI-adapters do
+	 not accept this, as they stick quite near to ANSI-SCSI and report
+	 a COMMAND_ERROR message which causes the driver to panic. The main
+	 problem was located around the INQUIRY command. Now, for all the
+	 mentioned commands, the buffersize, sent to the adapter is at 
+	 maximum 255 which seems to be a quite reasonable solution. 
+	 TEST_UNIT_READY gets a buffersize of 0 to make sure, that no 
+	 data is transferred in order to avoid any possible command failure.
+      2) On unsuccessful TEST_UNIT_READY, the midlevel-driver has to send
+         a REQUEST_SENSE in order to see, where the problem is located. This
+	 REQUEST_SENSE may have various length in its answer-buffer. IBM
+	 SCSI-subsystems report a command failure, if the returned buffersize
+	 is different from the sent buffersize, but this can be supressed by
+	 a special bit, which is now done and problems seem to be solved.
+   2) Code adaption to all kernel-releases. Now, the 3.2 code compiles on 
+      2.0.x, 2.1.x, 2.2.x and 2.3.x kernel releases without any code-changes.
+   3) Commandline-parameters are recognized again, even under Kernel 2.3.x or
+      higher.
+   - Michael Lang   
+
+   April 27, 2000 (v3.2pre2)
+   1) Bypassed commands get read by the adapter by one cycle instead of two.
+      This increases SCSI-performance.
+   2) Synchronous datatransfer is provided for sure to be 5 MHz on older
+      SCSI and 10 MHz on internal F/W SCSI-adapter.
+   3) New commandline parameters allow to force the adapter to slow down while
+      in synchronous transfer. Could be helpful for very old devices.
+   - Michael Lang
+   
+   June 2, 2000 (v3.2pre5)
+   1) Added Jim Shorney's contribution to make the activity indicator
+      flashing in addition to the LED-alphanumeric display-panel on
+      models 95A. To be enabled to choose this feature freely, a new
+      commandline parameter is added, called 'activity'.
+   2) Added the READ_CONTROL bit for test_unit_ready SCSI-command.
+   3) Added some suppress_exception bits to read_device_capacity and
+      all device_inquiry occurences in the driver code.
+   4) Complaints about the various KERNEL_VERSION implementations are
+      taken into account. Every local_LinuxKernelVersion occurence is
+      now replaced by KERNEL_VERSION, defined in linux/version.h. 
+      Corresponding changes were applied to ibmmca.h, too. This was a
+      contribution to all kernel-parts by Philipp Hahn.
+   - Michael Lang
+   
+   July 17, 2000 (v3.2pre8)
+   A long period of collecting bugreports from all corners of the world
+   now lead to the following corrections to the code:
+   1) SCSI-2 F/W support crashed with a COMMAND ERROR. The reason for this 
+      was, that it is possible to disbale Fast-SCSI for the external bus.
+      The feature-control command, where this crash appeared regularly tried
+      to set the maximum speed of 10MHz synchronous transfer speed and that
+      reports a COMMAND ERROR, if external bus Fast-SCSI is disabled. Now,
+      the feature-command probes down from maximum speed until the adapter 
+      stops to complain, which is at the same time the maximum possible
+      speed selected in the reference program. So, F/W external can run at
+      5 MHz (slow-) or 10 MHz (fast-SCSI). During feature probing, the 
+      COMMAND ERROR message is used to detect if the adapter does not complain.
+   2) Up to now, only combined busmode is supported, if you use external
+      SCSI-devices, attached to the F/W-controller. If dual bus is selected,
+      only the internal SCSI-devices get accessed by Linux. For most 
+      applications, this should do fine. 
+   3) Wide-SCSI-addressing (16-Bit) is now possible for the internal F/W
+      bus on the F/W adapter. If F/W adapter is detected, the driver
+      automatically uses the extended PUN/LUN <-> LDN mapping tables, which
+      are now new from 3.2pre8. This allows PUNs between 0 and 15 and should
+      provide more fun with the F/W adapter.
+   4) Several machines use the SCSI: POS registers for internal/undocumented
+      storage of system relevant info. This confused the driver, mainly on
+      models 9595, as it expected no onboard SCSI only, if all POS in
+      the integrated SCSI-area are set to 0x00 or 0xff. Now, the mechanism
+      to check for integrated SCSI is much more restrictive and these problems
+      should be history.
+   - Michael Lang          
+
+   July 18, 2000 (v3.2pre9)
+   This develop rather quickly at the moment. Two major things were still
+   missing in 3.2pre8:
+   1) The adapter PUN for F/W adapters has 4-bits, while all other adapters
+      have 3-bits. This is now taken into account for F/W.
+   2) When you select CONFIG_IBMMCA_SCSI_ORDER_STANDARD, you should 
+      normally get the inverse probing order of your devices on the SCSI-bus.
+      The ANSI device order gets scrambled in version 3.2pre8!! Now, a new
+      and tested algorithm inverts the device-order on the SCSI-bus and
+      automatically avoids accidental access to whatever SCSI PUN the adapter 
+      is set and works with SCSI- and Wide-SCSI-addressing.
+   - Michael Lang
+
+   July 23, 2000 (v3.2pre10 unpublished) 
+   1) LED panel display supports wide-addressing in ibmmca=display mode.
+   2) Adapter-information and autoadaption to address-space is done.
+   3) Auto-probing for maximum synchronous SCSI transfer rate is working.
+   4) Optimization to some embedded function calls is applied.
+   5) Added some comment for the user to wait for SCSI-devices beeing probed.
+   6) Finished version 3.2 for Kernel 2.4.0. It least, I thought it is but...
+   - Michael Lang
+   
+   July 26, 2000 (v3.2pre11)
+   1) I passed a horrible weekend getting mad with NMIs on kernel 2.2.14 and
+      a model 9595. Asking around in the community, nobody except of me has
+      seen such errors. Weired, but I am trying to recompile everything on
+      the model 9595. Maybe, as I use a specially modified gcc, that could
+      cause problems. But, it was not the reason. The true background was,
+      that the kernel was compiled for i386 and the 9595 has a 486DX-2. 
+      Normally, no troubles should appear, but for this special machine,
+      only the right processor support is working fine!
+   2) Previous problems with synchronous speed, slowing down from one adapter 
+      to the next during probing are corrected. Now, local variables store
+      the synchronous bitmask for every single adapter found on the MCA bus.
+   3) LED alphanumeric panel support for XX95 systems is now showing some
+      alive rotator during boottime. This makes sense, when no monitor is 
+      connected to the system. You can get rid of all display activity, if
+      you do not use any parameter or just ibmmcascsi=activity, for the 
+      harddrive activity LED, existant on all PS/2, except models 8595-XXX.
+      If no monitor is available, please use ibmmcascsi=display, which works
+      fine together with the linuxinfo utility for the LED-panel.
+   - Michael Lang
+   
+   July 29, 2000 (v3.2)
+   1) Submission of this driver for kernel 2.4test-XX and 2.2.17.
+   - Michael Lang
+   
    4 To do
    -------
+        - IBM SCSI-2 F/W external SCSI bus support in seperate mode.
 	- It seems that the handling of bad disks is really bad -
 	  non-existent, in fact.
         - More testing of the full driver-controlled dynamical ldn 
-          (re)mapping for up to 56 SCSI-devices.
-        - Support more of the SCSI-command set.
-	- Support some of the caching abilities, particularly Read Prefetch.
-	  This fetches data into the cache, which later gets hit by the
-	  regular Read Data. (<--- This is coming soon!!!!)
-        - Abort and Reset functions still slightly buggy or better say,
-	  it is the new episode, called SCREAM III.
+          (re)mapping for up to 56 SCSI-devices. I guess, it won't work
+	  at the moment, but nobody ever really tried it.
+        - Abort and Reset functions still slightly buggy.
 
    5 Users' Manual
    ---------------
@@ -749,7 +911,13 @@
 				
 		    where '-' stays dark, 'D' shows the SCSI-device id
 		    and 'A' shows the SCSI hostindex, beeing currently 
-		    accessed.
+		    accessed. During boottime, this will give the message
+		    
+		                SCSIini*
+				
+                    on the LED-panel, where the * represents a rotator, 
+		    showing the activity during the probing phase of the
+		    driver which can take up to two minutes per SCSI-adapter.
 	 adisplay   This works like display, but gives more optical overview 
 	            of the activities on the SCSI-bus. The display will have
 		    the following output:
@@ -761,7 +929,22 @@
 		    hostindex. If display nor adisplay is set, the internal
 		    PS/2 harddisk LED is used for media-activities. So, if
 		    you really do not have a system with a LED-display, you
-		    should not set display or adisplay.
+		    should not set display or adisplay. Keep in mind, that
+		    display and adisplay can only be used alternatively. It
+		    is not recommended to use this option, if you have some
+		    wide-addressed devices e.g. at the SCSI-2 F/W adapter in
+		    your system. In addition, the usage of the display for
+		    other tasks in parallel, like the linuxinfo-utility makes 
+		    no sense with this option.
+	 activity   This enables the PS/2 harddisk LED activity indicator.
+	            Most PS/2 have no alphanumeric LED display, but some
+		    indicator. So you should use this parameter to activate it.
+		    If you own model 9595 (Server95), you can have both, the 
+		    LED panel and the activity indicator in parallel. However,
+		    some PS/2s, like the 8595 do not have any harddisk LED 
+		    activity indicator, which means, that you must use the
+		    alphanumeric LED display if you want to monitor SCSI-
+		    activity.
 	 bypass     This commandline parameter forces the driver never to use
 	            SCSI-subsystems' integrated SCSI-command set. Except of
 		    the immediate assign, which is of vital importance for
@@ -775,7 +958,10 @@
 		    this flag will slow-down SCSI-accesses slightly, as the 
 		    software generated commands are always slower than the 
 		    hardware. Non-harddisk devices always get read/write-
-		    commands in bypass mode.
+		    commands in bypass mode. On the most recent releases of 
+		    the Linux IBM-SCSI-driver, the bypass command should be
+		    no longer a necessary thing, if you are sure about your
+		    SCSI-hardware!
 	 normal     This is the parameter, introduced on the 2.0.x development
 	            rail by ZP Gu. This parameter defines the SCSI-device
 		    scan order in the new industry standard. This means, that
@@ -789,6 +975,19 @@
 		    pun=6 gets sda and a harddisk at pun=0 gets sdb. If you
 		    like to have the same SCSI-device order, as in DOS, OS-9
 		    or OS/2, just use this parameter.
+         fast       SCSI-I/O in synchronous mode is done at 5 MHz for IBM-
+                    SCSI-devices. SCSI-2 Fast/Wide Adapter/A external bus
+                    should then run at 10 MHz if Fast-SCSI is enabled,
+                    and at 5 MHz if Fast-SCSI is disabled on the external
+                    bus. This is the default setting when nothing is 
+                    specified here.
+         medium     Synchronous rate is at 50% approximately, which means
+                    2.5 MHz for IBM SCSI-adapters and 5.0 MHz for F/W ext.
+                    SCSI-bus (when Fast-SCSI speed enabled on external bus).
+         slow       The slowest possible synchronous transfer rate is set. 
+                    This means 1.82 MHz for IBM SCSI-adapters and 2.0 MHz
+                    for F/W external bus at Fast-SCSI speed on the external
+		    bus.
 		    
    A further option is that you can force the SCSI-driver to accept a SCSI-
    subsystem at a certain I/O-address with a predefined adapter PUN. This
@@ -805,7 +1004,7 @@
         ibmmcascsi=adisplay,bypass
 	
    This will use the advanced display mode for the model 95 LED display and
-   every SCSI-command passed to a attached device will get bypassed in order
+   every SCSI-command passed to an attached device will get bypassed in order
    not to use any of the subsystem built-in commands.
    
         ibmmcascsi=display,0x3558,7
@@ -837,9 +1036,9 @@
 	with OS/2 and DOS, you have to activate this flag in the kernel
 	configuration or you should set 'ansi' as parameter for the kernel.
 	The parameter 'normal' sets the new industry standard, starting
-	from pun 0, scaning up to pun 6. This allows you to change your 
+	from pun 0, scanning up to pun 6. This allows you to change your 
 	opinion still after having already compiled the kernel.
-     Q: Why can I not find the IBM MCA SCSI support in the config menue?
+     Q: Why I cannot find the IBM MCA SCSI support in the config menue?
      A: You have to activate MCA bus support, first.
      Q: Where can I find the latest info about this driver?
      A: See the file MAINTAINERS for the current WWW-address, which offers
@@ -849,13 +1048,9 @@
      A: Just force it to be recognized by kernel parameters. See section 5.1.
      Q: The driver screws up, if it starts to probe SCSI-devices, is there
         some way out of it?
-     A: This is based on some problems with the driver. In such cases, send
-        e-mail to the maintainer. If you are owner of a model with the serial
-	number 95XX, just send as subject NOTIFY 95XX PROBLEM and the 
-	maintainer immediately knows about your problem. But please:
-	Check your hardware and only if it works fine with other operating
-	systems, send E-Mail to me to notify the troubles. See the homepage
-	for how to send bug-reports or please read the next Q/A, here:
+     A: Yes, that was some recognition problem of the correct SCSI-adapter
+        and its I/O base addresses. Upgrade your driver to the latest release
+	and it should be fine again.
      Q: I get a message: panic IBM MCA SCSI: command error .... , what can
         I do against this?
      A: Previously, I followed the way by ignoring command errors by using
@@ -867,8 +1062,8 @@
         ibmmcascsi=forgiveall. Are there other possibilities to prevent
 	such panics?
      A: No, get just the latest release of the driver and it should work 
-        better and better with increasing version number. Forget this
-	ibmmcascsi=forgiveall, as also ignorecmd are obsolete.
+        better and better with increasing version number. Forget about this
+	ibmmcascsi=forgiveall, as also ignorecmd are obsolete.!
      Q: Linux panics or stops without any comment, but it is probable, that my
         harddisk(s) have bad blocks.
      A: Sorry, the bad-block handling is still a feeble point of this driver,
@@ -893,10 +1088,45 @@
 	Astonishingly, reset works in most cases quite ok, but the harddisks
 	won't run in synchonous mode anymore after a reset, until you reboot.
      Q: Why does my XXX w/Cache adapter not use read-prefetch?
-     A: w/Cache technical manuals are incoming here, so if I understood the
-        command of read-prefetch, it should be an easy thing to get harddisks
-	read in read-prefetch with w/Cache controllers. Some weeks or months,
-	still ahead and a lot of work still to do, sigh ...
+     A: Ok, that is not completely possible. If a cache is present, the 
+        adapter tries to use it internally. Explicitly, one can use the cache
+	with a read prefetch command, maybe in future, but this requires
+	some major overhead of SCSI-commands that risks the performance to
+	go down more than it gets improved. Tests with that are running.
+     Q: I have a IBM SCSI-2 Fast/Wide adapter, it boots in some way and hangs.
+     A: Yes, that is understood, as for sure, your SCSI-2 Fast/Wide adapter
+        was in such a case recognized as integrated SCSI-adapter or something 
+	else, but not as the correct adapter. As the I/O-ports get assigned 
+	wrongly by that reason, the system should crash in most cases. You 
+	should upgrade to the latest release of the SCSI-driver. The 
+	recommended version is 3.2 or later. Here, the F/W support is in
+	a stable and reliable condition. Wide-addressing is in addition 
+	supported.
+     Q: I get a Ooops message and something like "killing interrupt".
+     A: The reason for this is that the IBM SCSI-subsystem only sends a 
+        termination status back, if some error appeared. In former releases
+	of the driver, it was not checked, if the termination status block
+	is NULL. From version 3.2, it is taken care of this.
+     Q: I have a F/W adapter and the driver sees my internal SCSI-devices,
+        but ignores the external ones.
+     A: Select combined busmode in the config-program and check for that
+        no SCSI-id on the external devices appears on internal devices.
+        Reboot afterwards. Dual busmode is supported, but works only for the
+	internal bus, yet. External bus is still ignored. Take care for your
+	SCSI-ids. If combined bus-mode is activated, on some adapters, 
+	the wide-addressing is not possible, so devices with ids between 8 
+	and 15 get ignored by the driver & adapter!
+     Q: I have a 9595 and I get a NMI during heavy SCSI I/O e.g. during fsck.
+        A COMMAND ERROR is reported and characters on the screen are missing.
+	Warm reboot is not possible. Things look like quite weired.
+     A: Check the processor type of your 9595. If you have an 80486 or 486DX-2
+        processor complex on your mainboard and you compiled a kernel that
+	supports 80386 processors, it is possible, that the kernel cannot
+	keep track of the PS/2 interrupt handling and stops on an NMI. Just
+	compile a kernel for the correct processor type of your PS/2 and
+	everything should be fine. This is necessary even if one assumes,
+	that some 80486 system should be downward compatible to 80386
+	software.
 	
    5.3 Bugreports
    --------------
@@ -909,7 +1139,9 @@
    Zubkoff, as Linus is burried in E-Mail and Leonard is supervising all
    SCSI-drivers and won't have the time left to look inside every single
    driver to fix a bug and especially DO NOT send modified code to Linus
-   Torvalds, which has not been checked here!!! Recently, I got a lot of 
+   Torvalds or Alan J. Cox which has not been checked here!!! They are both
+   quite burried in E-mail (as me, sometimes, too) and one should first check
+   for problems on my local teststand. Recently, I got a lot of 
    bugreports for errors in the ibmmca.c code, which I could not imagine, but
    a look inside some Linux-distribution showed me quite often some modified
    code, which did no longer work on most other machines than the one of the
@@ -934,23 +1166,36 @@
         http://www.uni-mainz.de/~langm000/linux.html
 	
    Here you can find info about the background of this driver, patches,
-   news and a bugreport form.
+   troubleshooting support, news and a bugreport form. Please check that
+   WWW-page regularly for latest hints.
+   
+   For the bugreport, please fill out the formular on the corresponding
+   WWW-page. Read the dedicated instructions and write as much as you
+   know about your problem. If you do not like such formulars, please send
+   some e-mail directly, but at least with the same information as required by
+   the formular.
+   
+   If you have extensive bugreports, including Ooops messages and 
+   screen-shots, please feel free to send it directly to the address
+   of the maintainer, too. The current address of the maintainer is:
+   
+            Michael Lang <langa2@kph.uni-mainz.de>
    
    6 References
    ------------
-   The source of information is "Update for the PS/2 Hardware 
-   Interface Technical Reference, Common Interfaces", September 1991, 
-   part number 04G3281, available in the U.S. for $21.75 at 
-   1-800-IBM-PCTB, elsewhere call your local friendly IBM 
-   representative. E.g. in Germany, "Hallo IBM" works really great.
-   In addition to SCSI subsystem, this update contains fairly detailed 
-   (at hardware register level) sections on diskette  controller,
-   keyboard controller, serial port controller, VGA, and XGA.
+   IBM Corp., "Update for the PS/2 Hardware Interface Technical Reference, 
+   Common Interfaces", Armonk, September 1991, PN 04G3281, 
+   (available in the U.S. for $21.75 at 1-800-IBM-PCTB or in Germany for
+   around 40,-DM at "Hallo IBM").
   
-   Additional information from "Personal System/2 Micro Channel SCSI
-   Adapter with Cache Technical Reference", March 1990, PN 68X2365,
-   probably available from the same source (or possibly found buried
-   in officemates desk).
+   IBM Corp., "Personal System/2 Micro Channel SCSI
+   Adapter with Cache Technical Reference", Armonk, March 1990, PN 68X2365.
+
+   IBM Corp., "Personal System/2 Micro Channel SCSI
+   Adapter Technical Reference", Armonk, March 1990, PN 68X2397.
+
+   IBM Corp., "SCSI-2 Fast/Wide Adapter/A Technical Reference - Dual Bus",
+   Armonk, March 1994, PN 83G7545.
  
    Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie-
    Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl.
@@ -965,14 +1210,101 @@
    Helmut Rompel, "IBM Computerwelt GUIDE", What is what bei IBM., Systeme *
    Programme * Begriffe, IWT-Verlag GmbH - Muenchen, 1988
    
-   7 Trademarks
+   7 Credits to
+   ------------
+   7.1 People
+   ----------
+   Klaus Grimm
+                who already a long time ago gave me the old code from the
+		SCSI-driver in order to get it running for some old machine
+		in our institute.
+   Martin Kolinek
+                who wrote the first release of the IBM SCSI-subsystem driver.
+   Chris Beauregard
+                who for a long time maintained MCA-Linux and the SCSI-driver
+		in the beginning. Chris, wherever you are: Cheers to you!
+   Klaus Kudielka
+                with whom in the 2.1.x times, I had a quite fruitful
+                cooperation to get the driver running as a module and to get
+		it running with multiple SCSI-adapters.
+   David Weinehall
+                for his excellent maintenance of the MCA-stuff and the quite 
+		detailed bug reports and ideas for this driver (and his 
+		patience ;-)).
+   Alan J. Cox  
+                for his bugreports and his bold activities in cross-checking
+		the driver-code with his teststand.
+		
+   7.2 Sponsors & Supporters
+   -------------------------
+   "Hallo IBM",
+   IBM-Deutschland GmbH
+                the service of IBM-Deutschland for customers. Their E-Mail
+		service is unbeatable. Whatever old stuff I asked for, I 
+		always got some helpful answers.
+   Karl-Otto Reimers,
+   IBM Klub - Sparte IBM Geschichte, Sindelfingen
+                for sending me a copy of the w/Cache manual from the 
+		IBM-Deutschland archives.
+   Harald Staiger
+                for his extensive hardware donations which allows me today
+		still to test the driver in various constellations.
+   Erich Fritscher
+                for his very kind sponsoring.
+   Louis Ohland,
+   Charles Lasitter
+                for support by shipping me an IBM SCSI-2 Fast/Wide manual.
+                In addition, the contribution of various hardware is quite 
+                decessive and will make it possible to add FWSR (RAID)
+                adapter support to the driver in the near future! So,
+                complaints about no RAID support won't remain forever.
+                Yes, folks, that is no joke, RAID support is going to rise!
+   Erik Weber
+                for the great deal we made about a model 9595 and the nice
+                surrounding equipment and the cool trip to Mannheim
+                second-hand computer market.
+   Anthony Hogbin
+                for his direct shipment of a SCSI F/W adapter, which allowed
+                me immediately on the first stage to try it on model 8557
+                together with onboard SCSI adapter and some SCSI w/Cache.
+   Andreas Hotz
+                for his support by memory and an IBM SCSI-adapter. Collecting
+                all this together now allows me to try really things with
+                the driver at maximum load and variety on various models in
+                a very quick and efficient way.
+   Peter Jennewein
+                for his model 30, which serves me as part of my teststand
+		and his cool remark about how you make an ordinary diskette
+		drive working and how to connect it to an IBM-diskette port.
+   Johannes Gutenberg-University, Mainz &
+   Institut fuer Kernphysik, MAMI
+                for the offered space, the link, placed on the central
+                homepage and the space to store and offer the driver and 
+		related material and the free working times, which allow
+                me to answer all your e-mail.
+                   
+   8 Trademarks
    ------------
    IBM, PS/2, OS/2, Microchannel are registered trademarks of International 
-   Business Machines Corp.
+   Business Machines Corporation
    
    MS-DOS is a registered trademark of Microsoft Corporation
    
-   OS-9 is a registered trademark of Microware Systems
+   Microware, OS-9 are registered trademarks of Microware Systems
+   
+   9 Disclaimer
+   ------------
+   Beside the GNU public license and the dependant disclaimers and disclaimers
+   concerning the Linux-kernel in special, this SCSI-driver comes without any
+   warranty. Its functionality is tested as good as possible on certain 
+   machines and combinations of computer hardware, which does not exclude,
+   that dataloss or severe damage of hardware is possible while using this
+   part of software on some arbitrary computer hardware or in combination 
+   with other software packages. It is highly recommended to make backup
+   copies of your data before using this software.
+   
+   This driver supports hardware, produced by International Business Machines
+   Corporation (IBM).
    
 ------
 Michael Lang 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/README.ncr53c8xx linux.18p8/drivers/scsi/README.ncr53c8xx
--- linux.vanilla/drivers/scsi/README.ncr53c8xx	Fri Apr 21 12:46:31 2000
+++ linux.18p8/drivers/scsi/README.ncr53c8xx	Thu Aug 31 14:50:52 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,7 +166,14 @@
 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
+897        Y         Y      FAST40    80 MB/s        Y             Y
+1510D      Y         Y      FAST40    80 MB/s        Y             Y
+1010       Y         Y      FAST80   160 MB/s        N             Y
+1010_66*   Y         Y      FAST80   160 MB/s        N             Y
+
+* Chip supports 33MHz and 66MHz PCI buses.
 
 
 Summary of other supported features:
@@ -156,21 +193,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 +260,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 +536,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 +629,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 +646,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 +654,54 @@
 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
-   Only apply to 860, 875 and 895 controllers.
+10.2.5  Ultra SCSI support
+   Only apply to 860, 875, 895, 895a, 896, 1010 and 1010_66 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:n    All ultra speeds enabled
+        ultra:2    Ultra2 enabled
+        ultra:1    Ultra enabled
+        ultra:0    Ultra speeds 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 +713,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 +724,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 +755,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 +766,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 +811,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 +848,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 +881,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 +1010,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 +1262,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 +1310,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
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/README.st linux.18p8/drivers/scsi/README.st
--- linux.vanilla/drivers/scsi/README.st	Fri Apr 21 12:46:31 2000
+++ linux.18p8/drivers/scsi/README.st	Mon Sep 11 21:20:33 2000
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Sun Apr 18 13:24:43 1999 by makisara@home
+Last modified: Tue Aug 15 15:54:46 2000 by makisara@kai.makisara.local
 
 
 BASICS
@@ -67,7 +67,7 @@
 In variable block mode, the byte count in write() determines the size
 of the physical block on tape. When reading, the drive reads the next
 tape block and returns to the user the data if the read() byte count
-is at least the block size. Otherwise the data is truncated.
+is at least the block size. Otherwise an error is returned.
 
 In fixed block mode, the data transfer between the drive and the
 driver is in multiples of the block size. The write() byte count must
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/atp870u.c linux.18p8/drivers/scsi/atp870u.c
--- linux.vanilla/drivers/scsi/atp870u.c	Fri Apr 21 12:46:28 2000
+++ linux.18p8/drivers/scsi/atp870u.c	Thu Aug 31 15:07:52 2000
@@ -1,11 +1,15 @@
 /* $Id: atp870u.c,v 1.0 1997/05/07 15:22:00 root Exp root $
  *  linux/kernel/atp870u.c
  *
- *  Copyright (C) 1997  Wu Ching Chen
+ *  Copyright (C) 1997	Wu Ching Chen
  *  2.1.x update (C) 1998  Krzysztof G. Baranowski
- *   
- * Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes 
- * 
+ *
+ * Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes
+ *
+ * Wu Ching Chen : NULL pointer fixes  2000/06/02
+ *		   support atp876 chip
+ *		   enable 32 bit fifo transfer
+ *		   support cdrom & remove device run ultra speed
  */
 
 #include <linux/module.h>
@@ -106,19 +110,19 @@
 	dev->in_int = 1;
 	workportu = dev->ioport;
 	tmport = workportu;
-	
-	if (dev->working != 0) 
+
+	if (dev->working != 0)
 	{
 		tmport += 0x1f;
 		j = inb(tmport);
-		if((j&0x80)==0)
+		if ((j & 0x80) == 0)
 		{
-			dev->in_int=0;
+			dev->in_int = 0;
 			return;
 		}
 
 		tmpcip = dev->pciport;
-		if ((inb(tmpcip) & 0x08) != 0) 
+		if ((inb(tmpcip) & 0x08) != 0)
 		{
 			tmpcip += 0x2;
 			for (k=0; k < 1000; k++)
@@ -130,7 +134,7 @@
 				if ((inb(tmpcip) & 0x01) == 0)
 				{
 					goto stop_dma;
-				}    
+				}
 			}
 		}
 stop_dma:
@@ -139,9 +143,9 @@
 		tmport -= 0x08;
 
 		i = inb(tmport);
-		if ((j & 0x40) == 0) 
+		if ((j & 0x40) == 0)
 		{
-			if ((dev->last_cmd & 0x40) == 0) 
+			if ((dev->last_cmd & 0x40) == 0)
 			{
 				dev->last_cmd = 0xff;
 			}
@@ -155,30 +159,32 @@
 		/*
 		 *	Remap wide devices onto id numbers
 		 */
-		 
+
 		if ((target_id & 0x40) != 0) {
 			target_id = (target_id & 0x07) | 0x08;
 		} else {
 			target_id &= 0x07;
 		}
-		
-		if (i == 0x85) 
+
+		if (i == 0x85)
 		{
 			/*
 			 *	Flip wide
 			 */
-			if (dev->wide_idu != 0) 
+			if (dev->wide_idu != 0)
 			{
 				tmport = workportu + 0x1b;
-				j = inb(tmport) & 0x0e;
-				j |= 0x01;
-				outb(j, tmport);
+				outb(0x01,tmport);
+				while ((inb(tmport) & 0x01) != 0x01)
+				{
+				   outb(0x01,tmport);
+				}
 			}
 			/*
 			 *	Issue more commands
 			 */
 			if (((dev->quhdu != dev->quendu) || (dev->last_cmd != 0xff)) &&
-			    (dev->in_snd == 0)) 
+			    (dev->in_snd == 0))
 			{
 				send_s870(h);
 			}
@@ -188,7 +194,7 @@
 			dev->in_int = 0;
 			return;
 		}
-		if (i == 0x21) 
+		if (i == 0x21)
 		{
 			tmport -= 0x05;
 			adrcntu = 0;
@@ -206,7 +212,7 @@
 			dev->in_int = 0;
 			return;
 		}
-		if ((i == 0x80) || (i == 0x8f)) 
+		if ((i == 0x80) || (i == 0x8f))
 		{
 			lun = 0;
 			tmport -= 0x07;
@@ -215,7 +221,7 @@
 				tmport += 0x0d;
 				lun = inb(tmport) & 0x07;
 			} else {
-				if (j == 0x41) 
+				if (j == 0x41)
 				{
 					tmport += 0x02;
 					adrcntu = 0;
@@ -231,7 +237,7 @@
 					dev->in_int = 0;
 					return;
 				}
-				else 
+				else
 				{
 					outb(0x46, tmport);
 					dev->id[target_id].dirctu = 0x00;
@@ -252,7 +258,7 @@
 			/*
 			 *	Remap wide identifiers
 			 */
-			if ((target_id & 0x10) != 0) 
+			if ((target_id & 0x10) != 0)
 			{
 				target_id = (target_id & 0x07) | 0x08;
 			} else {
@@ -277,8 +283,21 @@
 			j |= dev->id[target_id].dirctu;
 			outb(j, tmport++);
 			outb(0x80, tmport);
+
+			/* enable 32 bit fifo transfer */
+			tmport = workportu + 0x3a;
+			if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) ||
+			    (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a))
+			{
+			   outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport);
+			}
+			else
+			{
+			   outb((unsigned char)(inb(tmport) & 0xf3),tmport);
+			}
+
 			tmport = workportu + 0x1b;
-			j = inb(tmport) & 0x0e;
+			j = 0;
 			id = 1;
 			id = id << target_id;
 			/*
@@ -288,7 +307,11 @@
 				j |= 0x01;
 			}
 			outb(j, tmport);
-			
+			while ((inb(tmport) & 0x01) != j)
+			{
+			   outb(j,tmport);
+			}
+
 			if (dev->id[target_id].last_lenu == 0) {
 				tmport = workportu + 0x18;
 				outb(0x08, tmport);
@@ -296,7 +319,7 @@
 				return;
 			}
 			prd = dev->id[target_id].prd_posu;
-			while (adrcntu != 0) 
+			while (adrcntu != 0)
 			{
 				id = ((unsigned short int *) (prd))[2];
 				if (id == 0) {
@@ -340,19 +363,19 @@
 			dev->in_int = 0;
 			return;
 		}
-		
+
 		/*
 		 *	Current scsi request on this target
 		 */
-		 
+
 		workrequ = dev->id[target_id].curr_req;
-		
+
 		if (i == 0x42) {
 			errstus = 0x02;
 			workrequ->result = errstus;
 			goto go_42;
 		}
-		if (i == 0x16) 
+		if (i == 0x16)
 		{
 			errstus = 0;
 			tmport -= 0x08;
@@ -376,15 +399,17 @@
 			 */
 			if (dev->wide_idu != 0) {
 				tmport = workportu + 0x1b;
-				j = inb(tmport) & 0x0e;
-				j |= 0x01;
-				outb(j, tmport);
+				outb(0x01,tmport);
+				while ((inb(tmport) & 0x01) != 0x01)
+				{
+				   outb(0x01,tmport);
+				}
 			}
 			/*
 			 *	If there is stuff to send and nothing going then send it
 			 */
 			if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) &&
-			    (dev->in_snd == 0)) 
+			    (dev->in_snd == 0))
 			{
 				send_s870(h);
 			}
@@ -445,9 +470,9 @@
 		dev->in_int = 0;
 		return;
 	} else {
-		tmport = workportu + 0x17;
-		inb(tmport);
-		dev->working = 0;
+//		tmport = workportu + 0x17;
+//		inb(tmport);
+//		dev->working = 0;
 		dev->in_int = 0;
 		return;
 	}
@@ -480,7 +505,7 @@
 	/*
 	 *	Fake a timeout for missing targets
 	 */
-	 
+
 	if ((m & dev->active_idu) == 0) {
 		req_p->result = 0x00040000;
 		done(req_p);
@@ -556,7 +581,17 @@
 	if ((dev->last_cmd != 0xff) && ((dev->last_cmd & 0x40) != 0)) {
 		dev->last_cmd &= 0x0f;
 		workrequ = dev->id[dev->last_cmd].curr_req;
-		goto cmd_subp;
+		if (workrequ != NULL)	     /* check NULL pointer */
+		{
+		   goto cmd_subp;
+		}
+		dev->last_cmd = 0xff;
+		if (dev->quhdu == dev->quendu)
+		{
+		   dev->in_snd = 0;
+		   restore_flags(flags);
+		   return ;
+		}
 	}
 	dev->working++;
 	j = dev->quhdu;
@@ -597,6 +632,9 @@
 			workrequ->request_bufflen = 0x08;
 		}
 	}
+	if (dev->ata_cdbu[0] == 0x00) {
+		workrequ->request_bufflen = 0;
+	}
 	/*
 	 *	Why limit this ????
 	 */
@@ -606,11 +644,11 @@
 			dev->ata_cdbu[4] = 0x24;
 		}
 	}
-	
+
 	tmport = workportu + 0x1b;
-	j = inb(tmport) & 0x0e;
+	j = 0;
 	target_id = workrequ->target;
-	
+
 	/*
 	 *	Wide ?
 	 */
@@ -618,13 +656,17 @@
 	w = w << target_id;
 	if ((w & dev->wide_idu) != 0) {
 		j |= 0x01;
-	}	
+	}
 	outb(j, tmport);
-	
+	while ((inb(tmport) & 0x01) != j)
+	{
+	   outb(j,tmport);
+	}
+
 	/*
 	 *	Write the command
 	 */
-	 
+
 	tmport = workportu;
 	outb(workrequ->cmd_len, tmport++);
 	outb(0x2c, tmport++);
@@ -639,17 +681,17 @@
 	 *	Write the target
 	 */
 	outb(dev->id[target_id].devspu, tmport++);
-	
+
 	/*
 	 *	Figure out the transfer size
 	 */
-	if (workrequ->use_sg) 
+	if (workrequ->use_sg)
 	{
 		l = 0;
 		sgpnt = (struct scatterlist *) workrequ->request_buffer;
-		for (i = 0; i < workrequ->use_sg; i++) 
+		for (i = 0; i < workrequ->use_sg; i++)
 		{
-			if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) 
+			if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER)
 			{
 				panic("Foooooooood fight!");
 			}
@@ -700,13 +742,13 @@
 	tmpcip = dev->pciport;
 	prd = dev->id[target_id].prd_tableu;
 	dev->id[target_id].prd_posu = prd;
-	
+
 	/*
 	 *	Now write the request list. Either as scatter/gather or as
 	 *	a linear chain.
 	 */
-	 
-	if (workrequ->use_sg) 
+
+	if (workrequ->use_sg)
 	{
 		sgpnt = (struct scatterlist *) workrequ->request_buffer;
 		i = 0;
@@ -743,8 +785,21 @@
 	outb(0x06, tmpcip);
 	outb(0x00, tmpcip);
 	tmpcip = tmpcip - 2;
+
+	tmport = workportu + 0x3a;
+	if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) ||
+	    (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a))
+	{
+	   outb((unsigned char)((inb(tmport) & 0xf3) | 0x08),tmport);
+	}
+	else
+	{
+	   outb((unsigned char)(inb(tmport) & 0xf3),tmport);
+	}
+	tmport = workportu + 0x1c;
+
 	if ((dev->ata_cdbu[0] == WRITE_6) || (dev->ata_cdbu[0] == WRITE_10) ||
-	    (dev->ata_cdbu[0] == WRITE_12) || (dev->ata_cdbu[0] == MODE_SELECT)) 
+	    (dev->ata_cdbu[0] == WRITE_12) || (dev->ata_cdbu[0] == MODE_SELECT))
 	{
 		dev->id[target_id].dirctu = 0x20;
 		if (inb(tmport) == 0) {
@@ -758,7 +813,7 @@
 		restore_flags(flags);
 		return;
 	}
-	if (inb(tmport) == 0) 
+	if (inb(tmport) == 0)
 	{
 		tmport = workportu + 0x18;
 		outb(0x08, tmport);
@@ -804,20 +859,20 @@
 			goto FUN_D7;
 		}
 	}
-	*val |= 0x4000;		/* assert DB6           */
+	*val |= 0x4000; 	/* assert DB6		*/
 	outw(*val, tmport);
-	*val &= 0xdfff;		/* assert DB5           */
+	*val &= 0xdfff; 	/* assert DB5		*/
 	outw(*val, tmport);
 FUN_D5:
 	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns) */
-		if ((inw(tmport) & 0x2000) != 0) {	/* DB5 all release?       */
+		if ((inw(tmport) & 0x2000) != 0) {	/* DB5 all release?	  */
 			goto FUN_D5;
 		}
 	}
-	*val |= 0x8000;		/* no DB4-0, assert DB7    */
+	*val |= 0x8000; 	/* no DB4-0, assert DB7    */
 	*val &= 0xe0ff;
 	outw(*val, tmport);
-	*val &= 0xbfff;		/* release DB6             */
+	*val &= 0xbfff; 	/* release DB6		   */
 	outw(*val, tmport);
       FUN_D6:
 	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns)  */
@@ -893,9 +948,9 @@
 		outb(k, tmport++);
 		tmport = dev->ioport + 0x1b;
 		if (dev->chip_veru == 4) {
-			outb((unsigned char) ((inb(tmport) & 0x0e) | 0x01), tmport);
+			outb(0x01, tmport);
 		} else {
-			outb((unsigned char) (inb(tmport) & 0x0e), tmport);
+			outb(0x00, tmport);
 		}
 wait_rdyok:
 		tmport = dev->ioport + 0x18;
@@ -923,17 +978,17 @@
 
 	outb(0, 0x80);
 
-	val = 0x0080;		/* bsy  */
+	val = 0x0080;		/* bsy	*/
 	tmport = dev->ioport + 0x1c;
 	outw(val, tmport);
-	val |= 0x0040;		/* sel  */
+	val |= 0x0040;		/* sel	*/
 	outw(val, tmport);
-	val |= 0x0004;		/* msg  */
+	val |= 0x0004;		/* msg	*/
 	outw(val, tmport);
 	inb(0x80);		/* 2 deskew delay(45ns*2=90ns) */
 	val &= 0x007f;		/* no bsy  */
 	outw(val, tmport);
-	mydlyu(0xffff);		/* recommanded SCAM selection response time */
+	mydlyu(0xffff); 	/* recommanded SCAM selection response time */
 	mydlyu(0xffff);
 	val &= 0x00fb;		/* after 1ms no msg */
 	outw(val, tmport);
@@ -983,7 +1038,7 @@
 	val |= 0x3f00;
 	fun_scam(dev, &val);
 	outb(3, 0x80);
-	val &= 0x00ff;		/* isolation        */
+	val &= 0x00ff;		/* isolation	    */
 	val |= 0x2000;
 	fun_scam(dev, &val);
 	outb(4, 0x80);
@@ -1018,10 +1073,10 @@
 	printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
 	i = 15;
 	j = mbuf[0];
-	if ((j & 0x20) != 0) {	/* bit5=1:ID upto 7      */
+	if ((j & 0x20) != 0) {	/* bit5=1:ID upto 7	 */
 		i = 7;
 	}
-	if ((j & 0x06) == 0) {	/* IDvalid?             */
+	if ((j & 0x06) == 0) {	/* IDvalid?		*/
 		goto G2Q5;
 	}
 	k = mbuf[1];
@@ -1036,7 +1091,7 @@
 		goto small_id;
 	}
 G2Q5:				/* srch from max acceptable ID#  */
-	k = i;			/* max acceptable ID#            */
+	k = i;			/* max acceptable ID#		 */
 G2Q_LP:
 	m = 1;
 	m <<= k;
@@ -1047,12 +1102,12 @@
 		k--;
 		goto G2Q_LP;
 	}
-G2Q_QUIN:		/* k=binID#,       */
+G2Q_QUIN:		/* k=binID#,	   */
 	assignid_map |= m;
 	if (k < 8) {
 		quintet[0] = 0x38;	/* 1st dft ID<8    */
 	} else {
-		quintet[0] = 0x31;	/* 1st  ID>=8      */
+		quintet[0] = 0x31;	/* 1st	ID>=8	   */
 	}
 	k &= 0x07;
 	quintet[1] = g2q_tab[k];
@@ -1073,15 +1128,15 @@
 void is870(unsigned long host, unsigned int wkport)
 {
 	unsigned int tmport;
-	unsigned char i, j, k, rmb;
+	unsigned char i, j, k, rmb, n;
 	unsigned short int m;
 	static unsigned char mbuf[512];
-	static unsigned char satn[9] = 	{0, 0, 0, 0, 0, 0, 0, 6, 6};
+	static unsigned char satn[9] =	{0, 0, 0, 0, 0, 0, 0, 6, 6};
 	static unsigned char inqd[9] =	{0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
-	static unsigned char synn[6] =  {0x80, 1, 3, 1, 0x19, 0x0e};
+	static unsigned char synn[6] =	{0x80, 1, 3, 1, 0x19, 0x0e};
 	static unsigned char synu[6] =	{0x80, 1, 3, 1, 0x0c, 0x0e};
 	static unsigned char synw[6] =	{0x80, 1, 3, 1, 0x0c, 0x07};
-	static unsigned char wide[6] =  {0x80, 1, 2, 3, 1, 0};
+	static unsigned char wide[6] =	{0x80, 1, 2, 3, 1, 0};
 	struct atp_unit *dev = &atp_unit[host];
 
 	sync_idu = 0;
@@ -1101,10 +1156,13 @@
 			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_idu);
 			continue;
 		}
+		tmport = wkport + 0x1b;
 		if (dev->chip_veru == 4) {
-			tmport = wkport + 0x1b;
-			j = (inb(tmport) & 0x0e) | 0x01;
-			outb(j, tmport);
+		   outb(0x01, tmport);
+		}
+		else
+		{
+		   outb(0x00, tmport);
 		}
 		tmport = wkport + 1;
 		outb(0x08, tmport++);
@@ -1180,10 +1238,9 @@
 			continue;
 		}
 		while (inb(tmport) != 0x8e);
+		tmport = wkport + 0x1b;
 		if (dev->chip_veru == 4) {
-			tmport = wkport + 0x1b;
-			j = inb(tmport) & 0x0e;
-			outb(j, tmport);
+			outb(0x00, tmport);
 		}
 		tmport = wkport + 0x18;
 		outb(0x08, tmport);
@@ -1224,6 +1281,7 @@
 		printk(KERN_INFO "         ID: %2d  %s\n", i, &mbuf[8]);
 		dev->id[i].devtypeu = mbuf[0];
 		rmb = mbuf[1];
+		n = mbuf[7];
 		if (dev->chip_veru != 4) {
 			goto not_wide;
 		}
@@ -1234,8 +1292,7 @@
 			goto not_wide;
 		}
 		tmport = wkport + 0x1b;
-		j = (inb(tmport) & 0x0e) | 0x01;
-		outb(j, tmport);
+		outb(0x01, tmport);
 		tmport = wkport + 3;
 		outb(satn[0], tmport++);
 		outb(satn[1], tmport++);
@@ -1374,13 +1431,15 @@
 		m = m << i;
 		dev->wide_idu |= m;
 not_wide:
-		if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07)) {
+		if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) ||
+		    ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0)))
+		{
 			goto set_sync;
 		}
 		continue;
 set_sync:
 		tmport = wkport + 0x1b;
-		j = inb(tmport) & 0x0e;
+		j = 0;
 		if ((m & dev->wide_idu) != 0) {
 			j |= 0x01;
 		}
@@ -1420,17 +1479,13 @@
 		while ((inb(tmport) & 0x80) == 0) {
 			if ((inb(tmport) & 0x01) != 0) {
 				tmport -= 0x06;
-				if (rmb != 0) {
-					outb(synn[j++], tmport);
+				if ((m & dev->wide_idu) != 0) {
+					outb(synw[j++], tmport);
 				} else {
-					if ((m & dev->wide_idu) != 0) {
-						outb(synw[j++], tmport);
+					if ((m & dev->ultra_map) != 0) {
+						outb(synu[j++], tmport);
 					} else {
-						if ((m & dev->ultra_map) != 0) {
-							outb(synu[j++], tmport);
-						} else {
-							outb(synn[j++], tmport);
-						}
+						outb(synn[j++], tmport);
 					}
 				}
 				tmport += 0x06;
@@ -1579,9 +1634,9 @@
 	int tmpcnt = 0;
 	int count = 0;
 	int result;
-	
-	static unsigned short devid[7] = {
-		0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0
+
+	static unsigned short devid[8] = {
+		0x8002, 0x8010, 0x8020, 0x8030, 0x8040, 0x8050, 0x8060, 0
 	};
 
 	printk(KERN_INFO "aec671x_detect: \n");
@@ -1662,7 +1717,7 @@
 		base_io &= 0xfffffff8;
 
 		if (check_region(base_io,0x40) != 0)
-		{  
+		{
 			return 0;
 		}
 		printk(KERN_INFO "   ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d    IO:%x, IRQ:%d.\n"
@@ -1692,6 +1747,13 @@
 			printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
 			goto unregister;
 		}
+
+		if (chip_ver[h] > 0x07) 	  /* check if atp876 chip   */
+		{				  /* then enable terminator */
+		   tmport = base_io + 0x3e;
+		   outb(0x30, tmport);
+		}
+
 		tmport = base_io + 0x3a;
 		k = (inb(tmport) & 0xf3) | 0x10;
 		outb(k, tmport);
@@ -1730,7 +1792,7 @@
 		shpnt->n_io_port = 0x40;	/* Number of bytes of I/O space used */
 		shpnt->irq = irq;
 		restore_flags(flags);
-		request_region(base_io, 0x40, "atp870u");	/* Register the IO ports that we use */
+		request_region(base_io, 0x40, "atp870u");       /* Register the IO ports that we use */
 		count++;
 		index++;
 		continue;
@@ -1793,7 +1855,7 @@
 	}
 	panic("Reset bus host not found !");
 find_host:
-/*      SCpnt->result = 0x00080000;
+/*	SCpnt->result = 0x00080000;
 	SCpnt->scsi_done(SCpnt);
 	dev->working=0;
 	dev->quhdu=0;
@@ -1806,14 +1868,14 @@
 {
 	static char buffer[128];
 
-	strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.0+ac ");
+	strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.1+ac ");
 
 	return buffer;
 }
 
 int atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
 {
-	return -ENOSYS;		/* Currently this is a no-op */
+	return -ENOSYS; 	/* Currently this is a no-op */
 }
 
 #define BLS buffer + len + size
@@ -1851,7 +1913,7 @@
 	if (offset == 0) {
 		memset(buff, 0, sizeof(buff));
 	}
-	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.0+ac\n");
+	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.1+ac\n");
 	len += size;
 	pos = begin + len;
 	size = 0;
@@ -1899,7 +1961,7 @@
 int atp870u_release (struct Scsi_Host *pshost)
 {
 	int h;
-	for (h = 0; h <= admaxu; h++) 
+	for (h = 0; h <= admaxu; h++)
 	{
 		if (pshost == atp_host[h]) {
 			int k;
@@ -1912,7 +1974,7 @@
 		}
 	}
 	panic("atp870u: bad scsi host passed.\n");
-		
+
 }
 
 #ifdef MODULE
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/atp870u.h linux.18p8/drivers/scsi/atp870u.h
--- linux.vanilla/drivers/scsi/atp870u.h	Fri Apr 21 23:20:06 2000
+++ linux.18p8/drivers/scsi/atp870u.h	Fri Sep 15 15:13:38 2000
@@ -1,7 +1,7 @@
 #ifndef _ATP870U_H
 
 /* $Id: atp870u.h,v 1.0 1997/05/07 15:09:00 root Exp root $
-
+ *
  * Header file for the ACARD 870U/W driver for Linux
  *
  * $Log: atp870u.h,v $
@@ -13,6 +13,14 @@
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
 /* I/O Port */
 
 #define MAX_CDB 12
@@ -20,10 +28,10 @@
 
 int atp870u_detect(Scsi_Host_Template *);
 int atp870u_command(Scsi_Cmnd *);
-int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+int atp870u_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int atp870u_abort(Scsi_Cmnd *);
 int atp870u_reset(Scsi_Cmnd *, unsigned int);
-int atp870u_biosparam(Disk *, kdev_t, int *);
+int atp870u_biosparam(Disk *, kdev_t, int*);
 int atp870u_release(struct Scsi_Host *);
 void send_s870(unsigned char);
 
@@ -32,18 +40,20 @@
 #define ATP870U_CMDLUN 1
 
 #ifndef NULL
-#define NULL 0
+	#define NULL 0
 #endif
 
+extern struct proc_dir_entry proc_scsi_atp870u;
+
 extern const char *atp870u_info(struct Scsi_Host *);
 
 extern int atp870u_proc_info(char *, char **, off_t, int, int, int);
-extern struct proc_dir_entry proc_scsi_atp870u;
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
 #define ATP870U {						\
 	next: NULL,						\
 	module: NULL,						\
-	proc_dir:			&proc_scsi_atp870u,	\
+	proc_dir: &proc_scsi_atp870u,/* proc_dir_entry */	\
 	proc_info: atp870u_proc_info,				\
 	name: NULL,						\
 	detect: atp870u_detect, 				\
@@ -69,5 +79,26 @@
 	use_clustering: ENABLE_CLUSTERING,			\
 	use_new_eh_code: 0					\
 }
-
+#else
+#define ATP870U {  NULL, NULL,				\
+		     &proc_scsi_atp870u,/* proc_dir_entry */ \
+		     atp870u_proc_info, 		\
+		     NULL,				\
+		     atp870u_detect,			\
+		     NULL,				\
+		     atp870u_info,			\
+		     atp870u_command,			\
+		     atp870u_queuecommand,		\
+		     atp870u_abort,			\
+		     atp870u_reset,			\
+		     NULL,				\
+		     atp870u_biosparam, 		\
+		     qcnt,				\
+		     7, 				\
+		     ATP870U_SCATTER,			\
+		     ATP870U_CMDLUN,			\
+		     0, 				\
+		     0, 				\
+		     ENABLE_CLUSTERING}
+#endif
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/gdth.c linux.18p8/drivers/scsi/gdth.c
--- linux.vanilla/drivers/scsi/gdth.c	Fri Apr 21 12:46:28 2000
+++ linux.18p8/drivers/scsi/gdth.c	Mon Jul 24 10:32:20 2000
@@ -20,9 +20,46 @@
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.2.12                                *
+ * Tested with Linux 1.2.13, ..., 2.2.16, ..., 2.4.0-test4              *
  *                                                                      *
  * $Log: gdth.c,v $
+ * Revision 1.42  2000/07/20 09:04:50  achim
+ * Small changes for kernel 2.4
+ *
+ * Revision 1.41  2000/07/04 14:11:11  achim
+ * gdth_analyse_hdrive() added to rescan drives after online expansion
+ *
+ * Revision 1.40  2000/06/27 11:24:16  achim
+ * Changes Clustering, Screenservice
+ *
+ * Revision 1.39  2000/06/15 13:09:04  achim
+ * Changes for gdth_do_cmd()
+ *
+ * Revision 1.38  2000/06/15 12:08:43  achim
+ * Bugfix gdth_sync_event(), service SCREENSERVICE
+ * Data direction for command 0xc2 changed to DOU
+ *
+ * Revision 1.37  2000/05/25 13:50:10  achim
+ * New driver parameter virt_ctr added
+ *
+ * Revision 1.36  2000/05/04 08:50:46  achim
+ * Event buffer now in gdth_ha_str
+ *
+ * Revision 1.35  2000/03/03 10:44:08  achim
+ * New event_string only valid for the RP controller family
+ *
+ * Revision 1.34  2000/03/02 14:55:29  achim
+ * New mechanism for async. event handling implemented
+ *
+ * Revision 1.33  2000/02/21 15:37:37  achim
+ * Bugfix Alpha platform + DPMEM above 4GB
+ *
+ * Revision 1.32  2000/02/14 16:17:37  achim
+ * Bugfix sense_buffer[] + raw devices
+ *
+ * Revision 1.31  2000/02/10 10:29:00  achim
+ * Delete sense_buffer[0], if command OK
+ *
  * Revision 1.30  1999/11/02 13:42:39  achim
  * ARRAY_DRV_LIST2 implemented
  * Now 255 log. and 100 host drives supported
@@ -143,7 +180,7 @@
  * Initial revision
  *
  ************************************************************************/
-#ident "$Id: gdth.c,v 1.30 1999/11/02 13:42:39 achim Exp $" 
+#ident "$Id: gdth.c,v 1.42 2000/07/20 09:04:50 achim Exp $" 
 
 /* All GDT Disk Array Controllers are fully supported by this driver.
  * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
@@ -170,10 +207,12 @@
  * max_ids:x                    x - target ID count per channel (1..MAXID)
  * rescan:Y                     rescan all channels/IDs 
  * rescan:N                     use all devices found until now
+ * virt_ctr:Y                   map every channel to a virtual controller 
+ * virt_ctr:N                   use multi channel support 
  * hdr_channel:x                x - number of virtual bus for host drives
  *
- * The default value is: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
- *                        max_ids:127,rescan:N,hdr_channel:0".
+ * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
+ *                          max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0".
  * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
  * 
  * When loading the gdth driver as a module, the same options are available. 
@@ -183,7 +222,7 @@
  * '1' in place of 'Y' and '0' in place of 'N'.
  * 
  * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
- *                         max_ids=127 rescan=0 hdr_channel=0"
+ *                         max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0"
  * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
  */
 
@@ -204,6 +243,9 @@
 #include <linux/proc_fs.h>
 #include <linux/time.h>
 #include <linux/timer.h>
+#ifdef GDTH_RTC
+#include <linux/mc146818rtc.h>
+#endif
 #if LINUX_VERSION_CODE >= 0x020100
 #include <linux/reboot.h>
 #else
@@ -213,7 +255,9 @@
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#if LINUX_VERSION_CODE >= 0x02015F
+#if LINUX_VERSION_CODE >= 0x020322
+#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= 0x02015F
 #include <asm/spinlock.h>
 #endif
 
@@ -236,7 +280,7 @@
 static void gdth_interrupt(int irq,struct pt_regs *regs);
 #endif
 static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
-static int gdth_async_event(int hanum,int service);
+static int gdth_async_event(int hanum);
 static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
 
 static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
@@ -271,6 +315,7 @@
 static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
                              ulong32 p2,ulong32 p3);
 static int gdth_search_drives(int hanum);
+static int gdth_analyse_hdrive(int hanum, ushort hdrive);
 
 static void *gdth_mmap(ulong paddr, ulong size);
 static void gdth_munmap(void *addr);
@@ -289,8 +334,6 @@
 
 #ifdef DEBUG_GDTH
 static unchar   DebugState = DEBUG_GDTH;
-extern int sys_syslog(int,char*,int);
-#define LOGEN sys_syslog(7,NULL,0)
 
 #ifdef __SERIAL__
 #define MAX_SERBUF 160
@@ -359,9 +402,9 @@
 #define TRACE3(a)   {if (DebugState!=0) {ser_printk a;}}
 
 #else /* !__SERIAL__ */
-#define TRACE(a)    {if (DebugState==1) {LOGEN;printk a;}}
-#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {LOGEN;printk a;}}
-#define TRACE3(a)   {if (DebugState!=0) {LOGEN;printk a;}}
+#define TRACE(a)    {if (DebugState==1) {printk a;}}
+#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {printk a;}}
+#define TRACE3(a)   {if (DebugState!=0) {printk a;}}
 #endif
 
 #else /* !DEBUG */
@@ -441,7 +484,7 @@
 #define gdth_readl(addr)        (ulong32)readl((ulong)(addr))
 #define gdth_writeb(b,addr)     writeb((b),(ulong)(addr))
 #define gdth_writew(b,addr)     writew((b),(ulong)(addr))
-#define gdth_writel(b,addr)     writel((b),(ulong)(addr))
+#define gdth_writel(b,addr)     writel((ulong32)(b),(ulong)(addr))
 
 #else
 static void *gdth_mmap(ulong paddr, ulong size) 
@@ -457,7 +500,7 @@
 #define gdth_readl(addr)        (ulong32)readl((ulong)(addr))
 #define gdth_writeb(b,addr)     writeb((b),(ulong)(addr))
 #define gdth_writew(b,addr)     writew((b),(ulong)(addr))
-#define gdth_writel(b,addr)     writel((b),(ulong)(addr))
+#define gdth_writel(b,addr)     writel((ulong32)(b),(ulong)(addr))
 #endif
 
 
@@ -493,17 +536,21 @@
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU,
     DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
-    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
 };
 
 /* __initfunc, __initdata macros */
-#if LINUX_VERSION_CODE >= 0x020126
+#if LINUX_VERSION_CODE >= 0x020322
+#define GDTH_INITFUNC(type, func)       type __init func 
+#include <linux/init.h>
+#elif LINUX_VERSION_CODE >= 0x020126
+#define GDTH_INITFUNC(type, func)       __initfunc(type func)
 #include <linux/init.h>
 #else
-#define __initfunc(A) A
+#define GDTH_INITFUNC(type, func)       type func
 #define __initdata
 #define __init
 #endif
@@ -550,6 +597,8 @@
 static int max_ids = MAXID;
 /* rescan all IDs */
 static int rescan = 0;
+/* map channels to virtual controllers */
+static int virt_ctr = 0;
 
 #ifdef MODULE
 #if LINUX_VERSION_CODE >= 0x02011A
@@ -562,6 +611,7 @@
 MODULE_PARM(hdr_channel, "i");
 MODULE_PARM(max_ids, "i");
 MODULE_PARM(rescan, "i");
+MODULE_PARM(virt_ctr, "i");
 MODULE_AUTHOR("Achim Leubner");
 #endif
 #endif
@@ -569,10 +619,12 @@
 /* /proc support */
 #if LINUX_VERSION_CODE >= 0x010300
 #include <linux/stat.h> 
+#if LINUX_VERSION_CODE < 0x020322
 struct proc_dir_entry proc_scsi_gdth = {
     PROC_SCSI_GDTH, 4, "gdth",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
+#endif
 #include "gdth_proc.h"
 #include "gdth_proc.c"
 #endif
@@ -621,7 +673,7 @@
 
 /* controller search and initialization functions */
 
-__initfunc (static int gdth_search_eisa(ushort eisa_adr))
+GDTH_INITFUNC(static int, gdth_search_eisa(ushort eisa_adr))
 {
     ulong32 id;
     
@@ -639,7 +691,7 @@
 }
 
 
-__initfunc (static int gdth_search_isa(ulong32 bios_adr))
+GDTH_INITFUNC(static int, gdth_search_isa(ulong32 bios_adr))
 {
     void *addr;
     ulong32 id;
@@ -655,9 +707,9 @@
 }
 
 
-__initfunc (static int gdth_search_pci(gdth_pci_str *pcistr))
+GDTH_INITFUNC(static int, gdth_search_pci(gdth_pci_str *pcistr))
 {
-    ulong32 base0, base1, base2;
+    ulong base0, base1, base2;
     ushort device_id, cnt;
 #if LINUX_VERSION_CODE >= 0x2015C
     struct pci_dev *pdev;
@@ -674,7 +726,43 @@
         if (device_id > PCI_DEVICE_ID_VORTEX_GDT6555 &&
             device_id < PCI_DEVICE_ID_VORTEX_GDT6x17RP)
             continue;
-#if LINUX_VERSION_CODE >= 0x2015C
+#if LINUX_VERSION_CODE >= 0x20363
+        pdev = NULL;
+        while ((pdev = pci_find_device(PCI_VENDOR_ID_VORTEX,device_id,pdev)) 
+               != NULL) {
+            if (pci_enable_device(pdev))
+                continue;
+            if (cnt >= MAXHA)
+                return cnt;
+            /* GDT PCI controller found, resources are already in pdev */
+            pcistr[cnt].pdev = pdev;
+            pcistr[cnt].device_id = device_id;
+            pcistr[cnt].bus = pdev->bus->number;
+            pcistr[cnt].device_fn = pdev->devfn;
+            pcistr[cnt].irq = pdev->irq;
+            base0 = pci_resource_flags(pdev, 0);
+            base1 = pci_resource_flags(pdev, 1);
+            base2 = pci_resource_flags(pdev, 2);
+            if (device_id <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
+                device_id >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
+                if (!(base0 & IORESOURCE_MEM)) 
+                    continue;
+                pcistr[cnt].dpmem = pci_resource_start(pdev, 0);
+            } else {                                  /* GDT6110, GDT6120, .. */
+                if (!(base0 & IORESOURCE_MEM) ||
+                    !(base2 & IORESOURCE_MEM) ||
+                    !(base1 & IORESOURCE_IO)) 
+                    continue;
+                pcistr[cnt].dpmem = pci_resource_start(pdev, 2);
+                pcistr[cnt].io_mm = pci_resource_start(pdev, 0);
+                pcistr[cnt].io    = pci_resource_start(pdev, 1);
+            }
+            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
+                    pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
+                    pcistr[cnt].irq, pcistr[cnt].dpmem));
+            cnt++;
+        }       
+#elif LINUX_VERSION_CODE >= 0x2015C
         pdev = NULL;
         while ((pdev = pci_find_device(PCI_VENDOR_ID_VORTEX,device_id,pdev)) 
                != NULL) {
@@ -695,7 +783,7 @@
                     PCI_BASE_ADDRESS_SPACE_MEMORY)
                     continue;
                 pcistr[cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
-            } else {                                    /* GDT6110, GDT6120, .. */
+            } else {                                  /* GDT6110, GDT6120, .. */
                 if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
                     PCI_BASE_ADDRESS_SPACE_MEMORY ||
                     (base2 & PCI_BASE_ADDRESS_SPACE) !=
@@ -707,9 +795,9 @@
                 pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
                 pcistr[cnt].io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
             }
-            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n",
+            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
                     pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
-                    pcistr[cnt].irq, (int)pcistr[cnt].dpmem));
+                    pcistr[cnt].irq, pcistr[cnt].dpmem));
             cnt++;
         }       
 #else   
@@ -762,7 +850,7 @@
                 pcistr[cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
                 pcistr[cnt].io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
             }
-            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n",
+            TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
                     pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
                     pcistr[cnt].irq, pcistr[cnt].dpmem));
             cnt++;
@@ -773,7 +861,7 @@
 }
 
 
-__initfunc (static void gdth_sort_pci(gdth_pci_str *pcistr, int cnt))
+GDTH_INITFUNC(static void, gdth_sort_pci(gdth_pci_str *pcistr, int cnt))
 {    
     gdth_pci_str temp;
     int i, changed;
@@ -811,7 +899,7 @@
 }
 
 
-__initfunc (static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha))
+GDTH_INITFUNC(static int, gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha))
 {
     ulong32 retries,id;
     unchar prot_ver,eisacf,i,irq_found;
@@ -900,7 +988,7 @@
 }
 
        
-__initfunc (static int gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha))
+GDTH_INITFUNC(static int, gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha))
 {
     register gdt2_dpram_str *dp2_ptr;
     int i;
@@ -997,7 +1085,7 @@
 }
 
 
-__initfunc (static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha))
+GDTH_INITFUNC(static int, gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha))
 {
     register gdt6_dpram_str *dp6_ptr;
     register gdt6c_dpram_str *dp6c_ptr;
@@ -1165,7 +1253,18 @@
         }
 
         /* manipulate config. space to enable DPMEM, start RP controller */
-#if LINUX_VERSION_CODE >= 0x2015C
+#if LINUX_VERSION_CODE >= 0x20363
+        pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
+        command |= 6;
+        pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
+        if (pci_resource_start(pcistr->pdev, 8) == 1UL)
+            pci_resource_start(pcistr->pdev, 8) = 0UL;
+        i = 0xFEFF0001UL;
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i);
+        gdth_delay(1);
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
+                               pci_resource_start(pcistr->pdev, 8));
+#elif LINUX_VERSION_CODE >= 0x2015C
         pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
         command |= 6;
         pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
@@ -1193,13 +1292,13 @@
         pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
                                    PCI_ROM_ADDRESS, rom_addr);
 #endif
-	
+        
         /* check and reset interface area */
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
         gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
         if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
-            printk("GDT-PCI: Cannot access DPMEM at 0x%x (shadowed?)\n", 
-                   (int)pcistr->dpmem);
+            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
+                   pcistr->dpmem);
             found = FALSE;
             for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
                 gdth_munmap(ha->brd);
@@ -1298,7 +1397,7 @@
 
 /* controller protocol functions */
 
-__initfunc (static void gdth_enable_int(int hanum))
+GDTH_INITFUNC(static void, gdth_enable_int(int hanum))
 {
     gdth_ha_str *ha;
     ulong flags;
@@ -1609,6 +1708,12 @@
             cmd_ptr->u.raw.bus        = (unchar)p2;
             cmd_ptr->u.raw.target     = (unchar)p3;
             cmd_ptr->u.raw.lun        = (unchar)(p3 >> 8);
+        } else if (service == SCREENSERVICE) {
+            if (opcode == GDT_REALTIME) {
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = p2;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = p3;
+            }
         }
         ha->cmd_len          = sizeof(gdth_cmd_str);
         ha->cmd_offs_dpmem   = 0;
@@ -1631,20 +1736,21 @@
 
 /* search for devices */
 
-__initfunc (static int gdth_search_drives(int hanum))
+GDTH_INITFUNC(static int, gdth_search_drives(int hanum))
 {
     register gdth_ha_str *ha;
     ushort cdev_cnt, i;
-    int drv_cyls, drv_hds, drv_secs;
-    ulong32 bus_no;
-    ulong32 drv_cnt, drv_no, j;
+    ulong32 bus_no, drv_cnt, drv_no, j;
     gdth_getch_str *chn;
     gdth_drlist_str *drl;
     gdth_iochan_str *ioc;
     gdth_raw_iochan_str *iocr;
     gdth_arcdl_str *alst;
     gdth_alist_str *alst2;
-        
+#ifdef GDTH_RTC
+    unchar rtc[12];
+#endif     
+   
     TRACE(("gdth_search_drives() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
 
@@ -1655,7 +1761,28 @@
         return 0;
     }
     TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
-    
+
+#ifdef GDTH_RTC
+    /* read realtime clock info, send to controller */
+    /* 1. wait for the falling edge of update flag */
+    for (j = 0; j < 1000000; ++j)
+        if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+            break;
+    for (j = 0; j < 1000000; ++j)
+        if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+            break;
+    /* 2. read info */
+    do {
+        for (j = 0; j < 12; ++j) 
+            rtc[j] = CMOS_READ(j);
+    } while (rtc[0] != CMOS_READ(0));
+    TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
+            *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
+    /* 3. send to controller firmware */
+    gdth_internal_cmd(hanum,SCREENSERVICE,GDT_REALTIME, *(ulong32 *)&rtc[0],
+                      *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]);
+#endif   
+ 
     /* initialize cache service */
     if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
         printk("GDT: Initialization error cache service (code %d)\n",
@@ -1664,6 +1791,7 @@
     }
     TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
     cdev_cnt = (ushort)ha->info;
+    ha->fw_vers = ha->service;
 
     /* detect number of buses - try new IOCTL */
     iocr = (gdth_raw_iochan_str *)ha->pscratch;
@@ -1723,7 +1851,8 @@
     ha->more_proc = FALSE;
     if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
                           INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
-        ha->binfo = *(gdth_binfo_str *)ha->pscratch;
+        memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch,
+               sizeof(gdth_binfo_str));
         if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES,
                               INVALID_CHANNEL,sizeof(gdth_bfeat_str))) {
             TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n"));
@@ -1798,14 +1927,14 @@
                     }
                 }
             }
-	    alst = (gdth_arcdl_str *)ha->pscratch;
-	    alst->entries_avail = MAX_LDRIVES;
-	    alst->first_entry = 0;
-	    alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]);
+            alst = (gdth_arcdl_str *)ha->pscratch;
+            alst->entries_avail = MAX_LDRIVES;
+            alst->first_entry = 0;
+            alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]);
             if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
                                   ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, 
                                   INVALID_CHANNEL, sizeof(gdth_arcdl_str) +
-				  (alst->entries_avail-1) * sizeof(gdth_alist_str))) { 
+                                  (alst->entries_avail-1) * sizeof(gdth_alist_str))) { 
                 for (j = 0; j < alst->entries_init; ++j) {
                     ha->hdr[j].is_arraydrv = alst->list[j].is_arrayd;
                     ha->hdr[j].is_master = alst->list[j].is_master;
@@ -1813,9 +1942,9 @@
                     ha->hdr[j].is_hotfix = alst->list[j].is_hotfix;
                     ha->hdr[j].master_no = alst->list[j].cd_handle;
                 }
-	    } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
-					 ARRAY_DRV_LIST | LA_CTRL_PATTERN,
-					 0, 35 * sizeof(gdth_alist_str))) {
+            } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                         ARRAY_DRV_LIST | LA_CTRL_PATTERN,
+                                         0, 35 * sizeof(gdth_alist_str))) {
                 for (j = 0; j < 35; ++j) {
                     alst2 = &((gdth_alist_str *)ha->pscratch)[j];
                     ha->hdr[j].is_arraydrv = alst2->is_arrayd;
@@ -1881,60 +2010,70 @@
         }
     }
 
-    /* scanning for cache devices */
-    for (i=0; i<cdev_cnt && i<MAX_HDRIVES; ++i) {
-        TRACE(("gdth_search_drives() cachedev. %d\n",i));
-        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,i,0,0)) {
-            ha->hdr[i].present = TRUE;
-            ha->hdr[i].size = ha->info;
-
-            /* evaluate mapping (sectors per head, heads per cylinder) */
-            ha->hdr[i].size &= ~SECS32;
-            if (ha->info2 == 0) {
-                gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs);
-            } else {
-                drv_hds = ha->info2 & 0xff;
-                drv_secs = (ha->info2 >> 8) & 0xff;
-                drv_cyls = ha->hdr[i].size /drv_hds/drv_secs;
-            }
-            ha->hdr[i].heads = (unchar)drv_hds;
-            ha->hdr[i].secs  = (unchar)drv_secs;
-            /* round size */
-            ha->hdr[i].size  = drv_cyls * drv_hds * drv_secs;
-            TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n",
-                   i,ha->hdr[i].size,drv_hds,drv_secs));
-            
-            /* get informations about device */
-            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,i,
-                                  0,0)) {
-                TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
-                       i,ha->info));
-                ha->hdr[i].devtype = (ushort)ha->info;
-            }
+    /* scanning for host drives */
+    for (i = 0; i < cdev_cnt; ++i) 
+        gdth_analyse_hdrive(hanum,i);
+    
+    TRACE(("gdth_search_drives() OK\n"));
+    return 1;
+}
 
-            /* cluster info */
-            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,i,
-                                  0,0)) {
-                TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
-                       i,ha->info));
-                ha->hdr[i].cluster_type = (unchar)ha->info;
-            } else {
-                ha->hdr[i].cluster_type = 0;
-            }           
+static int gdth_analyse_hdrive(int hanum,ushort hdrive)
+{
+    register gdth_ha_str *ha;
+    int drv_cyls, drv_hds, drv_secs;
 
-            /* R/W attributes */
-            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,i,
-                                  0,0)) {
-                TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
-                       i,ha->info));
-                ha->hdr[i].rw_attribs = (unchar)ha->info;
-            } else {
-                ha->hdr[i].rw_attribs = 0;
-            }           
-        }
+    TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive));
+    if (hdrive >= MAX_HDRIVES)
+        return 0;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,hdrive,0,0)) 
+        return 0;
+    ha->hdr[hdrive].present = TRUE;
+    ha->hdr[hdrive].size = ha->info;
+
+    /* evaluate mapping (sectors per head, heads per cylinder) */
+    ha->hdr[hdrive].size &= ~SECS32;
+    if (ha->info2 == 0) {
+        gdth_eval_mapping(ha->hdr[hdrive].size,&drv_cyls,&drv_hds,&drv_secs);
+    } else {
+        drv_hds = ha->info2 & 0xff;
+        drv_secs = (ha->info2 >> 8) & 0xff;
+        drv_cyls = ha->hdr[hdrive].size /drv_hds/drv_secs;
+    }
+    ha->hdr[hdrive].heads = (unchar)drv_hds;
+    ha->hdr[hdrive].secs  = (unchar)drv_secs;
+    /* round size */
+    ha->hdr[hdrive].size  = drv_cyls * drv_hds * drv_secs;
+    TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n",
+            hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs));
+            
+    /* get informations about device */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) {
+        TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
+                hdrive,ha->info));
+        ha->hdr[hdrive].devtype = (ushort)ha->info;
     }
 
-    TRACE(("gdth_search_drives() OK\n"));
+    /* cluster info */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,hdrive,0,0)) {
+        TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
+                hdrive,ha->info));
+        ha->hdr[hdrive].cluster_type = (unchar)ha->info;
+    } else {
+        ha->hdr[hdrive].cluster_type = 0;
+    }           
+
+    /* R/W attributes */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) {
+        TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
+                hdrive,ha->info));
+        ha->hdr[hdrive].rw_attribs = (unchar)ha->info;
+    } else {
+        ha->hdr[hdrive].rw_attribs = 0;
+    }           
+
     return 1;
 }
 
@@ -1954,11 +2093,7 @@
     GDTH_LOCK_HA(ha, flags);
 
     scp->SCp.this_residual = (int)priority;
-#if LINUX_VERSION_CODE >= 0x020000
-    b = scp->channel;
-#else
-    b = NUMDATA(nscp->host)->busnum;
-#endif
+    b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
     t = scp->target;
 #if LINUX_VERSION_CODE >= 0x010300
     if (priority >= DEFAULT_PRI) {
@@ -2019,11 +2154,7 @@
     for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
         if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
             pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
-#if LINUX_VERSION_CODE >= 0x020000
-        b = nscp->channel;
-#else
-        b = NUMDATA(nscp->host)->busnum;
-#endif
+        b = virt_ctr ? NUMDATA(nscp->host)->busnum : nscp->channel;
         t = nscp->target;
         if (nscp->SCp.this_residual >= DEFAULT_PRI) {
             if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
@@ -2085,21 +2216,8 @@
             if (b == ha->virt_bus && nscp->cmnd[0] != INQUIRY &&
                 nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE &&
                 (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) {
-                if (!(ha->hdr[t].cluster_type & CLUSTER_MOUNTED)) {
-                    /* cluster drive NOT MOUNTED */
-                    if (!(ha->hdr[t].cluster_type & CLUSTER_RESERVED)) {
-                        /* cluster drive NOT RESERVED */
-                        nscp->SCp.Status = GDT_MOUNT;
-                    } else {
-                        /* cluster drive RESERVED (on the other node) */
-                        nscp->SCp.Status = GDT_CLUST_INFO;
-                    }
-                } else {
-                    if (!(ha->hdr[t].cluster_type & CLUSTER_RESERVED)) {
-                        /* cluster drive MOUNTED and not RESERVED */
-                        nscp->SCp.Status = GDT_CLUST_INFO;
-                    }
-                }
+                /* always GDT_CLUST_INFO! */
+                nscp->SCp.Status = GDT_CLUST_INFO;
             }
         }
         }
@@ -2177,6 +2295,7 @@
                 if ( (nscp->cmnd[4]&1) && !(ha->hdr[t].devtype&1) ) {
                     TRACE(("Prevent r. nonremov. drive->do nothing\n"));
                     nscp->result = DID_OK << 16;
+                    nscp->sense_buffer[0] = 0;
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
@@ -2353,6 +2472,7 @@
         break;
     }
     scp->result = DID_OK << 16;
+    scp->sense_buffer[0] = 0;
 
     if (!scp->SCp.have_data_in)
         scp->SCp.have_data_in++;
@@ -2545,7 +2665,7 @@
         cmdp->u.raw.sense_len  = 16;
         cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer);
         cmdp->u.raw.direction  = 
-            gdth_direction_tab[scp->cmnd[0]]==DOU ? DATA_OUT : DATA_IN;
+            gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
         memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
 
         if (scp->use_sg) {
@@ -2677,8 +2797,12 @@
 
     if (ebuffer[elastidx].event_source == source &&
         ebuffer[elastidx].event_idx == idx &&
-        !memcmp((char *)&ebuffer[elastidx].event_data.eu,
-            (char *)&evt->eu, evt->size)) {
+        ((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 &&
+            !memcmp((char *)&ebuffer[elastidx].event_data.eu,
+            (char *)&evt->eu, evt->size)) ||
+        (evt->size == 0 && ebuffer[elastidx].event_data.size == 0 &&
+            !strcmp((char *)&ebuffer[elastidx].event_data.event_string,
+            (char *)&evt->event_string)))) { 
         e = &ebuffer[elastidx];
         do_gettimeofday(&tv);
         e->last_stamp = tv.tv_sec;
@@ -2791,11 +2915,9 @@
     gdt6_dpram_str *dp6_ptr;
     gdt2_dpram_str *dp2_ptr;
     Scsi_Cmnd *scp;
-    int hanum, rval;
+    int hanum, rval, i;
     unchar IStatus;
-    ushort CmdStatus, Service = 0;
-    ulong32 InfoBytes, InfoBytes2 = 0;
-    gdth_evt_data dvr;
+    ushort Service;
     ulong flags = 0;
 
     TRACE(("gdth_interrupt() IRQ %d\n",irq));
@@ -2813,9 +2935,7 @@
 
     /* search controller */
     if ((hanum = gdth_get_status(&IStatus,irq)) == -1) {
-        /*
-        TRACE2(("gdth_interrupt(): Spurious interrupt received\n"));
-        */
+        /* spurious interrupt */
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
         return;
@@ -2829,34 +2949,28 @@
     if (ha->type == GDT_EISA) {
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = inw(ha->bmic + MAILBOXREG+8);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {            /* async. event ? */
-                Service = inw(ha->bmic + MAILBOXREG+10);
-                InfoBytes2 = inl(ha->bmic + MAILBOXREG+4);
-            }
+            ha->status = inw(ha->bmic + MAILBOXREG+8);
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else                                      /* no error */
-            CmdStatus = S_OK;
-        InfoBytes = inl(ha->bmic + MAILBOXREG+12);
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = inl(ha->bmic + MAILBOXREG+4);
+            ha->status = S_OK;
+        ha->info = inl(ha->bmic + MAILBOXREG+12);
+        ha->service = inw(ha->bmic + MAILBOXREG+10);
+        ha->info2 = inl(ha->bmic + MAILBOXREG+4);
+
         outb(0xff, ha->bmic + EDOORREG);            /* acknowledge interrupt */
         outb(0x00, ha->bmic + SEMA1REG);            /* reset status semaphore */
     } else if (ha->type == GDT_ISA) {
         dp2_ptr = (gdt2_dpram_str *)ha->brd;
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = gdth_readw(&dp2_ptr->u.ic.Status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {            /* async. event ? */
-                Service = gdth_readw(&dp2_ptr->u.ic.Service);
-                InfoBytes2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
-            }
+            ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else                                      /* no error */
-            CmdStatus = S_OK;
-        InfoBytes = gdth_readl(&dp2_ptr->u.ic.Info[0]);
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+            ha->status = S_OK;
+        ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
+        ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
+        ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+
         gdth_writeb(0xff, &dp2_ptr->io.irqdel);     /* acknowledge interrupt */
         gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);   /* reset command index */
         gdth_writeb(0, &dp2_ptr->io.Sema1);         /* reset status semaphore */
@@ -2864,52 +2978,56 @@
         dp6_ptr = (gdt6_dpram_str *)ha->brd;
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = gdth_readw(&dp6_ptr->u.ic.Status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {        /* async. event ? */
-                Service = gdth_readw(&dp6_ptr->u.ic.Service);
-                InfoBytes2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
-            }
+            ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else                                      /* no error */
-            CmdStatus = S_OK;
-        InfoBytes = gdth_readl(&dp6_ptr->u.ic.Info[0]);
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+            ha->status = S_OK;
+        ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
+        ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
+        ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+
         gdth_writeb(0xff, &dp6_ptr->io.irqdel);     /* acknowledge interrupt */
         gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);   /* reset command index */
         gdth_writeb(0, &dp6_ptr->io.Sema1);         /* reset status semaphore */
     } else if (ha->type == GDT_PCINEW) {
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = inw(PTR2USHORT(&ha->plx->status));
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {            /* async. event ? */
-                Service = inw(PTR2USHORT(&ha->plx->service));
-                InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1]));
-            }
+            ha->status = inw(PTR2USHORT(&ha->plx->status));
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else
-            CmdStatus = S_OK;
+            ha->status = S_OK;
+        ha->info = inl(PTR2USHORT(&ha->plx->info[0]));
+        ha->service = inw(PTR2USHORT(&ha->plx->service));
+        ha->info2 = inl(PTR2USHORT(&ha->plx->info[1]));
 
-        InfoBytes = inl(PTR2USHORT(&ha->plx->info[0]));
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = inl(PTR2USHORT(&ha->plx->info[1]));
         outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 
         outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 
     } else if (ha->type == GDT_PCIMPR) {
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
         if (IStatus & 0x80) {                       /* error flag */
             IStatus &= ~0x80;
-            CmdStatus = gdth_readw(&dp6m_ptr->i960r.status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,CmdStatus));
-            if (IStatus == ASYNCINDEX) {            /* async. event ? */
-                Service = gdth_readw(&dp6m_ptr->i960r.service);
-                InfoBytes2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
-            }
+            ha->status = gdth_readw(&dp6m_ptr->i960r.status);
+            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
         } else                                      /* no error */
-            CmdStatus = S_OK;
-        InfoBytes = gdth_readl(&dp6m_ptr->i960r.info[0]);
-        if (gdth_polling)                           /* init. -> more info */
-            InfoBytes2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+            ha->status = S_OK;
+        ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
+        ha->service = gdth_readw(&dp6m_ptr->i960r.service);
+        ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+
+        /* event string */
+        if (IStatus == ASYNCINDEX) {
+            if (ha->service != SCREENSERVICE &&
+                (ha->fw_vers & 0xff) >= 0x1a) {
+                ha->dvr.severity =   
+                    gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.severity);
+                for (i = 0; i < 256; ++i) {
+                    ha->dvr.event_string[i] = gdth_readb
+                        (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]);
+                    if (ha->dvr.event_string[i] == 0)
+                        break;
+                }
+            }
+        }
         gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
         gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
     } else {
@@ -2920,10 +3038,7 @@
     }
 
     TRACE(("gdth_interrupt() index %d stat %d info %d\n",
-           IStatus,CmdStatus,InfoBytes));
-    ha->status = CmdStatus;
-    ha->info   = InfoBytes;
-    ha->info2  = InfoBytes2;
+           IStatus,ha->status,ha->info));
 
     if (gdth_from_wait) {
         wait_hanum = hanum;
@@ -2932,7 +3047,7 @@
 
     if (IStatus == ASYNCINDEX) {
         TRACE2(("gdth_interrupt() async. event\n"));
-        gdth_async_event(hanum,Service);
+        gdth_async_event(hanum);
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
         gdth_next(hanum);
@@ -2941,9 +3056,9 @@
 
     if (IStatus == SPEZINDEX) {
         TRACE2(("Service unknown or not initialized !\n"));
-        dvr.size = sizeof(dvr.eu.driver);
-        dvr.eu.driver.ionode = hanum;
-        gdth_store_event(ha, ES_DRIVER, 4, &dvr);
+        ha->dvr.size = sizeof(ha->dvr.eu.driver);
+        ha->dvr.eu.driver.ionode = hanum;
+        gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
         return;
@@ -2953,10 +3068,10 @@
     ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND;
     if (scp == UNUSED_CMND) {
         TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
-        dvr.size = sizeof(dvr.eu.driver);
-        dvr.eu.driver.ionode = hanum;
-        dvr.eu.driver.index = IStatus;
-        gdth_store_event(ha, ES_DRIVER, 1, &dvr);
+        ha->dvr.size = sizeof(ha->dvr.eu.driver);
+        ha->dvr.eu.driver.ionode = hanum;
+        ha->dvr.eu.driver.index = IStatus;
+        gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
         return;
@@ -2987,9 +3102,7 @@
     register gdth_ha_str *ha;
     gdth_msg_str *msg;
     gdth_cmd_str *cmdp;
-    char c='\r';
-    ushort i;
-    gdth_evt_data dvr;
+    unchar b;
 
     ha   = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
@@ -3017,11 +3130,11 @@
             cmdp->OpCode        = GDT_READ;
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
-            cmdp->u.screen.msg_handle= msg->msg_handle;
-            cmdp->u.screen.msg_addr  = virt_to_bus(msg);
+            cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
+            cmdp->u.screen.su.msg.msg_addr  = virt_to_bus(msg);
             ha->scratch_busy = TRUE;
             ha->cmd_offs_dpmem = 0;
-            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
                 + sizeof(ulong32);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
@@ -3030,22 +3143,19 @@
         }
 
         if (msg->msg_answer && msg->msg_alen) {
-            for (i=0; i<msg->msg_alen && i<MSGLEN; ++i) {
-                /* getchar() ?? */           
-                /* .. */
-                if (c == '\r')
-                    break;
-                msg->msg_text[i] = c; 
-            }
-            msg->msg_alen -= i;
-            if (c!='\r' && msg->msg_alen!=0) {
-                msg->msg_answer = 1;
-                msg->msg_ext    = 1;
+            /* default answers (getchar() not possible) */
+            if (msg->msg_alen == 1) {
+                msg->msg_alen = 0;
+                msg->msg_len = 1;
+                msg->msg_text[0] = 0;
             } else {
-                msg->msg_ext    = 0;
-                msg->msg_answer = 0;
+                msg->msg_alen -= 2;
+                msg->msg_len = 2;
+                msg->msg_text[0] = 1;
+                msg->msg_text[1] = 0;
             }
-            msg->msg_len = i;
+            msg->msg_ext    = 0;
+            msg->msg_answer = 0;
             while (gdth_test_busy(hanum))
                 gdth_delay(0);
             cmdp->Service       = SCREENSERVICE;
@@ -3055,11 +3165,11 @@
             cmdp->OpCode        = GDT_WRITE;
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
-            cmdp->u.screen.msg_handle= msg->msg_handle;
-            cmdp->u.screen.msg_addr  = virt_to_bus(msg);
+            cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
+            cmdp->u.screen.su.msg.msg_addr  = virt_to_bus(msg);
             ha->scratch_busy = TRUE;
             ha->cmd_offs_dpmem = 0;
-            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
                 + sizeof(ulong32);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
@@ -3069,8 +3179,9 @@
         printk("\n");
 
     } else {
-        if (scp->SCp.Status == -1 && scp->channel != ha->virt_bus) {
-            ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[scp->target]--;
+        b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+        if (scp->SCp.Status == -1 && b != ha->virt_bus) {
+            ha->raw[BUS_L2P(ha,b)].io_cnt[scp->target]--;
         }
         /* cache or raw service */
         if (ha->status == S_OK) {
@@ -3107,6 +3218,7 @@
                     scp->sense_buffer[0] = 0x70;
                     scp->sense_buffer[2] = UNIT_ATTENTION;
                     scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                    scp->SCp.Message = (int)(ha->info<<16|S_BSY);
                 } else {
                     scp->SCp.Status = -1;
                     /* retry */
@@ -3121,6 +3233,7 @@
                     ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
                 }           
                 scp->result = DID_OK << 16;
+                scp->sense_buffer[0] = 0;
             }
         } else if (ha->status == S_BSY) {
             TRACE2(("Controller busy -> retry !\n"));
@@ -3131,9 +3244,6 @@
             return 2;
         } else {
             scp->SCp.Message = (int)((ha->info<<16)|ha->status);
-            memset((char*)scp->sense_buffer,0,16);
-            scp->sense_buffer[0] = 0x70;
-            scp->sense_buffer[2] = NOT_READY;
 
             if (scp->SCp.Status != -1) {
                 TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n",
@@ -3145,34 +3255,44 @@
                     scp->SCp.this_residual = HIGH_PRI;
                     return 2;
                 }
+                memset((char*)scp->sense_buffer,0,16);
+                scp->sense_buffer[0] = 0x70;
+                scp->sense_buffer[2] = NOT_READY;
                 scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
             } else if (scp->cmnd[0] == RESERVE ||
                        scp->cmnd[0] == RELEASE) {
+                memset((char*)scp->sense_buffer,0,16);
+                scp->sense_buffer[0] = 0x70;
+                scp->sense_buffer[2] = NOT_READY;
                 scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
             } else if (service == CACHESERVICE) {
-		if (ha->status == S_CACHE_UNKNOWN &&
-		    (ha->hdr[scp->target].cluster_type & 
-		     CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) {
-		    /* bus reset -> force GDT_CLUST_INFO */
-		    ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
-		}
+                if (ha->status == S_CACHE_UNKNOWN &&
+                    (ha->hdr[scp->target].cluster_type & 
+                     CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) {
+                    /* bus reset -> force GDT_CLUST_INFO */
+                    ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
+                }
+                memset((char*)scp->sense_buffer,0,16);
+                scp->sense_buffer[0] = 0x70;
+                scp->sense_buffer[2] = NOT_READY;
                 scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
 #if LINUX_VERSION_CODE >= 0x010300
                 if (scp->done != gdth_scsi_done)
 #endif  
                 {
-                    dvr.size = sizeof(dvr.eu.sync);
-                    dvr.eu.sync.ionode  = hanum;
-                    dvr.eu.sync.service = service;
-                    dvr.eu.sync.status  = ha->status;
-                    dvr.eu.sync.info    = ha->info;
-                    dvr.eu.sync.hostdrive = scp->target;
+                    ha->dvr.size = sizeof(ha->dvr.eu.sync);
+                    ha->dvr.eu.sync.ionode  = hanum;
+                    ha->dvr.eu.sync.service = service;
+                    ha->dvr.eu.sync.status  = ha->status;
+                    ha->dvr.eu.sync.info    = ha->info;
+                    ha->dvr.eu.sync.hostdrive = scp->target;
                     if (ha->status >= 0x8000)
-                        gdth_store_event(ha, ES_SYNC, 0, &dvr);
+                        gdth_store_event(ha, ES_SYNC, 0, &ha->dvr);
                     else
-                        gdth_store_event(ha, ES_SYNC, service, &dvr);
+                        gdth_store_event(ha, ES_SYNC, service, &ha->dvr);
                 }
             } else {
+                /* sense buffer filled from controller firmware (DMA) */
                 if (ha->status!=S_RAW_SCSI || ha->info>=0x100) {
                     scp->result = DID_BAD_TARGET << 16;
                 } else {
@@ -3336,12 +3456,17 @@
         "GDT HA %u, Uncorrectable DRAM error detected with ECC",
 /*72*/  "\011\000\002\012\001\013\001\014\001"
         "GDT HA %u, SCSI bus %u, ID %u, LUN %u: reassigning block",
+/*73*/  "\005\000\002\006\002"
+        "GDT HA %u, Host drive %u resetted locally",
+/*74*/  "\005\000\002\006\002"
+        "GDT HA %u, Host drive %u resetted remotely",
+/*75*/  "\003\000\002"
+        "GDT HA %u, async. status 75 unknown",
 };
 
 
-static int gdth_async_event(int hanum,int service)
+static int gdth_async_event(int hanum)
 {
-    gdth_evt_data dvr;
     gdth_ha_str *ha;
     gdth_msg_str *msg;
     gdth_cmd_str *cmdp;
@@ -3351,9 +3476,9 @@
     cmdp= ha->pccb;
     msg = (gdth_msg_str *)ha->pscratch;
     TRACE2(("gdth_async_event() ha %d serv %d\n",
-            hanum,service));
+            hanum,ha->service));
 
-    if (service == SCREENSERVICE) {
+    if (ha->service == SCREENSERVICE) {
         if (ha->status == MSG_REQUEST) {
             while (gdth_test_busy(hanum))
                 gdth_delay(0);
@@ -3364,11 +3489,11 @@
             cmdp->OpCode        = GDT_READ;
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
-            cmdp->u.screen.msg_handle= MSG_INV_HANDLE;
-            cmdp->u.screen.msg_addr  = virt_to_bus(msg);
+            cmdp->u.screen.su.msg.msg_handle= MSG_INV_HANDLE;
+            cmdp->u.screen.su.msg.msg_addr  = virt_to_bus(msg);
             ha->scratch_busy = TRUE;
             ha->cmd_offs_dpmem = 0;
-            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.msg_addr) 
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
                 + sizeof(ulong32);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
@@ -3383,14 +3508,29 @@
         }
 
     } else {
-        dvr.size = sizeof(dvr.eu.async);
-        dvr.eu.async.ionode   = hanum;
-        dvr.eu.async.service = service;
-        dvr.eu.async.status  = ha->status;
-        dvr.eu.async.info    = ha->info;
-        *(ulong32 *)dvr.eu.async.scsi_coord  = ha->info2;
-        gdth_store_event(ha, ES_ASYNC, service, &dvr);
-        gdth_log_event( &dvr, NULL );
+        if (ha->type == GDT_PCIMPR && 
+            (ha->fw_vers & 0xff) >= 0x1a) {
+            ha->dvr.size = 0;
+            ha->dvr.eu.async.ionode = hanum;
+            ha->dvr.eu.async.status  = ha->status;
+            /* severity and event_string already set! */
+        } else {        
+            ha->dvr.size = sizeof(ha->dvr.eu.async);
+            ha->dvr.eu.async.ionode   = hanum;
+            ha->dvr.eu.async.service = ha->service;
+            ha->dvr.eu.async.status  = ha->status;
+            ha->dvr.eu.async.info    = ha->info;
+            *(ulong32 *)ha->dvr.eu.async.scsi_coord  = ha->info2;
+        }
+        gdth_store_event( ha, ES_ASYNC, ha->service, &ha->dvr );
+        gdth_log_event( &ha->dvr, NULL );
+    
+        /* new host drive from expand? */
+        if (ha->service == CACHESERVICE && ha->status == 56) {
+            TRACE2(("gdth_async_event(): new host drive %d created\n",
+                    (ushort)ha->info));
+            gdth_analyse_hdrive(hanum, (ushort)ha->info);
+        }   
     }
     return 1;
 }
@@ -3402,7 +3542,14 @@
     int i,j;
 
     TRACE2(("gdth_log_event()\n"));
-    if (dvr->eu.async.service == CACHESERVICE && 
+    if (dvr->size == 0) {
+        if (buffer == NULL) {
+            printk("Adapter %d: %s\n",dvr->eu.async.ionode,dvr->event_string); 
+        } else {
+            sprintf(buffer,"Adapter %d: %s\n",
+                dvr->eu.async.ionode,dvr->event_string); 
+        }
+    } else if (dvr->eu.async.service == CACHESERVICE && 
         INDEX_OK(dvr->eu.async.status, async_cache_tab)) {
         TRACE2(("GDT: Async. event cache service, event no.: %d\n",
                 dvr->eu.async.status));
@@ -3474,7 +3621,7 @@
 #endif
 
 
-__initfunc (int gdth_detect(Scsi_Host_Template *shtp))
+GDTH_INITFUNC(int, gdth_detect(Scsi_Host_Template *shtp))
 {
     struct Scsi_Host *shp;
     gdth_ha_str *ha;
@@ -3522,6 +3669,9 @@
                 scsi_unregister(shp);
                 continue;
             }
+#ifdef __ia64__
+            break;
+#else
             /* controller found and initialized */
             printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
                    isa_bios,ha->irq,ha->drq);
@@ -3559,7 +3709,12 @@
             NUMDATA(shp)->busnum= 0;
 
             ha->pccb = CMDDATA(shp);
+#if LINUX_VERSION_CODE >= 0x020322
+            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
+                                                     GDTH_SCRATCH_ORD);
+#else
             ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+#endif
             ha->scratch_busy = FALSE;
             ha->req_first = NULL;
             ha->tid_cnt = MAX_HDRIVES;
@@ -3574,7 +3729,11 @@
                 --gdth_ctr_count;
                 --gdth_ctr_vcount;
                 if (ha->pscratch != NULL)
+#if LINUX_VERSION_CODE >= 0x020322
+                    free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
+#else
                     scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#endif
 #if LINUX_VERSION_CODE >= 0x010346 
                 free_irq(ha->irq,NULL);
 #else
@@ -3590,21 +3749,26 @@
 #if LINUX_VERSION_CODE >= 0x020000
             shp->max_id      = ha->tid_cnt;
             shp->max_lun     = MAXLUN;
-            shp->max_channel = ha->bus_cnt;
-#else
-            /* register addit. SCSI channels as virtual controllers */
-            for (b=1; b<ha->bus_cnt+1; ++b) {
-                shp = scsi_register(shtp,sizeof(gdth_num_str));
-                shp->unchecked_isa_dma = 1;
-                shp->irq = ha->irq;
-                shp->dma_channel = ha->drq;
-                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                NUMDATA(shp)->hanum = (ushort)hanum;
-                NUMDATA(shp)->busnum = b;
-            }
+            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+            if (virt_ctr)  
 #endif
+            {
+                virt_ctr = 1;
+                /* register addit. SCSI channels as virtual controllers */
+                for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                    shp = scsi_register(shtp,sizeof(gdth_num_str));
+                    shp->unchecked_isa_dma = 1;
+                    shp->irq = ha->irq;
+                    shp->dma_channel = ha->drq;
+                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                    NUMDATA(shp)->hanum = (ushort)hanum;
+                    NUMDATA(shp)->busnum = b;
+                }
+            }  
+
             GDTH_INIT_LOCK_HA(ha);
             gdth_enable_int(hanum);
+#endif /* !__ia64__ */
         }
     }
 
@@ -3646,7 +3810,12 @@
                     NUMDATA(shp)->hanum));
 
             ha->pccb = CMDDATA(shp);
+#if LINUX_VERSION_CODE >= 0x020322
+            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
+                                                     GDTH_SCRATCH_ORD);
+#else
             ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+#endif
             ha->scratch_busy = FALSE;
             ha->req_first = NULL;
             ha->tid_cnt = MAX_HDRIVES;
@@ -3661,7 +3830,11 @@
                 --gdth_ctr_count;
                 --gdth_ctr_vcount;
                 if (ha->pscratch != NULL)
+#if LINUX_VERSION_CODE >= 0x020322
+                    free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
+#else
                     scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#endif
 #if LINUX_VERSION_CODE >= 0x010346 
                 free_irq(ha->irq,NULL);
 #else
@@ -3677,22 +3850,23 @@
 #if LINUX_VERSION_CODE >= 0x020000
             shp->max_id      = ha->tid_cnt;
             shp->max_lun     = MAXLUN;
-            shp->max_channel = ha->bus_cnt;
-#else
-            /* register addit. SCSI channels as virtual controllers */
-            for (b=1; b<ha->bus_cnt+1; ++b) {
-                shp = scsi_register(shtp,sizeof(gdth_num_str));
-                shp->unchecked_isa_dma = 0;
-                shp->irq = ha->irq;
-                shp->dma_channel = 0xff;
-                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                NUMDATA(shp)->hanum = (ushort)hanum;
-                NUMDATA(shp)->busnum = b;
-                TRACE2(("EISA detect Bus %d: shp %x hanum %d\n",
-                        NUMDATA(shp)->busnum,(ulong32)shp,
-                        NUMDATA(shp)->hanum));
-            }
+            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+            if (virt_ctr)  
 #endif
+            {
+                virt_ctr = 1;
+                /* register addit. SCSI channels as virtual controllers */
+                for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                    shp = scsi_register(shtp,sizeof(gdth_num_str));
+                    shp->unchecked_isa_dma = 0;
+                    shp->irq = ha->irq;
+                    shp->dma_channel = 0xff;
+                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                    NUMDATA(shp)->hanum = (ushort)hanum;
+                    NUMDATA(shp)->busnum = b;
+                }
+            }  
+
             GDTH_INIT_LOCK_HA(ha);
             gdth_enable_int(hanum);
         }
@@ -3745,7 +3919,12 @@
             NUMDATA(shp)->busnum= 0;
 
             ha->pccb = CMDDATA(shp);
+#if LINUX_VERSION_CODE >= 0x020322
+            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
+                                                     GDTH_SCRATCH_ORD);
+#else
             ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+#endif
             ha->scratch_busy = FALSE;
             ha->req_first = NULL;
             ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
@@ -3760,7 +3939,11 @@
                 --gdth_ctr_count;
                 --gdth_ctr_vcount;
                 if (ha->pscratch != NULL)
+#if LINUX_VERSION_CODE >= 0x020322
+                    free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
+#else
                     scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#endif
 #if LINUX_VERSION_CODE >= 0x010346 
                 free_irq(ha->irq,NULL);
 #else
@@ -3776,19 +3959,23 @@
 #if LINUX_VERSION_CODE >= 0x020000
             shp->max_id      = ha->tid_cnt;
             shp->max_lun     = MAXLUN;
-            shp->max_channel = ha->bus_cnt;
-#else
-            /* register addit. SCSI channels as virtual controllers */
-            for (b=1; b<ha->bus_cnt+1; ++b) {
-                shp = scsi_register(shtp,sizeof(gdth_num_str));
-                shp->unchecked_isa_dma = 0;
-                shp->irq = ha->irq;
-                shp->dma_channel = 0xff;
-                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                NUMDATA(shp)->hanum = (ushort)hanum;
-                NUMDATA(shp)->busnum = b;
-            }
+            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+            if (virt_ctr)  
 #endif
+            {
+                virt_ctr = 1;
+                /* register addit. SCSI channels as virtual controllers */
+                for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                    shp = scsi_register(shtp,sizeof(gdth_num_str));
+                    shp->unchecked_isa_dma = 0;
+                    shp->irq = ha->irq;
+                    shp->dma_channel = 0xff;
+                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                    NUMDATA(shp)->hanum = (ushort)hanum;
+                    NUMDATA(shp)->busnum = b;
+                }
+            }  
+
             GDTH_INIT_LOCK_HA(ha);
             gdth_enable_int(hanum);
         }
@@ -3833,10 +4020,16 @@
             free_irq(shp->irq);
 #endif
         }
+#ifndef __ia64__
         if (shp->dma_channel != 0xff) {
             free_dma(shp->dma_channel);
         }
+#endif
+#if LINUX_VERSION_CODE >= 0x020322
+        free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
+#else
         scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#endif
         gdth_ctr_released++;
         TRACE2(("gdth_release(): HA %d of %d\n", 
                 gdth_ctr_released, gdth_ctr_count));
@@ -3937,26 +4130,26 @@
     gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *cmnd;
+    unchar b;
 
     TRACE2(("gdth_eh_bus_reset()\n"));
     hanum = NUMDATA(scp->host)->hanum;
+    b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
     ha    = HADATA(gdth_ctr_tab[hanum]);
 
     /* clear command tab */
     GDTH_LOCK_HA(ha, flags);
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         cmnd = ha->cmd_tab[i].cmnd;
-        if (!SPECIAL_SCP(cmnd) && cmnd->channel == scp->channel)
+        if (!SPECIAL_SCP(cmnd) && cmnd->channel == b)
             ha->cmd_tab[i].cmnd = UNUSED_CMND;
     }
     GDTH_UNLOCK_HA(ha, flags);
 
-    if (scp->channel == ha->virt_bus) {
+    if (b == ha->virt_bus) {
         /* host drives */
         for (i = 0; i < MAX_HDRIVES; ++i) {
-            if (ha->hdr[i].present && 
-                (ha->hdr[i].cluster_type & CLUSTER_RESERVED) 
-                == CLUSTER_RESERVED) { 
+            if (ha->hdr[i].present) {
                 GDTH_LOCK_HA(ha, flags);
                 gdth_polling = TRUE;
                 while (gdth_test_busy(hanum))
@@ -3972,12 +4165,12 @@
         /* raw devices */
         GDTH_LOCK_HA(ha, flags);
         for (i = 0; i < MAXID; ++i)
-            ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0;
+            ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0;
         gdth_polling = TRUE;
         while (gdth_test_busy(hanum))
             gdth_delay(0);
         gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
-                          BUS_L2P(ha,scp->channel), 0, 0);
+                          BUS_L2P(ha,b), 0, 0);
         gdth_polling = FALSE;
         GDTH_UNLOCK_HA(ha, flags);
     }
@@ -3997,17 +4190,17 @@
 int gdth_bios_param(Disk *disk,int dev,int *ip)
 #endif
 {
-    unchar t;
+    unchar b, t;
     int hanum;
     gdth_ha_str *ha;
 
     hanum = NUMDATA(disk->device->host)->hanum;
+    b = virt_ctr ? NUMDATA(disk->device->host)->busnum : disk->device->channel;
     t = disk->device->id;
-    TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", 
-            hanum, disk->device->channel, t));
+    TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t)); 
     ha = HADATA(gdth_ctr_tab[hanum]);
 
-    if (disk->device->channel != ha->virt_bus || ha->hdr[t].heads == 0) {
+    if (b != ha->virt_bus || ha->hdr[t].heads == 0) {
         /* raw device or host drive without mapping information */
         TRACE2(("Evaluate mapping\n"));
         gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]);
@@ -4075,19 +4268,32 @@
 {
     int             i;
     gdth_ha_str     *ha;
+    gdth_cmd_str    gdtcmd;
+#if LINUX_VERSION_CODE >= 0x020322
+    Scsi_Cmnd       *scp;
+    Scsi_Device     *sdev;
+#else
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
-    gdth_cmd_str    gdtcmd;
-    char            cmnd[12];   
+#endif
+    char            cmnd[MAX_COMMAND_SIZE];   
+    memset(cmnd, 0xff, 12);
 
     TRACE2(("gdth_flush() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
+
+#if LINUX_VERSION_CODE >= 0x020322
+    sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+    scp  = scsi_allocate_device(sdev, 1, FALSE);
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#else
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    memset(cmnd, 0xff, 12);
     sdev.host = scp.host = gdth_ctr_tab[hanum];
     sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
+#endif
 
     for (i = 0; i < MAX_HDRIVES; ++i) {
         if (ha->hdr[i].present) {
@@ -4098,9 +4304,17 @@
             gdtcmd.u.cache.BlockNo = 1;
             gdtcmd.u.cache.sg_canz = 0;
             TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
+#if LINUX_VERSION_CODE >= 0x020322
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+#else
             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+#endif
         }
     }
+#if LINUX_VERSION_CODE >= 0x020322
+    scsi_release_command(scp);
+    scsi_free_host_dev(sdev);
+#endif
 }
 
 /* shutdown routine */
@@ -4112,10 +4326,15 @@
 {
     int             hanum;
 #ifndef __alpha__
+    gdth_cmd_str    gdtcmd;
+#if LINUX_VERSION_CODE >= 0x020322
+    Scsi_Cmnd       *scp;
+    Scsi_Device     *sdev;
+#else
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
-    gdth_cmd_str    gdtcmd;
-    char            cmnd[12];
+#endif
+    char            cmnd[MAX_COMMAND_SIZE];   
 #endif
 
 #if LINUX_VERSION_CODE >= 0x020100
@@ -4136,19 +4355,32 @@
 
 #ifndef __alpha__
         /* controller reset */
+        memset(cmnd, 0xff, 12);
+#if LINUX_VERSION_CODE >= 0x020322
+        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+        scp  = scsi_allocate_device(sdev, 1, FALSE);
+        scp->cmd_len = 12;
+        scp->use_sg = 0;
+#else
         memset(&sdev,0,sizeof(Scsi_Device));
         memset(&scp, 0,sizeof(Scsi_Cmnd));
-        memset(cmnd, 0xff, 12);
         sdev.host = scp.host = gdth_ctr_tab[hanum];
         sdev.id = scp.target = sdev.host->this_id;
         scp.device = &sdev;
+#endif
 
         gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_RESET;
         TRACE2(("gdth_halt(): reset controller %d\n", hanum));
+#if LINUX_VERSION_CODE >= 0x020322
+        gdth_do_cmd(scp, &gdtcmd, cmnd, 10);
+        scsi_release_command(scp);
+        scsi_free_host_dev(sdev);
+#else
         gdth_do_cmd(&scp, &gdtcmd, cmnd, 10);
 #endif
+#endif
     }
     printk("Done.\n");
 
@@ -4156,7 +4388,9 @@
     del_timer(&gdth_timer);
 #endif
 #if LINUX_VERSION_CODE >= 0x020100
+#if LINUX_VERSION_CODE < 0x020322
     unregister_reboot_notifier(&gdth_notifier);
+#endif
     return NOTIFY_OK;
 #endif
 }
@@ -4164,7 +4398,7 @@
 
 
 /* called from init/main.c */
-__initfunc (void gdth_setup(char *str,int *ints))
+GDTH_INITFUNC(void, gdth_setup(char *str,int *ints))
 {
     int i, argc;
     char *cur_str, *argv;
@@ -4207,6 +4441,8 @@
             max_ids = val;
         else if (!strncmp(argv, "rescan:", 7))
             rescan = val;
+        else if (!strncmp(argv, "virt_ctr:", 9))
+            virt_ctr = val;
         else if (!strncmp(argv, "reserve_list:", 13)) {
             reserve_list[0] = val;
             for (i = 1; i < MAX_RES_ARGS; i++) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/gdth.h linux.18p8/drivers/scsi/gdth.h
--- linux.vanilla/drivers/scsi/gdth.h	Wed May  3 22:31:20 2000
+++ linux.18p8/drivers/scsi/gdth.h	Fri Sep 15 15:13:39 2000
@@ -10,7 +10,7 @@
  *
  * <achim@vortex.de>
  *
- * $Id: gdth.h,v 1.24 1999/11/02 13:43:49 achim Exp $
+ * $Id: gdth.h,v 1.33 2000/07/24 09:29:25 achim Exp $
  */
 
 #include <linux/version.h>
@@ -29,9 +29,9 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "1.17"
+#define GDTH_VERSION_STR        "1.23"
 #define GDTH_VERSION            1
-#define GDTH_SUBVERSION         17
+#define GDTH_SUBVERSION         23
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
@@ -126,7 +126,8 @@
 #endif
 
 /* limits */
-#define GDTH_SCRATCH    4096                    /* 4KB scratch buffer */
+#define GDTH_SCRATCH    PAGE_SIZE               /* 4KB scratch buffer */
+#define GDTH_SCRATCH_ORD 0                      /* order 0 means 1 page */
 #define GDTH_MAXCMDS    124
 #define GDTH_MAXC_P_L   16                      /* max. cmds per lun */
 #define GDTH_MAX_RAW    2                       /* max. cmds per raw device */
@@ -180,7 +181,7 @@
 #define CLUSTER_RESERVED      4
 #define CLUSTER_RESERVE_STATE (CLUSTER_DRIVE|CLUSTER_MOUNTED|CLUSTER_RESERVED)
 
-/* cache/raw service commands */
+/* commands for all services, cache service */
 #define GDT_INIT        0                       /* service initialization */
 #define GDT_READ        1                       /* read command */
 #define GDT_WRITE       2                       /* write command */
@@ -202,7 +203,7 @@
 #define GDT_RW_ATTRIBS  23                      /* R/W attribs (write thru,..)*/
 #define GDT_CLUST_RESET 24                      /* releases the cluster drives*/
 
-/* additional raw service commands */
+/* raw service commands */
 #define GDT_RESERVE     14                      /* reserve dev. to raw serv. */
 #define GDT_RELEASE     15                      /* release device */
 #define GDT_RESERVE_ALL 16                      /* reserve all devices */
@@ -211,6 +212,9 @@
 #define GDT_SCAN_START  19                      /* start device scan */
 #define GDT_SCAN_END    20                      /* stop device scan */  
 
+/* screen service commands */
+#define GDT_REALTIME    3                       /* realtime clock to screens. */
+
 /* IOCTL command defines */
 #define SCSI_DR_INFO    0x00                    /* SCSI drive info */                   
 #define SCSI_CHAN_CNT   0x05                    /* SCSI channel count */   
@@ -235,18 +239,9 @@
 #define IO_CHANNEL      0x00020000L             /* default IO channel */
 #define INVALID_CHANNEL 0x0000ffffL             /* invalid channel */
 
-/* IOCTLs */
-#define GDTIOCTL_MASK       ('J'<<8)
-#define GDTIOCTL_GENERAL    (GDTIOCTL_MASK | 0) /* general IOCTL */
-#define GDTIOCTL_DRVERS     (GDTIOCTL_MASK | 1) /* get driver version */
-#define GDTIOCTL_CTRTYPE    (GDTIOCTL_MASK | 2) /* get controller type */
-#define GDTIOCTL_CTRCNT     (GDTIOCTL_MASK | 5) /* get controller count */
-#define GDTIOCTL_LOCKDRV    (GDTIOCTL_MASK | 6) /* lock host drive */
-#define GDTIOCTL_LOCKCHN    (GDTIOCTL_MASK | 7) /* lock channel */
-#define GDTIOCTL_EVENT      (GDTIOCTL_MASK | 8) /* read controller events */
-
 /* service errors */
 #define S_OK            1                       /* no error */
+#define S_GENERR        6                       /* general error */
 #define S_BSY           7                       /* controller busy */
 #define S_CACHE_UNKNOWN 12                      /* cache serv.: drive unknown */
 #define S_RAW_SCSI      12                      /* raw serv.: target error */
@@ -263,10 +258,8 @@
 #define HIGH_PRI        0x08
 
 /* data directions */
-#ifndef HOSTS_C
-#define DATA_IN         0x01000000L             /* data from target */
-#define DATA_OUT        0x00000000L             /* data to target */
-#endif
+#define GDTH_DATA_IN    0x01000000L             /* data from target */
+#define GDTH_DATA_OUT   0x00000000L             /* data to target */
 
 /* BMIC registers (EISA controllers) */
 #define ID0REG          0x0c80                  /* board ID */
@@ -472,11 +465,11 @@
 } PACKED gdth_alist_str;
 
 typedef struct {
-    ulong32	entries_avail;			/* allocated entries */
-    ulong32	entries_init;			/* returned entries */
-    ulong32	first_entry;			/* first entry number */
-    ulong32	list_offset;			/* offset of following list */
-    gdth_alist_str list[1];			/* list */
+    ulong32     entries_avail;                  /* allocated entries */
+    ulong32     entries_init;                   /* returned entries */
+    ulong32     first_entry;                    /* first entry number */
+    ulong32     list_offset;                    /* offset of following list */
+    gdth_alist_str list[1];                     /* list */
 } PACKED gdth_arcdl_str;
 
 /* cache info/config IOCTL */
@@ -609,8 +602,13 @@
         } PACKED ioctl;                         /* IOCTL command structure */
         struct {
             ushort      reserved;
-            ulong32     msg_handle;             /* message handle */
-            ulong32     msg_addr;               /* message buffer address */
+            union {
+                struct {
+                    ulong32  msg_handle;        /* message handle */
+                    ulong32  msg_addr;          /* message buffer address */
+                } PACKED msg;
+                unchar       data[12];          /* buffer for rtc data, ... */
+            } su;
         } PACKED screen;                        /* screen service cmd. str. */
         struct {
             ushort      reserved;
@@ -673,6 +671,8 @@
             ulong32         l1, l2, l3, l4;
         } PACKED test;
     } eu;
+    ulong32                 severity;
+    unchar                  event_string[256];          
 } PACKED gdth_evt_data;
 
 typedef struct {
@@ -822,7 +822,9 @@
     unchar              unused5[7];
     unchar              edoor_en_reg;           /* board interrupts enable */
     unchar              unused6[27];
-    ulong32             unused7[1004];          /* size: 4 KB */
+    ulong32             unused7[939];         
+    ulong32             severity;       
+    char                evt_str[256];           /* event string */
 } PACKED gdt6m_i960_regs;
 
 /* DPRAM PCI MPR controllers */
@@ -856,6 +858,7 @@
     ushort              type;                   /* controller class */
     ushort              raw_feat;               /* feat. raw service (s/g,..) */
     ulong32             stype;                  /* controller subtype */
+    ushort              fw_vers;                /* firmware version */
     ushort              cache_feat;             /* feat. cache serv. (s/g,..) */
     ushort              bmic;                   /* BMIC address (EISA) */
     void                *brd;                   /* DPRAM address */
@@ -868,6 +871,7 @@
     unchar              irq;                    /* IRQ */
     unchar              drq;                    /* DRQ (ISA controllers) */
     ushort              status;                 /* command status */
+    ushort              service;                /* service/firmware ver./.. */
     ulong32             info;
     ulong32             info2;                  /* additional info */
     Scsi_Cmnd           *req_first;             /* top of request queue */
@@ -914,6 +918,7 @@
     gdth_cpar_str       cpar;                   /* controller cache par. */
     gdth_bfeat_str      bfeat;                  /* controller features */
     gdth_binfo_str      binfo;                  /* controller info */
+    gdth_evt_data       dvr;                    /* event structure */
 #if LINUX_VERSION_CODE >= 0x02015F
     spinlock_t          smp_lock;
 #endif
@@ -1004,7 +1009,38 @@
 #endif
 const char *gdth_info(struct Scsi_Host *);
 
-#if LINUX_VERSION_CODE >= 0x02015F
+#if LINUX_VERSION_CODE >= 0x020322
+int gdth_bios_param(Disk *,kdev_t,int *);
+int gdth_proc_info(char *,char **,off_t,int,int,int);
+int gdth_eh_abort(Scsi_Cmnd *scp);
+int gdth_eh_device_reset(Scsi_Cmnd *scp);
+int gdth_eh_bus_reset(Scsi_Cmnd *scp);
+int gdth_eh_host_reset(Scsi_Cmnd *scp);
+#define GDTH { proc_name:       "gdth",                          \
+               proc_info:       gdth_proc_info,                  \
+               name:            "GDT SCSI Disk Array Controller",\
+               detect:          gdth_detect,                     \
+               release:         gdth_release,                    \
+               info:            gdth_info,                       \
+               command:         gdth_command,                    \
+               queuecommand:    gdth_queuecommand,               \
+               eh_abort_handler: gdth_eh_abort,                  \
+               eh_device_reset_handler: gdth_eh_device_reset,    \
+               eh_bus_reset_handler: gdth_eh_bus_reset,          \
+               eh_host_reset_handler: gdth_eh_host_reset,        \
+               abort:           gdth_abort,                      \
+               reset:           gdth_reset,                      \
+               bios_param:      gdth_bios_param,                 \
+               can_queue:       GDTH_MAXCMDS,                    \
+               this_id:         -1,                              \
+               sg_tablesize:    GDTH_MAXSG,                      \
+               cmd_per_lun:     GDTH_MAXC_P_L,                   \
+               present:         0,                               \
+               unchecked_isa_dma: 1,                             \
+               use_clustering:  ENABLE_CLUSTERING,               \
+               use_new_eh_code: 1       /* use new error code */ }    
+
+#elif LINUX_VERSION_CODE >= 0x02015F
 int gdth_bios_param(Disk *,kdev_t,int *);
 extern struct proc_dir_entry proc_scsi_gdth;
 int gdth_proc_info(char *,char **,off_t,int,int,int);
@@ -1035,6 +1071,7 @@
                unchecked_isa_dma: 1,                             \
                use_clustering:  ENABLE_CLUSTERING,               \
                use_new_eh_code: 1       /* use new error code */ }    
+
 #elif LINUX_VERSION_CODE >= 0x010300
 int gdth_bios_param(Disk *,kdev_t,int *);
 extern struct proc_dir_entry proc_scsi_gdth;
@@ -1059,6 +1096,7 @@
                    0,                                   \
                    1,                                   \
                    ENABLE_CLUSTERING}
+
 #else
 int gdth_bios_param(Disk *,int,int *);
 #define GDTH { NULL, NULL,                              \
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/gdth_ioctl.h linux.18p8/drivers/scsi/gdth_ioctl.h
--- linux.vanilla/drivers/scsi/gdth_ioctl.h	Fri Apr 21 12:46:28 2000
+++ linux.18p8/drivers/scsi/gdth_ioctl.h	Mon Jul 24 10:32:20 2000
@@ -2,7 +2,7 @@
 #define _GDTH_IOCTL_H
 
 /* gdth_ioctl.h
- * $Id: gdth_ioctl.h,v 1.3 1999/05/26 11:49:57 achim Exp $
+ * $Id: gdth_ioctl.h,v 1.6 2000/07/24 09:29:43 achim Exp $
  */
 
 /* IOCTLs */
@@ -18,8 +18,10 @@
 #define GDTIOCTL_EVENT      (GDTIOCTL_MASK | 8) /* read controller events */
 #define GDTIOCTL_SCSI       (GDTIOCTL_MASK | 9) /* SCSI command */
 #define GDTIOCTL_RESET_BUS  (GDTIOCTL_MASK |10) /* reset SCSI bus */
+#define GDTIOCTL_RESCAN     (GDTIOCTL_MASK |11) /* rescan host drives */
 
-#define GDTIOCTL_MAGIC      0xaffe0001UL
+#define GDTIOCTL_MAGIC      0xaffe0003UL
+#define EVENT_SIZE          294 
 
 
 /* IOCTL structure (write) */
@@ -46,7 +48,7 @@
         struct {
             int             erase;              /* erase event ? */
             int             handle;
-            unchar          evt[34];            /* event structure */
+            unchar          evt[EVENT_SIZE];    /* event structure */
         } event;
         struct {
             unchar          bus;                /* SCSI bus */
@@ -87,7 +89,7 @@
         } ctrcnt;
         struct {
             int             handle;
-            unchar          evt[34];            /* event structure */
+            unchar          evt[EVENT_SIZE];    /* event structure */
         } event;
         struct {
             unchar          bus;                /* SCSI bus, 0xff: invalid */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/gdth_proc.c linux.18p8/drivers/scsi/gdth_proc.c
--- linux.vanilla/drivers/scsi/gdth_proc.c	Fri Apr 21 12:46:28 2000
+++ linux.18p8/drivers/scsi/gdth_proc.c	Mon Jul 24 10:32:20 2000
@@ -1,5 +1,5 @@
 /* gdth_proc.c 
- * $Id: gdth_proc.c,v 1.16 1999/11/02 13:44:11 achim Exp $
+ * $Id: gdth_proc.c,v 1.22 2000/07/24 09:30:28 achim Exp $
  */
 
 #include "gdth_ioctl.h"
@@ -31,18 +31,30 @@
 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
 {
     int             ret_val;
+#if LINUX_VERSION_CODE >= 0x020322
+    Scsi_Cmnd       *scp;
+    Scsi_Device     *sdev;
+#else
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
+#endif
     gdth_iowr_str   *piowr;
 
     TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
     piowr = (gdth_iowr_str *)buffer;
 
+#if LINUX_VERSION_CODE >= 0x020322
+    sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
+    scp  = scsi_allocate_device(sdev, 1, FALSE);
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#else
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
     sdev.host = scp.host = gdth_ctr_vtab[vh];
     sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
+#endif
 
     if (length >= 4) {
         if (strncmp(buffer,"gdth",4) == 0) {
@@ -52,23 +64,33 @@
         } else if (piowr->magic == GDTIOCTL_MAGIC) {
             ret_val = gdth_set_bin_info( buffer, length, hanum, scp );
         } else {
-            printk("GDT: Wrong signature: %6s\n",buffer);
+            printk("GDT: Wrong signature: %x\n",piowr->magic);
             ret_val = -EINVAL;
         }
     } else {
         ret_val = -EINVAL;
     }
+#if LINUX_VERSION_CODE >= 0x020322
+    scsi_release_command(scp);
+    scsi_free_host_dev(sdev);
+#endif
     return ret_val;
 }
          
+#if LINUX_VERSION_CODE >= 0x020322
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
+#else
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+#endif
 {
     int             orig_length, drive, wb_mode;
     int             i, found;
     gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
     gdth_cpar_str   *pcpar;
-    char            cmnd[12];
+
+    char            cmnd[MAX_COMMAND_SIZE];
+    memset(cmnd, 0xff, 12);
 
     TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
@@ -76,7 +98,6 @@
     drive = -1;
     wb_mode = 0;
     found = FALSE;
-    memset(cmnd, 0xff, 12);
 
     if (length >= 5 && strncmp(buffer,"flush",5)==0) {
         buffer += 6;
@@ -103,7 +124,11 @@
                 gdtcmd.u.cache.DeviceNo = i;
                 gdtcmd.u.cache.BlockNo = 1;
                 gdtcmd.u.cache.sg_canz = 0;
+#if LINUX_VERSION_CODE >= 0x020322
+                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+#else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+#endif
             }
         }
         if (!found)
@@ -156,7 +181,11 @@
         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
         pcpar->write_back = wb_mode==1 ? 0:1;
+#if LINUX_VERSION_CODE >= 0x020322
+        gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+#else
         gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+#endif
         gdth_ioctl_free(hanum);
         printk("Done.\n");
         return(orig_length);
@@ -166,9 +195,14 @@
     return(-EINVAL);
 }
 
+#if LINUX_VERSION_CODE >= 0x020322
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
+#else
 static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
+#endif
 {
     unchar          i, j;
+    ushort          k, hdr_cnt;
     gdth_ha_str     *ha;
     gdth_iowr_str   *piowr;
     gdth_iord_str   *piord;
@@ -177,9 +211,11 @@
     ulong32         *ppadd, add_size;
     ulong32         *ppadd2, add_size2;
     ulong           flags;
-    char            cmnd[12];   
     gdth_cmd_str    gdtcmd;
 
+    char            cmnd[MAX_COMMAND_SIZE];   
+    memset(cmnd, 0xff, 12);
+
     TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
     piowr = (gdth_iowr_str *)buffer;
@@ -187,7 +223,6 @@
     pcmd = NULL;
     ppadd = ppadd2 = NULL;
     add_size = add_size2 = 0;
-    memset(cmnd, 0xff, 12);
 
     if (length < GDTOFFSOF(gdth_iowr_str,iu))
         return(-EINVAL);
@@ -242,8 +277,13 @@
             *ppadd2 = virt_to_bus(piord->iu.general.data+add_size);
         }
         /* do IOCTL */
+#if LINUX_VERSION_CODE >= 0x020322
+        gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
+        piord->status = (ulong32)scp->SCp.Message;
+#else
         gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
         piord->status = (ulong32)scp.SCp.Message;
+#endif
         break;
 
       case GDTIOCTL_DRVERS:
@@ -387,12 +427,20 @@
             return(-EBUSY);
         piord = (gdth_iord_str *)ha->pscratch;
         piord->size = sizeof(gdth_iord_str);
-        scp.target = scp.device->id = piowr->iu.scsi.target;
-        scp.channel = scp.device->channel = piowr->iu.scsi.bus;
         memcpy(cmnd, piowr->iu.scsi.cmd, 12);
+#if LINUX_VERSION_CODE >= 0x020322
+        scp->target = scp->device->id = piowr->iu.scsi.target;
+        scp->channel = scp->device->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
+        scp->cmd_len = piowr->iu.scsi.cmd_len;
+        gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
+        piord->status = (ulong32)scp->SCp.Message;
+#else
+        scp.target = scp.device->id = piowr->iu.scsi.target;
+        scp.channel = scp.device->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
         scp.cmd_len = piowr->iu.scsi.cmd_len;
         gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (ulong32)scp.result;
+        piord->status = (ulong32)scp.SCp.Message;
+#endif
         break;
 
       case GDTIOCTL_RESET_BUS:
@@ -400,8 +448,23 @@
             return(-EBUSY);
         piord = (gdth_iord_str *)ha->pscratch;
         piord->size = sizeof(gdth_iord_str);
-        scp.channel = scp.device->channel = piowr->iu.scsi.bus;
+#if LINUX_VERSION_CODE >= 0x020322
+        scp->channel = scp->device->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
+        piord->status = (ulong32)gdth_eh_bus_reset( scp );
+        if (piord->status == SUCCESS)
+            piord->status = S_OK;
+        else
+            piord->status = S_GENERR;
+#elif LINUX_VERSION_CODE >= 0x02015F
+        scp.channel = scp.device->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
         piord->status = (ulong32)gdth_eh_bus_reset( &scp );
+        if (piord->status == SUCCESS)
+            piord->status = S_OK;
+        else
+            piord->status = S_GENERR;
+#else
+        piord->status = S_OK;
+#endif
         break;
 
       case GDTIOCTL_HDRLIST:
@@ -423,22 +486,50 @@
                     gdtcmd.u.cache.DeviceNo = i;
                     gdtcmd.u.cache.BlockNo = 0;
                     gdtcmd.u.cache.sg_canz = 0;
+#if LINUX_VERSION_CODE >= 0x020322
+                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                    if ((scp->SCp.Message & 0xffff) == S_OK)
+                        piord->iu.hdr_list[i].cluster_type = 
+                            (unchar)(scp->SCp.Message>>16);
+#else
                     gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
                     if ((scp.SCp.Message & 0xffff) == S_OK)
                         piord->iu.hdr_list[i].cluster_type = 
                             (unchar)(scp.SCp.Message>>16);
-		}
+#endif
+                }
             } else {
                 piord->iu.hdr_list[i].bus = 0xff;
             }
         }
         break;
 
+      case GDTIOCTL_RESCAN:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        GDTH_LOCK_HA(ha, flags);
+        gdth_polling = TRUE;
+        while (gdth_test_busy(hanum))
+            gdth_delay(0);
+        /* initialize cache service */
+        gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0);
+        hdr_cnt = (ushort)ha->info;
+        /* scanning for host drives */
+        for (k = 0; k < MAX_HDRIVES; ++k)
+            ha->hdr[k].present = FALSE;
+        for (k = 0; k < hdr_cnt; ++k) 
+            gdth_analyse_hdrive(hanum, k);
+        gdth_polling = FALSE;
+        GDTH_UNLOCK_HA(ha, flags);
+        break;
+
       default:
         return(-EINVAL);
     }
-    /* we return a buffer ID to detect the right buffer during READ-IOCTL */
-    return 1;
+    return length;
 }
 
 static int gdth_get_info(char *buffer,char **start,off_t offset,
@@ -454,9 +545,13 @@
 
     gdth_cmd_str gdtcmd;
     gdth_evt_str estr;
+#if LINUX_VERSION_CODE >= 0x020322
+    Scsi_Cmnd *scp;
+    Scsi_Device *sdev;
+#else
     Scsi_Cmnd scp;
     Scsi_Device sdev;
-    char cmnd[12];
+#endif
     char hrec[161];
     struct timeval tv;
 
@@ -467,19 +562,27 @@
     gdth_cdrinfo_str *pcdi;
     gdth_hget_str *phg;
 
+    char cmnd[MAX_COMMAND_SIZE];
+    memset(cmnd, 0xff, 12);
+
     TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
     ha = HADATA(gdth_ctr_tab[hanum]);
-    id = length;
 
+#if LINUX_VERSION_CODE >= 0x020322
+    sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
+    scp  = scsi_allocate_device(sdev, 1, FALSE);
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#else
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    memset(cmnd, 0xff, 12);
     sdev.host = scp.host = gdth_ctr_vtab[vh];
     sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
+#endif
 
-    /* look for buffer ID in length */
-    if (id > 1) {
+    /* ioctl from tool? */
+    if (!gdth_ioctl_check_bin(hanum, (ushort)length)) {
         /* request is i.e. "cat /proc/scsi/gdth/0" */ 
         /* format: %-15s\t%-10s\t%-15s\t%s */
         /* driver parameters */
@@ -514,11 +617,10 @@
         /* controller information */
         size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
         len += size;  pos = begin + len;
-#if LINUX_VERSION_CODE >= 0x020000
-        strcpy(hrec, ha->binfo.type_string);
-#else
-        sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
-#endif
+        if (virt_ctr)
+            sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
+        else
+            strcpy(hrec, ha->binfo.type_string);
         size = sprintf(buffer+len,
                        " Number:       \t%d         \tName:          \t%s\n",
                        hanum, hrec);
@@ -586,11 +688,16 @@
                     sizeof(pds->list[0]);
                 if (pds->entries > cnt)
                     pds->entries = cnt;
+#if LINUX_VERSION_CODE >= 0x020322
+                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                if ((scp->SCp.Message & 0xffff) != S_OK) 
+#else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
                 if ((scp.SCp.Message & 0xffff) != S_OK) 
+#endif
+                { 
                     pds->count = 0;
-                TRACE2(("pdr_statistics() entries %d status %d\n",
-                        pds->count, scp.SCp.Message));
+                }
 
                 /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
                 for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
@@ -606,8 +713,14 @@
                     gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
                     gdtcmd.u.ioctl.channel = 
                         ha->raw[i].address | ha->raw[i].id_list[j];
+#if LINUX_VERSION_CODE >= 0x020322
+                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                    if ((scp->SCp.Message & 0xffff) == S_OK) 
+#else
                     gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                    if ((scp.SCp.Message & 0xffff) == S_OK) {
+                    if ((scp.SCp.Message & 0xffff) == S_OK) 
+#endif
+                    {
                         strncpy(hrec,pdi->vendor,8);
                         strncpy(hrec+8,pdi->product,16);
                         strncpy(hrec+24,pdi->revision,4);
@@ -657,8 +770,14 @@
                         gdtcmd.u.ioctl.channel = 
                             ha->raw[i].address | ha->raw[i].id_list[j];
                         pdef->sddc_type = 0x08;
+#if LINUX_VERSION_CODE >= 0x020322
+                        gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                        if ((scp->SCp.Message & 0xffff) == S_OK) 
+#else
                         gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                        if ((scp.SCp.Message & 0xffff) == S_OK) {
+                        if ((scp.SCp.Message & 0xffff) == S_OK) 
+#endif
+                        {
                             size = sprintf(buffer+len,
                                            " Grown Defects:\t%d\n",
                                            pdef->sddc_cnt);
@@ -704,9 +823,16 @@
                     gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
                     gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
                     gdtcmd.u.ioctl.channel = drv_no;
+#if LINUX_VERSION_CODE >= 0x020322
+                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                    if ((scp->SCp.Message & 0xffff) != S_OK)
+#else
                     gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
                     if ((scp.SCp.Message & 0xffff) != S_OK)
+#endif
+                    {
                         break;
+                    }
                     pcdi->ld_dtype >>= 16;
                     j++;
                     if (pcdi->ld_dtype > 2) {
@@ -801,8 +927,14 @@
                 gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
                 gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
                 gdtcmd.u.ioctl.channel = i;
+#if LINUX_VERSION_CODE >= 0x020322
+                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                if ((scp->SCp.Message & 0xffff) == S_OK) 
+#else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                if ((scp.SCp.Message & 0xffff) == S_OK) {
+                if ((scp.SCp.Message & 0xffff) == S_OK) 
+#endif
+                {
                     if (pai->ai_state == 0)
                         strcpy(hrec, "idle");
                     else if (pai->ai_state == 2)
@@ -876,8 +1008,14 @@
                 gdtcmd.u.ioctl.channel = i;
                 phg->entries = MAX_HDRIVES;
                 phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
+#if LINUX_VERSION_CODE >= 0x020322
+                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+                if ((scp->SCp.Message & 0xffff) != S_OK) 
+#else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                if ((scp.SCp.Message & 0xffff) != S_OK) {
+                if ((scp.SCp.Message & 0xffff) != S_OK) 
+#endif
+                {
                     ha->hdr[i].ldr_no = i;
                     ha->hdr[i].rw_attribs = 0;
                     ha->hdr[i].start_sec = 0;
@@ -891,8 +1029,6 @@
                         ha->hdr[k].start_sec = phg->entry[j].start_sec;
                     }
                 }
-                TRACE2(("host_get entries %d status %d\n",
-                        phg->entries, scp.SCp.Message));
             }
             gdth_ioctl_free(hanum);
 
@@ -959,17 +1095,14 @@
         length = piord->size;
         memcpy(buffer+len, (char *)piord, length);
         gdth_ioctl_free(hanum);
-        len += length; pos = begin + len;
-
-        if (pos < offset) {
-            len = 0;
-            begin = pos;
-        }
-        if (pos > offset + length)
-            goto stop_output;
+        len = length; 
     }
 
 stop_output:
+#if LINUX_VERSION_CODE >= 0x020322
+    scsi_release_command(scp);
+    scsi_free_host_dev(sdev);
+#endif
     *start = buffer +(offset-begin);
     len -= (offset-begin);
     if (len > length)
@@ -982,8 +1115,12 @@
 static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, 
                         char *cmnd, int timeout)
 {
-    struct semaphore sem = MUTEX_LOCKED;
     unsigned bufflen;
+#if LINUX_VERSION_CODE >= 0x020322
+    DECLARE_MUTEX_LOCKED(sem);
+#else
+    struct semaphore sem = MUTEX_LOCKED;
+#endif
 
     TRACE2(("gdth_do_cmd()\n"));
     if (gdtcmd != NULL) { 
@@ -995,9 +1132,13 @@
     }
     scp->request.rq_status = RQ_SCSI_BUSY;
     scp->request.sem = &sem;
+#if LINUX_VERSION_CODE >= 0x020322
+    scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
+#else
     GDTH_LOCK_SCSI_DOCMD();
     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
     GDTH_UNLOCK_SCSI_DOCMD();
+#endif
     down(&sem);
 }
 
@@ -1046,26 +1187,41 @@
     GDTH_UNLOCK_HA(ha, flags);
 }
 
+static int gdth_ioctl_check_bin(int hanum, ushort size)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+    int ret_val;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    GDTH_LOCK_HA(ha, flags);
+
+    ret_val = FALSE;
+    if (ha->scratch_busy) {
+        if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size)
+            ret_val = TRUE;
+    }
+    GDTH_UNLOCK_HA(ha, flags);
+    return ret_val;
+}
+
+
 static void gdth_wait_completion(int hanum, int busnum, int id)
 {
     gdth_ha_str *ha;
     ulong flags;
     int i;
     Scsi_Cmnd *scp;
+    unchar b;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         scp = ha->cmd_tab[i].cmnd;
-#if LINUX_VERSION_CODE >= 0x020000
-        if (!SPECIAL_SCP(scp) && scp->target == (unchar)id &&
-            scp->channel == (unchar)busnum)
-#else
-        if (!SPECIAL_SCP(scp) && scp->target == (unchar)id &&
-            NUMDATA(scp->host)->busnum == (unchar)busnum)
-#endif
-        {
+        b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+        if (!SPECIAL_SCP(scp) && scp->target == (unchar)id && 
+            b == (unchar)busnum) {
             scp->SCp.have_data_in = 0;
             GDTH_UNLOCK_HA(ha, flags);
             while (!scp->SCp.have_data_in)
@@ -1084,19 +1240,14 @@
     gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *scp;
+    unchar b;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-#if LINUX_VERSION_CODE >= 0x020000
-        if (scp->target == (unchar)id &&
-            scp->channel == (unchar)busnum)
-#else
-        if (scp->target == (unchar)id &&
-            NUMDATA(scp->host)->busnum == (unchar)busnum)
-#endif
-        {
+        b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+        if (scp->target == (unchar)id && b == (unchar)busnum) {
             TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
             scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
         }
@@ -1109,19 +1260,14 @@
     gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *scp;
+    unchar b;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
-#if LINUX_VERSION_CODE >= 0x020000
-        if (scp->target == (unchar)id &&
-            scp->channel == (unchar)busnum)
-#else
-        if (scp->target == (unchar)id &&
-            NUMDATA(scp->host)->busnum == (unchar)busnum)
-#endif
-        {
+        b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+        if (scp->target == (unchar)id && b == (unchar)busnum) {
             TRACE2(("gdth_start_timeout(): update_timeout()\n"));
             gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
         }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/gdth_proc.h linux.18p8/drivers/scsi/gdth_proc.h
--- linux.vanilla/drivers/scsi/gdth_proc.h	Fri Apr 21 12:46:28 2000
+++ linux.18p8/drivers/scsi/gdth_proc.h	Mon Jul 24 10:32:20 2000
@@ -2,24 +2,31 @@
 #define _GDTH_PROC_H
 
 /* gdth_proc.h 
- * $Id: gdth_proc.h,v 1.7 1999/05/26 11:49:32 achim Exp $
+ * $Id: gdth_proc.h,v 1.10 2000/07/24 09:30:01 achim Exp $
  */
 
 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
-static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
 static int gdth_get_info(char *buffer,char **start,off_t offset,
                          int length,int vh,int hanum,int busnum);
 
+#if LINUX_VERSION_CODE >= 0x020322
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp);
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp);
+#else 
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+#endif
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
+                        char *cmnd, int timeout);
+
 static int gdth_ioctl_alloc(int hanum, ushort size);
 static void gdth_ioctl_free(int hanum);
+static int gdth_ioctl_check_bin(int hanum, ushort size);
 static void gdth_wait_completion(int hanum, int busnum, int id);
 static void gdth_stop_timeout(int hanum, int busnum, int id);
 static void gdth_start_timeout(int hanum, int busnum, int id);
 static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout);
 
-static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
-                        char *cmnd, int timeout);
 void gdth_scsi_done(Scsi_Cmnd *scp);
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/hosts.c linux.18p8/drivers/scsi/hosts.c
--- linux.vanilla/drivers/scsi/hosts.c	Sat Sep  9 18:42:41 2000
+++ linux.18p8/drivers/scsi/hosts.c	Sun Sep  3 14:00:02 2000
@@ -131,6 +131,10 @@
 #include "aha1740.h"
 #endif
 
+#ifdef CONFIG_SCSI_AACRAID
+#include "aacraid/include/linit.h"
+#endif
+
 #ifdef CONFIG_SCSI_AIC7XXX
 #include "aic7xxx.h"
 #endif
@@ -483,6 +487,9 @@
 #endif
 #ifdef CONFIG_SCSI_AHA1740
     AHA1740,
+#endif
+#ifdef CONFIG_SCSI_AACRAID
+    AAC_HOST_TEMPLATE_ENTRY,
 #endif
 #ifdef CONFIG_SCSI_AIC7XXX
     AIC7XXX,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ibmmca.c linux.18p8/drivers/scsi/ibmmca.c
--- linux.vanilla/drivers/scsi/ibmmca.c	Fri Apr 21 12:46:28 2000
+++ linux.18p8/drivers/scsi/ibmmca.c	Mon Jul 31 20:57:07 2000
@@ -7,7 +7,7 @@
  * See the file README.ibmmca for a detailed description of this driver,
  * the commandline arguments and the history of its development.
  * See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest
- * updates and info.
+ * updates, info and ADF-files for adapters supported by this driver.
  */
 
 /******************* HEADER FILE INCLUDES ************************************/
@@ -16,14 +16,12 @@
 #endif
 
 /* choose adaption for Kernellevel */
-#define local_LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-#if LINUX_VERSION_CODE < local_LinuxVersionCode(2,1,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,65)
 #define OLDKERN
 #else
 #undef OLDKERN
 #endif
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/ctype.h>
@@ -36,10 +34,13 @@
 #include <linux/stat.h>
 #include <linux/mca.h>
 #include <asm/system.h>
-#ifndef OLDKERN
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17)
+#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 #include <asm/spinlock.h>
 #endif
 #include <asm/io.h>
+#include <linux/init.h>
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -49,6 +50,7 @@
 
 /******************* LOCAL DEFINES *******************************************/
 
+/* milliseconds of delay for timing out reset. */
 #ifndef mdelay
 #define mdelay(a)    udelay((a) * 1000)
 #endif
@@ -56,7 +58,7 @@
 /*--------------------------------------------------------------------*/
 
 /* current version of this driver-source: */
-#define IBMMCA_SCSI_DRIVER_VERSION "3.1e"
+#define IBMMCA_SCSI_DRIVER_VERSION "3.2"
 
 /*--------------------------------------------------------------------*/
 
@@ -110,6 +112,7 @@
 /*note: the lower nibble specifies the device(0-14), or subsystem(15) */
 #define IM_SCB_CMD_COMPLETED               0x10
 #define IM_SCB_CMD_COMPLETED_WITH_RETRIES  0x50
+#define IM_LOOP_SCATTER_BUFFER_FULL        0x60
 #define IM_ADAPTER_HW_FAILURE              0x70
 #define IM_IMMEDIATE_CMD_COMPLETED         0xa0
 #define IM_CMD_COMPLETED_WITH_FAILURE      0xc0
@@ -153,7 +156,7 @@
 	    unsigned short length;	/*block length, on SCSI device */
 	  }
 	blk;
-	unsigned char scsi_command[12];		/*other scsi command */
+	unsigned char scsi_command[12];	   /*other scsi command */
       }
     u2;
   };
@@ -165,6 +168,31 @@
     unsigned long byte_length;
   };
 
+/*structure returned by a get_pos_info command: */
+struct im_pos_info
+  {
+     unsigned short pos_id;         /* adapter id */
+     unsigned char pos_3a;          /* pos 3 (if pos 6 = 0) */
+     unsigned char pos_2;           /* pos 2 */
+     unsigned char int_level;       /* interrupt level IRQ 11 or 14 */
+     unsigned char pos_4a;          /* pos 4 (if pos 6 = 0) */
+     unsigned short connector_size; /* MCA connector size: 16 or 32 Bit */
+     unsigned char num_luns;        /* number of supported luns per device */
+     unsigned char num_puns;        /* number of supported puns */
+     unsigned char pacing_factor;   /* pacing factor */
+     unsigned char num_ldns;        /* number of ldns available */
+     unsigned char eoi_off;         /* time EOI and interrupt inactive */
+     unsigned char max_busy;        /* time between reset and busy on */
+     unsigned short cache_stat;     /* ldn cachestat. Bit=1 = not cached */
+     unsigned short retry_stat;     /* retry status of ldns. Bit=1=disabled */
+     unsigned char pos_4b;          /* pos 4 (if pos 6 = 1) */
+     unsigned char pos_3b;          /* pos 3 (if pos 6 = 1) */
+     unsigned char pos_6;           /* pos 6 */
+     unsigned char pos_5;           /* pos 5 */ 
+     unsigned short max_overlap;    /* maximum overlapping requests */
+     unsigned short num_bus;        /* number of SCSI-busses */
+  };
+
 /*values for SCB command word */
 #define IM_NO_SYNCHRONOUS      0x0040	/*flag for any command */
 #define IM_NO_DISCONNECT       0x0080	/*flag for any command */
@@ -175,6 +203,7 @@
 #define IM_REQUEST_SENSE_CMD   0x1c08
 #define IM_READ_CAPACITY_CMD   0x1c09
 #define IM_DEVICE_INQUIRY_CMD  0x1c0b
+#define IM_READ_LOGICAL_CMD    0x1c2a
 #define IM_OTHER_SCSI_CMD_CMD  0x241f
 
 /* unused, but supported, SCB commands */
@@ -190,6 +219,7 @@
 #define IM_RETRY_ENABLE              0x2000
 #define IM_POINTER_TO_LIST           0x1000
 #define IM_SUPRESS_EXCEPTION_SHORT   0x0400
+#define IM_BYPASS_BUFFER             0x0200
 #define IM_CHAIN_ON_NO_ERROR         0x0001
 
 /*TSB (Termination Status Block) structure */
@@ -211,15 +241,17 @@
   };
 
 /*subsystem uses interrupt request level 14 */
-#define IM_IRQ  14
+#define IM_IRQ     14
+/*SCSI-2 F/W may evade to interrupt 11 */
+#define IM_IRQ_FW  11
 
 /*--------------------------------------------------------------------*/
 /*
 	The model 95 doesn't have a standard activity light.  Instead it
-	has a row of LEDs on the front.  We use the last one as the activity
-	indicator if we think we're on a model 95.  I suspect the model id
-	check will be either too narrow or too general, and some machines
-	won't have an activity indicator.  Oh well...
+	has a row of alphanumerial LEDs on the front.  We use the last one 
+        as the activity indicator if we think we're on a model 95.  I suspect
+        the model id check will be either too narrow or too general, and some 
+        machines won't have an activity indicator.  Oh well...
 
 	The regular PS/2 disk led is turned on/off by bits 6,7 of system
 	control port.
@@ -229,6 +261,12 @@
 #define MOD95_LED_PORT	   0x108
 /* system-control-register of PS/2s with diskindicator */
 #define PS2_SYS_CTR        0x92
+/* activity displaying methods */
+#define LED_DISP           1
+#define LED_ADISP          2
+#define LED_ACTIVITY       4
+
+#define CMD_FAIL           255
 
 /* The SCSI-ID(!) of the accessed SCSI-device is shown on PS/2-95 machines' LED
    displays. ldn is no longer displayed here, because the ldn mapping is now 
@@ -237,30 +275,39 @@
    interest, debugging or just for having fun. The left number gives the
    host-adapter number and the right shows the accessed SCSI-ID. */
 
-/* use_display is set by the ibmmcascsi=display command line arg */
-static int use_display = 0;
-/* use_adisplay is set by ibmmcascsi=adisplay, which offers a higher
- * level of displayed luxus on PS/2 95 (really fancy! :-))) */
-static int use_adisplay = 0;
+/* display_mode is set by the ibmmcascsi= command line arg */
+static int display_mode = 0;
+/* set default adapter timeout */
+static unsigned int adapter_timeout = 45;
+/* for probing on feature-command: */
+static unsigned int global_command_error_excuse = 0;
+/* global setting by command line for adapter_speed */
+static int global_adapter_speed = 0; /* full speed by default */
 
+/* Panel / LED on, do it right for F/W addressin, too. adisplay will
+ * just ignore ids>7, as the panel has only 7 digits available */
 #define PS2_DISK_LED_ON(ad,id) {\
-	if( use_display ) { outb((char)(id+48), MOD95_LED_PORT ); \
-        outb((char)(ad+48), MOD95_LED_PORT+1); } \
-        else if( use_adisplay ) { if (id<7) outb((char)(id+48), \
-	MOD95_LED_PORT+1+id); outb((char)(ad+48), MOD95_LED_PORT); } \
-	else outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \
+        if (display_mode & LED_DISP) { \
+           if (id>9) \
+	     outw((ad+48)|((id+55)<<8), MOD95_LED_PORT ); \
+           else \
+             outw((ad+48)|((id+48)<<8), MOD95_LED_PORT ); } \
+        else if (display_mode & LED_ADISP) { \
+           if (id<7) outb((char)(id+48),MOD95_LED_PORT+1+id); \
+           outb((char)(ad+48), MOD95_LED_PORT); } \
+        if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
+           outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \
 }
-
+/* Panel / LED off */
 /* bug fixed, Dec 15, 1997, where | was replaced by & here */
 #define PS2_DISK_LED_OFF() {\
-	if( use_display ) { outb( ' ', MOD95_LED_PORT ); \
-        outb(' ', MOD95_LED_PORT+1); } \
-        if ( use_adisplay ) { outb(' ',MOD95_LED_PORT ); \
-	outb(' ',MOD95_LED_PORT+1); outb(' ',MOD95_LED_PORT+2); \
-        outb(' ',MOD95_LED_PORT+3); outb(' ',MOD95_LED_PORT+4); \
-        outb(' ',MOD95_LED_PORT+5); outb(' ',MOD95_LED_PORT+6); \
-	outb(' ',MOD95_LED_PORT+7); } \
-	else outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \
+	if (display_mode & LED_DISP) \
+           outw(0x2020, MOD95_LED_PORT ); \
+        else if (display_mode & LED_ADISP) { \
+           outl(0x20202020,MOD95_LED_PORT); \
+           outl(0x20202020,MOD95_LED_PORT+4); } \
+	if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
+           outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \
 }
 
 /*--------------------------------------------------------------------*/
@@ -272,17 +319,29 @@
     char *description;
   };
 
+/* types of different supported hardware that goes to hostdata special */
+#define IBM_SCSI2_FW     0
+#define IBM_7568_WCACHE  1
+#define IBM_EXP_UNIT     2
+#define IBM_SCSI_WCACHE  3
+#define IBM_SCSI         4
+
+/* other special flags for hostdata structure */
+#define FORCED_DETECTION         100
+#define INTEGRATED_SCSI          101
+
 /* List of possible IBM-SCSI-adapters */
 struct subsys_list_struct subsys_list[] =
 {
-  {0x8efc, "IBM Fast SCSI-2 Adapter"}, /* special = 0 */
-  {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/cache"}, /* special = 1 */
+  {0x8efc, "IBM SCSI-2 F/W Adapter"}, /* special = 0 */
+  {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/Cache"}, /* special = 1 */
   {0x8ef8, "IBM Expansion Unit SCSI Controller"},/* special = 2 */
   {0x8eff, "IBM SCSI Adapter w/Cache"}, /* special = 3 */
   {0x8efe, "IBM SCSI Adapter"}, /* special = 4 */
 };                   
 
-/*for /proc filesystem */
+/*for /proc filesystem, only valid in older kernel releases */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27)
 struct proc_dir_entry proc_scsi_ibmmca =
 {
   PROC_SCSI_IBMMCA, 6, "ibmmca",
@@ -290,6 +349,7 @@
   0, 0, 0, NULL, NULL, NULL, NULL,
   NULL, NULL, NULL 
 };
+#endif
 
 /* Max number of logical devices (can be up from 0 to 14).  15 is the address
 of the adapter itself. */
@@ -302,11 +362,12 @@
     struct im_tsb tsb; /* SCSI command complete status block structure */
     struct im_sge sge[16]; /* scatter gather list structure */
     unsigned char buf[256]; /* SCSI command return data buffer */
-    Scsi_Cmnd *cmd;  /* SCSI-command that is currently in progress */
-     
+    Scsi_Cmnd *cmd;  /* SCSI-command that is currently in progress */     
     int device_type; /* type of the SCSI-device. See include/scsi/scsi.h
 		        for interpretation of the possible values */
     int block_length;/* blocksize of a particular logical SCSI-device */
+    int cache_flag; /* 1 if this is uncached, 0 if cache is present for ldn */
+    int retry_flag; /* 1 if adapter retry is disabled, 0 if enabled */
   };
 
 /* statistics of the driver during operations (for proc_info) */
@@ -318,6 +379,8 @@
       int ldn_write_access[MAX_LOG_DEV+1];   /* total write-access on a ldn */
       int ldn_inquiry_access[MAX_LOG_DEV+1]; /* total inquiries on a ldn */
       int ldn_modeselect_access[MAX_LOG_DEV+1]; /* total mode selects on ldn */
+      int scbs;                              /* short SCBs queued */
+      int long_scbs;                         /* long SCBs queued */
       int total_accesses;                    /* total accesses on all ldns */
       int total_interrupts;                  /* total interrupts (should be
 						same as total_accesses) */
@@ -336,10 +399,10 @@
    /* array of logical devices: */
    struct logical_device _ld[MAX_LOG_DEV+1];   
    /* array to convert (pun, lun) into logical device number: */
-   unsigned char _get_ldn[8][8];
+   unsigned char _get_ldn[16][8];
    /*array that contains the information about the physical SCSI-devices
     attached to this host adapter: */
-   unsigned char _get_scsi[8][8];
+   unsigned char _get_scsi[16][8];
    /* used only when checking logical devices: */
    int _local_checking_phase_flag;
    /* report received interrupt: */
@@ -352,21 +415,30 @@
    int _last_scsi_command[MAX_LOG_DEV+1];
    /* identifier of the last SCSI-command type */
    int _last_scsi_type[MAX_LOG_DEV+1];
+   /* last blockcount */
+   int _last_scsi_blockcount[MAX_LOG_DEV+1];
+   /* last locgical block address */
+   unsigned long _last_scsi_logical_block[MAX_LOG_DEV+1];
    /* Counter that points on the next reassignable ldn for dynamical 
     remapping. The default value is 7, that is the first reassignable 
     number in the list at boottime: */
    int _next_ldn;
    /* Statistics-structure for this IBM-SCSI-host: */
    struct Driver_Statistics _IBM_DS;
-   /* This hostadapters pos-registers pos2 and pos3 */
-   unsigned _pos2, _pos3;
+   /* This hostadapters pos-registers pos2 until pos6 */
+   unsigned _pos2, _pos3, _pos4, _pos5, _pos6;
    /* assign a special variable, that contains dedicated info about the
     adaptertype */
    int _special;
+   /* connector size on the MCA bus */
+   int _connector_size;
+   /* synchronous SCSI transfer rate bitpattern */
+   int _adapter_speed;
 };
 
 /* macros to access host data structure */
 #define subsystem_pun(hi) (hosts[(hi)]->this_id)
+#define subsystem_maxid(hi) (hosts[(hi)]->max_id)
 #define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld)
 #define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn)
 #define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi)
@@ -376,11 +448,19 @@
 #define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status)
 #define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command)
 #define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
+#define last_scsi_blockcount(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_blockcount)
+#define last_scsi_logical_block(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_logical_block)
+#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
 #define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn)
 #define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS)
 #define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special)
+#define subsystem_connector_size(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_connector_size)
+#define adapter_speed(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_adapter_speed)
 #define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos2)
 #define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos3)
+#define pos4(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos4)
+#define pos5(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos5)
+#define pos6(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos6)
 
 /* Define a arbitrary number as subsystem-marker-type. This number is, as 
    described in the ANSI-SCSI-standard, not occupied by other device-types. */
@@ -412,10 +492,6 @@
 #define IM_RESET_NOT_IN_PROGRESS_NO_INT  4
 #define IM_RESET_FINISHED_OK_NO_INT      5
 
-/* special flags for hostdata structure */
-#define FORCED_DETECTION         100
-#define INTEGRATED_SCSI          101
-
 /* define undefined SCSI-command */
 #define NO_SCSI                  0xffff
 
@@ -427,7 +503,10 @@
 
 /* fill module-parameters only, when this define is present.
    (that is kernel version 2.1.x) */
-#ifdef MODULE_PARM
+#if defined(MODULE)
+static char *boot_options = NULL;
+#include <linux/module.h>
+MODULE_PARM(boot_options, "s");
 MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");
 MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); 
 MODULE_PARM(display, "1i");
@@ -452,8 +531,10 @@
 
 /* host information */
 static int found = 0;
-static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL };
-static unsigned int pos[8]; /* whole pos register-line */
+static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL, NULL, NULL, NULL, 
+                                                   NULL, NULL, NULL, NULL,
+                                                   NULL };
+static unsigned int pos[8]; /* whole pos register-line for diagnosis */
 /* Taking into account the additions, made by ZP Gu.
  * This selects now the preset value from the configfile and
  * offers the 'normal' commandline option to be accepted */
@@ -473,25 +554,30 @@
 #endif
 static void issue_cmd (int, unsigned long, unsigned char);
 static void internal_done (Scsi_Cmnd * cmd);
-static void check_devices (int);
+static void check_devices (int, int);
 static int immediate_assign(int, unsigned int, unsigned int, unsigned int, 
                             unsigned int);
+static int immediate_feature(int, unsigned int, unsigned int);
 #ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
 static int immediate_reset(int, unsigned int);
 #endif
 static int device_inquiry(int, int);
 static int read_capacity(int, int);
+static int get_pos_info(int);
 static char *ti_p(int);
 static char *ti_l(int);
+static char *ibmrate(unsigned int, int);
+static int probe_display(int);
+static int probe_bus_mode(int);
 static int device_exists (int, int, int *, int *);
-static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, 
-					 int, int, char *);
-
+static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *,
+					 int, int, int, char *);
 /* local functions needed for proc_info */
 static int ldn_access_load(int, int);
 static int ldn_access_total_read_write(int);
 
 static int bypass_controller = 0;   /* bypass integrated SCSI-cmd set flag */
+
 /*--------------------------------------------------------------------*/
 
 /******************* LOCAL FUNCTIONS IMPLEMENTATION *************************/
@@ -515,20 +601,17 @@
    unsigned int intr_reg;
    unsigned int cmd_result;
    unsigned int ldn;
-   static unsigned long flags;
+   unsigned long flags;
    Scsi_Cmnd *cmd;
-   int errorflag;
-   int interror;
-
-   host_index=0; /* make sure, host_index is 0, else this won't work and
-		    never dare to ask, what happens, if an interrupt-handler
-		    does not work :-((( .... */
+   int lastSCSI;
    
+   host_index = 0; /* make sure, host_index is 0 */
+
    /* search for one adapter-response on shared interrupt */
    while (hosts[host_index]
 	  && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST))
      host_index++;
-   
+      
    /* return if some other device on this IRQ caused the interrupt */
    if (!hosts[host_index]) return;
 
@@ -541,11 +624,6 @@
 	return;
      }
    
-   /*get command result and logical device */
-   intr_reg = inb (IM_INTR_REG(host_index));
-   cmd_result = intr_reg & 0xf0;
-   ldn = intr_reg & 0x0f;
-
    /*must wait for attention reg not busy, then send EOI to subsystem */
    while (1) 
      {
@@ -555,7 +633,8 @@
 #else
 	spin_lock_irqsave(&intr_lock, flags);
 #endif	
-	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) 
+	/* if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) */
+	if ((inb(IM_STAT_REG(host_index)) & 0xf) == (IM_CMD_REG_EMPTY | IM_INTR_REQUEST))
 	  break;
 #ifdef OLDKERN	
 	restore_flags(flags);
@@ -563,78 +642,107 @@
 	spin_unlock_irqrestore(&intr_lock, flags);
 #endif
      }
-   outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+   /*get command result and logical device */
+   intr_reg = (unsigned char)(inb (IM_INTR_REG(host_index)));
+   cmd_result = intr_reg & 0xf0;
+   ldn = intr_reg & 0x0f;
+
    /* get the last_scsi_command here */
-   interror = last_scsi_command(host_index)[ldn];   
-#ifdef OLDKERN
-   restore_flags(flags);
-#else
-   spin_unlock_irqrestore(&intr_lock, flags);
-#endif      
-   errorflag = 0; /* no errors by default */   
+   lastSCSI = last_scsi_command(host_index)[ldn];
+   
    /*these should never happen (hw fails, or a local programming bug) */
-   if (cmd_result == IM_ADAPTER_HW_FAILURE)
-     {
-	printk("\n");
-	printk("IBM MCA SCSI: ERROR - subsystem hardware failure!\n");
-	printk("              Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
-	       last_scsi_command(host_index)[ldn],ldn,host_index);
-	errorflag = 1;
-     }
-   if (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR)
-     {
-	printk("\n");
-	printk("IBM MCA SCSI: ERROR - software sequencing error!\n");
-	printk("              Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
-	       last_scsi_command(host_index)[ldn],ldn,host_index);
-	errorflag = 1;	
+   if (!global_command_error_excuse)
+     {	
+	switch (cmd_result)
+	  { /* Prevent from Ooopsing on error to show the real reason */      
+	   case IM_ADAPTER_HW_FAILURE:
+	   case IM_SOFTWARE_SEQUENCING_ERROR:
+	   case IM_CMD_ERROR:
+	     printk("\nIBM MCA SCSI: Fatal Subsystem ERROR!\n");
+	     printk("              Last cmd=0x%x, ena=%x, len=",lastSCSI,
+		    ld(host_index)[ldn].scb.enable);
+	     if (ld(host_index)[ldn].cmd)
+	       printk("%ld/%ld",(long)(ld(host_index)[ldn].cmd->request_bufflen),
+		      (long)(ld(host_index)[ldn].scb.sys_buf_length));
+	     else
+	       printk("none");
+	     printk(", ");
+	     if (ld(host_index)[ldn].cmd)
+	       printk("Blocksize=%d",ld(host_index)[ldn].scb.u2.blk.length);
+	     else
+	       printk("Blocksize=none");
+	     printk(", host=0x%x, ldn=0x%x\n",host_index, ldn);
+	     if (ld(host_index)[ldn].cmd)
+	       {		  
+		  printk("Blockcount=%d/%d\n",last_scsi_blockcount(host_index)[ldn],
+			 ld(host_index)[ldn].scb.u2.blk.count);
+		  printk("Logical block=%lx/%lx\n",last_scsi_logical_block(host_index)[ldn],
+			 ld(host_index)[ldn].scb.u1.log_blk_adr);
+	       }	     			 
+	     printk("Reason given: %s\n",
+		    (cmd_result==IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" :
+		    (cmd_result==IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" :
+		    (cmd_result==IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");	
+	     /* if errors appear, enter this section to give detailed info */
+	     printk("IBM MCA SCSI: Subsystem Error-Status follows:\n");
+	     printk("              Command Type................: %x\n",
+		    last_scsi_type(host_index)[ldn]);
+	     printk("              Attention Register..........: %x\n",
+		    inb (IM_ATTN_REG(host_index)));
+	     printk("              Basic Control Register......: %x\n",
+		    inb (IM_CTR_REG(host_index)));
+	     printk("              Interrupt Status Register...: %x\n",
+		    intr_reg);
+	     printk("              Basic Status Register.......: %x\n",
+		    inb (IM_STAT_REG(host_index)));
+	     if ((last_scsi_type(host_index)[ldn]==IM_SCB)||
+		 (last_scsi_type(host_index)[ldn]==IM_LONG_SCB))
+	       {
+	          printk("              SCB-Command.................: %x\n",
+			 ld(host_index)[ldn].scb.command);
+		  printk("              SCB-Enable..................: %x\n",
+			 ld(host_index)[ldn].scb.enable);
+		  printk("              SCB-logical block address...: %lx\n",
+			 ld(host_index)[ldn].scb.u1.log_blk_adr);
+		  printk("              SCB-system buffer address...: %lx\n",
+			 ld(host_index)[ldn].scb.sys_buf_adr);
+		  printk("              SCB-system buffer length....: %lx\n",
+			 ld(host_index)[ldn].scb.sys_buf_length);
+		  printk("              SCB-tsb address.............: %lx\n",
+			 ld(host_index)[ldn].scb.tsb_adr);
+		  printk("              SCB-Chain address...........: %lx\n",
+			 ld(host_index)[ldn].scb.scb_chain_adr);
+		  printk("              SCB-block count.............: %x\n",
+			 ld(host_index)[ldn].scb.u2.blk.count);
+		  printk("              SCB-block length............: %x\n",
+			 ld(host_index)[ldn].scb.u2.blk.length);
+	       }
+	     printk("              Send this report to the maintainer.\n");
+	     panic("IBM MCA SCSI: Fatal errormessage from the subsystem (0x%X,0x%X)!\n",
+		   lastSCSI,cmd_result);
+	     break;
+	  }  
      }
-   if (cmd_result == IM_CMD_ERROR)
-     {
-	printk("\n");
-	printk("IBM MCA SCSI: ERROR - command error!\n");
-	printk("              Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
-	       last_scsi_command(host_index)[ldn],ldn,host_index);
-	errorflag = 1;	
-     }
-   if (errorflag)
-     { /* if errors appear, enter this section to give detailed info */
-	printk("IBM MCA SCSI: Subsystem Error-Status follows:\n");
-	printk("              Command Type................: %x\n",
-	       last_scsi_type(host_index)[ldn]);
-	printk("              Attention Register..........: %x\n",
-	       inb (IM_ATTN_REG(host_index)));
-        printk("              Basic Control Register......: %x\n",
-	       inb (IM_CTR_REG(host_index)));
-	printk("              Interrupt Status Register...: %x\n",
-	       intr_reg);
-	printk("              Basic Status Register.......: %x\n",
-	       inb (IM_STAT_REG(host_index)));
-	if ((last_scsi_type(host_index)[ldn]==IM_SCB)||
-	    (last_scsi_type(host_index)[ldn]==IM_LONG_SCB))
-	  {
-	     printk("              SCB End Status Word.........: %x\n",
-		    ld(host_index)[ldn].tsb.end_status);
-	     printk("              Command Status..............: %x\n",
-		    ld(host_index)[ldn].tsb.cmd_status);
-	     printk("              Device Status...............: %x\n",
-		    ld(host_index)[ldn].tsb.dev_status);
-	     printk("              Command Error...............: %x\n",
-		    ld(host_index)[ldn].tsb.cmd_error);
-	     printk("              Device Error................: %x\n",
-		    ld(host_index)[ldn].tsb.dev_error);
-	     printk("              Last SCB Address (LSW)......: %x\n",
-		    ld(host_index)[ldn].tsb.low_of_last_scb_adr);
-	     printk("              Last SCB Address (MSW)......: %x\n",
-		    ld(host_index)[ldn].tsb.high_of_last_scb_adr);
+   else 
+     { /* The command error handling is made silent, but we tell the
+	* calling function, that there is a reported error from the
+	* adapter. */
+	switch (cmd_result)
+	  {
+	   case IM_ADAPTER_HW_FAILURE:
+	   case IM_SOFTWARE_SEQUENCING_ERROR:
+	   case IM_CMD_ERROR:
+	     global_command_error_excuse = CMD_FAIL;
+	     break;
+	   default:
+	     global_command_error_excuse = 0;
+	     break;
 	  }
-	printk("              Send report to the maintainer.\n");
-	panic("IBM MCA SCSI: Fatal errormessage from the subsystem!\n");
-     }
+     }   
    
    /* if no panic appeared, increase the interrupt-counter */
    IBM_DS(host_index).total_interrupts++;
-
+   
    /*only for local checking phase */
    if (local_checking_phase_flag(host_index))
      {
@@ -642,6 +750,13 @@
 	got_interrupt(host_index) = 1;
 	reset_status(host_index) = IM_RESET_FINISHED_OK;
 	last_scsi_command(host_index)[ldn] = NO_SCSI;
+	
+	outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&intr_lock, flags);
+#endif      
 	return;
      }   
    /*handling of commands coming from upper level of scsi driver */
@@ -668,6 +783,13 @@
 		    }
 		  stat_result(host_index) = cmd_result;
 		  last_scsi_command(host_index)[ldn] = NO_SCSI;
+		  last_scsi_type(host_index)[ldn] = 0;
+		  outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+		  restore_flags(flags);
+#else
+		  spin_unlock_irqrestore(&intr_lock, flags);
+#endif      
 		  return;
 	       }
 	     else if (last_scsi_command(host_index)[ldn] == IM_ABORT_IMM_CMD)
@@ -678,14 +800,22 @@
 		  disk_rw_in_progress = 0;
 		  PS2_DISK_LED_OFF();
 		  cmd = ld(host_index)[ldn].cmd;
+		  ld(host_index)[ldn].cmd = NULL;
 		  if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
 		    cmd->result = DID_NO_CONNECT << 16;
 		  else
 		    cmd->result = DID_ABORT << 16;
 		  stat_result(host_index) = cmd_result;
 		  last_scsi_command(host_index)[ldn] = NO_SCSI;
+		  last_scsi_type(host_index)[ldn] = 0;		  
+		  outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+		  restore_flags(flags);
+#else
+		  spin_unlock_irqrestore(&intr_lock, flags);
+#endif      		  
 		  if (cmd->scsi_done)
-		    (cmd->scsi_done) (cmd); /* should be the internal_done */
+		    (cmd->scsi_done)(cmd); /* should be the internal_done */
 		  return;
 	       }
 	     else
@@ -695,26 +825,49 @@
 		  reset_status(host_index) = IM_RESET_FINISHED_OK;
 		  stat_result(host_index) = cmd_result;
 		  last_scsi_command(host_index)[ldn] = NO_SCSI;
+		  
+		  outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+		  restore_flags(flags);
+#else
+		  spin_unlock_irqrestore(&intr_lock, flags);
+#endif      		  
 		  return;
 	       }	     
 	  }
-	last_scsi_command(host_index)[ldn] = NO_SCSI;	     
+	last_scsi_command(host_index)[ldn] = NO_SCSI;
+	last_scsi_type(host_index)[ldn] = 0;
 	cmd = ld(host_index)[ldn].cmd;
+	ld(host_index)[ldn].cmd = NULL;
 #ifdef IM_DEBUG_TIMEOUT
 	if (cmd)
 	  {
-	     if ((cmd->target == TIMEOUT_PUN)&&(cmd->lun == TIMEOUT_LUN))
+	     if ((cmd->target == TIMEOUT_PUN)&&
+		 (cmd->lun == TIMEOUT_LUN))
 	       {
 		  printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n",
 			 cmd->target, cmd->lun);
+		  outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+		  restore_flags(flags);
+#else
+		  spin_unlock_irqrestore(&intr_lock, flags);
+#endif      		  		  
 		  return;
 	       }
 	  }
 #endif
 	/*if no command structure, just return, else clear cmd */
 	if (!cmd)
-	  return;
-	ld(host_index)[ldn].cmd = NULL;
+	  {
+	     outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+	     restore_flags(flags);
+#else
+	     spin_unlock_irqrestore(&intr_lock, flags);
+#endif      		  
+	     return;
+	  }		
 	
 #ifdef IM_DEBUG_INT
 	printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", 
@@ -743,19 +896,37 @@
 	  }
 
 	/* IBM describes the status-mask to be 0x1e, but this is not conform
-	 * with SCSI-defintion, I suppose, it is a printing error in the
-	 * technical reference and assume as mask 0x3e. (ML) */
-	cmd->result = (ld(host_index)[ldn].tsb.dev_status & 0x3e);
-	/* write device status into cmd->result, and call done function */
+	 * with SCSI-defintion, I suppose, the reason for it is that IBM 
+	 * adapters do not support CMD_TERMINATED, TASK_SET_FULL and 
+	 * ACA_ACTIVE as returning statusbyte information. (ML) */
 	if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
-	  IBM_DS(host_index).total_errors++;
-	if (interror == NO_SCSI) /* unexpected interrupt :-( */
-	  cmd->result |= DID_BAD_INTR << 16;
+	  {
+	     cmd->result = (unsigned char)(ld(host_index)[ldn].tsb.dev_status & 0x1e);
+	     IBM_DS(host_index).total_errors++;
+	  }
 	else
+	  cmd->result = 0;
+	/* write device status into cmd->result, and call done function */
+	if (lastSCSI == NO_SCSI) /* unexpected interrupt :-( */
+	  cmd->result |= DID_BAD_INTR << 16;
+	else /* things went right :-) */
 	  cmd->result |= DID_OK << 16;
-	(cmd->scsi_done) (cmd);
-     }
-   if (interror == NO_SCSI)
+	outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&intr_lock, flags);
+#endif
+	/* This is for Kernel 2.2.x. Something weired happens here. 
+	 * Between the command got queued and the interrupt is released,
+	 * the flags sometimes contain different values, which must
+	 * be a strange thing. E.g. it appears when cold-booting with a
+	 * tape drive at id0. */
+	cmd->flags &= 0x3f;
+	if (cmd->scsi_done)
+	  (cmd->scsi_done)(cmd);
+     }   
+   if (lastSCSI == NO_SCSI)
      printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n");
    return;
 }
@@ -775,7 +946,7 @@
 #else
 	spin_lock_irqsave(&issue_lock, flags);
 #endif	
-	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
+	if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
 	  break;
 #ifdef OLDKERN	
 	restore_flags(flags);
@@ -791,6 +962,7 @@
 #else
    spin_unlock_irqrestore(&issue_lock, flags);
 #endif
+   return;
 }
 
 /*--------------------------------------------------------------------*/
@@ -798,6 +970,7 @@
 static void internal_done (Scsi_Cmnd * cmd)
 {
    cmd->SCp.Status++;
+   return;
 }
 
 /*--------------------------------------------------------------------*/
@@ -827,18 +1000,18 @@
      {
 	if (bypass_controller)
 	  { /* bypass the hardware integrated command set */
-	     scb->command = IM_OTHER_SCSI_CMD_CMD;      
-	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; 
+	     scb->command = IM_OTHER_SCSI_CMD_CMD | IM_NO_DISCONNECT;      
+	     scb->enable  = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
 	     scb->u1.scsi_cmd_length = cmd.cmd_len;
 	     memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len);
 	     last_scsi_command(host_index)[ldn] = INQUIRY;
-	     last_scsi_type(host_index)[ldn] = IM_SCB;
+	     last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
 	  }
 	else
 	  {
 	     /*fill scb with inquiry command */
-	     scb->command = IM_DEVICE_INQUIRY_CMD;
-	     scb->enable = IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	     scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT;
+	     scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
 	     last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD;
 	     last_scsi_type(host_index)[ldn] = IM_SCB;	     
 	  }
@@ -848,16 +1021,17 @@
 	
 	/*issue scb to passed ldn, and busy wait for interrupt */
 	got_interrupt(host_index) = 0;
-	issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+	if ((scb->command & IM_OTHER_SCSI_CMD_CMD) == IM_OTHER_SCSI_CMD_CMD)
+	  issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn);
+	else
+	  issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
 	while (!got_interrupt(host_index))
 	  barrier ();
 	
 	/*if command succesful, break */
 	if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
 	    (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
-	  {
-	     return 1;
-	  }
+	  return 1;
      }
    
    /*if all three retries failed, return "no device at this ldn" */
@@ -892,7 +1066,7 @@
 	if (bypass_controller)
 	  { /* bypass the SCSI-command */
 	     scb->command = IM_OTHER_SCSI_CMD_CMD;      
-	     scb->enable |= IM_READ_CONTROL;
+	     scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
 	     scb->u1.scsi_cmd_length = cmd.cmd_len;
 	     memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len);
 	     last_scsi_command(host_index)[ldn] = READ_CAPACITY;
@@ -901,7 +1075,7 @@
 	else
 	  {
 	     scb->command = IM_READ_CAPACITY_CMD;
-	     scb->enable = IM_READ_CONTROL;
+	     scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
 	     last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD;
 	     last_scsi_type(host_index)[ldn] = IM_SCB;	     
 	  }
@@ -911,16 +1085,17 @@
 	
 	/*issue scb to passed ldn, and busy wait for interrupt */
 	got_interrupt(host_index) = 0;
-	issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+	if ((scb->command & IM_OTHER_SCSI_CMD_CMD) == IM_OTHER_SCSI_CMD_CMD)
+	  issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn);
+	else
+	  issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
 	while (!got_interrupt(host_index))
 	  barrier ();
 	     
-	     /*if got capacity, get block length and return one device found */
+	/*if got capacity, get block length and return one device found */
 	if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
 	    (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
-	  {
-	     return 1;
-	  }
+	  return 1;
      }
    /*if all three retries failed, return "no device at this ldn" */
    if (retries >= 3)
@@ -929,6 +1104,52 @@
      return 1;
 }
 
+static int get_pos_info(int host_index)
+{
+   int retries;
+   struct im_scb *scb;
+   struct im_tsb *tsb;
+   unsigned char *buf;
+   
+   scb = &(ld(host_index)[MAX_LOG_DEV].scb);
+   tsb = &(ld(host_index)[MAX_LOG_DEV].tsb);
+   buf = (unsigned char *)(&(ld(host_index)[MAX_LOG_DEV].buf));
+   ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0;
+
+   for (retries = 0; retries < 3; retries++)
+     {
+	/*fill scb with get_pos_info command */
+	scb->command = IM_GET_POS_INFO_CMD;
+	scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER | IM_SUPRESS_EXCEPTION_SHORT;
+	last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
+	last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB;	     
+
+	scb->sys_buf_adr = virt_to_bus(buf);
+	if (special(host_index)==IBM_SCSI2_FW)
+	  scb->sys_buf_length = 256; /* get all info from F/W adapter */
+	else
+	  scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */
+	
+	scb->tsb_adr = virt_to_bus(tsb);
+	
+	/*issue scb to ldn=15, and busy wait for interrupt */
+	got_interrupt(host_index) = 0;
+	issue_cmd (host_index, virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);	
+	while (!got_interrupt(host_index))
+	  barrier ();
+	     
+	/*if got POS-stuff, get block length and return one device found */
+	if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
+	    (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+	  return 1;
+     }
+   /* if all three retries failed, return "no device at this ldn" */
+   if (retries >= 3)
+     return 0;
+   else
+     return 1;
+}
+
 /* SCSI-immediate-command for assign. This functions maps/unmaps specific
  ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
  subsystem and for dynamical remapping od ldns. */
@@ -941,26 +1162,80 @@
    
    for (retries=0; retries<3; retries ++)
      {
-        imm_command = inl(IM_CMD_REG(host_index));
-        imm_command &= (unsigned long)(0xF8000000); /* keep reserved bits */
-        imm_command |= (unsigned long)(IM_ASSIGN_IMM_CMD);
-        imm_command |= (unsigned long)((lun & 7) << 24);
-        imm_command |= (unsigned long)((operation & 1) << 23);
-        imm_command |= (unsigned long)((pun & 7) << 20);
-        imm_command |= (unsigned long)((ldn & 15) << 16);
-	
-	last_scsi_command(host_index)[0xf] = IM_ASSIGN_IMM_CMD;
-	last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
+	/* select mutation level of the SCSI-adapter */
+	switch (special(host_index))
+	  {
+	   case IBM_SCSI2_FW:
+	     imm_command = (unsigned long)(IM_ASSIGN_IMM_CMD);
+	     imm_command |= (unsigned long)((lun & 7) << 24);
+	     imm_command |= (unsigned long)((operation & 1) << 23);
+	     imm_command |= (unsigned long)((pun & 7)<< 20)|((pun & 8)<< 24);
+	     imm_command |= (unsigned long)((ldn & 15) << 16);
+	     break;
+	   default:
+	     imm_command = inl(IM_CMD_REG(host_index));
+	     imm_command &= (unsigned long)(0xF8000000); /* keep reserved bits */
+	     imm_command |= (unsigned long)(IM_ASSIGN_IMM_CMD);
+	     imm_command |= (unsigned long)((lun & 7) << 24);
+	     imm_command |= (unsigned long)((operation & 1) << 23);
+	     imm_command |= (unsigned long)((pun & 7) << 20);
+	     imm_command |= (unsigned long)((ldn & 15) << 16);
+	     break;
+	  }		
+	last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
+	last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
         got_interrupt(host_index) = 0;
-        issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | 0xf);
+        issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | MAX_LOG_DEV);
         while (!got_interrupt(host_index))
 	  barrier ();
 	
         /*if command succesful, break */
 	if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+	  return 1;
+     }
+   if (retries >= 3) 
+     return 0;
+   else
+     return 1;
+}
+
+static int immediate_feature(int host_index, unsigned int speed, 
+			     unsigned int timeout)
+{
+   int retries;
+   unsigned long imm_command;
+   
+   for (retries=0; retries<3; retries ++)
+     {
+	/* select mutation level of the SCSI-adapter */
+	switch (special(host_index))
 	  {
-	     return 1;
+	   default:
+	     imm_command  = IM_FEATURE_CTR_IMM_CMD;
+	     imm_command |= (unsigned long)((speed & 0x7) << 29);
+	     imm_command |= (unsigned long)((timeout & 0x1fff) << 16);
+	     break;
+	  }		
+	last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
+	last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
+        got_interrupt(host_index) = 0;
+	/* we need to run into command errors in order to probe for the
+	 * right speed! */
+	global_command_error_excuse = 1;
+        issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | MAX_LOG_DEV);
+        while (!got_interrupt(host_index))
+	  barrier ();
+	if (global_command_error_excuse == CMD_FAIL)
+	  {
+	     global_command_error_excuse = 0;	 
+	     return 2;
 	  }
+	else
+	  global_command_error_excuse = 0;
+	
+        /*if command succesful, break */
+	if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+	  return 1;
      }
    
    if (retries >= 3) 
@@ -1004,9 +1279,7 @@
 	  }
         /*if command succesful, break */
 	if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
-	  {
-	     return 1;
-	  }
+	  return 1;
      }
    
    if (retries >= 3) 
@@ -1052,6 +1325,97 @@
    return (char *)&answer;
 }
 
+/* transfers bitpattern of the feature command to values in MHz */
+static char *ibmrate(unsigned int speed, int adaptertype)
+{
+   int i;
+   i=adaptertype;
+   switch (speed)
+     {
+      case 0: if (i) return "5.00"; else return "10.00"; break;
+      case 1: if (i) return "4.00"; else return "8.00"; break;
+      case 2: if (i) return "3.33"; else return "6.66"; break;
+      case 3: if (i) return "2.86"; else return "5.00"; break;
+      case 4: if (i) return "2.50"; else return "4.00"; break;
+      case 5: if (i) return "2.22"; else return "3.10"; break;
+      case 6: if (i) return "2.00"; else return "2.50"; break;
+      case 7: if (i) return "1.82"; else return "2.00"; break;
+     }
+   return "---";
+}
+
+static int probe_display(int what)
+{
+   static int rotator = 0;
+   const char rotor[] = "|/-\\";
+   
+   if (!(display_mode & LED_DISP))
+     return 0;
+   if (!what)
+     {
+	outl(0x20202020,MOD95_LED_PORT);
+	outl(0x20202020,MOD95_LED_PORT+4);
+     }
+   else
+     {
+	outb('S',MOD95_LED_PORT+7);
+	outb('C',MOD95_LED_PORT+6);
+	outb('S',MOD95_LED_PORT+5);
+	outb('I',MOD95_LED_PORT+4);
+	outb('i',MOD95_LED_PORT+3);
+	outb('n',MOD95_LED_PORT+2);
+	outb('i',MOD95_LED_PORT+1);
+	outb((char)(rotor[rotator]),MOD95_LED_PORT);
+	rotator++;
+	if (rotator>3) 
+	  rotator=0;
+     }
+   return 0;  
+}
+
+static int probe_bus_mode(int host_index)
+{
+   struct im_pos_info *info;
+   int num_bus = 0;
+   int ldn;
+   
+   info = (struct im_pos_info *)(&(ld(host_index)[MAX_LOG_DEV].buf));
+   
+   if (get_pos_info(host_index))
+     {
+	if (info->connector_size & 0xf000)
+	  subsystem_connector_size(host_index)=16;
+	else
+	  subsystem_connector_size(host_index)=32;	
+	num_bus |= (info->pos_4b & 8) >> 3;
+	for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
+	  {
+	     if ((special(host_index)==IBM_SCSI_WCACHE)||
+		 (special(host_index)==IBM_7568_WCACHE))
+	       {     		  
+		  if (!((info->cache_stat >> ldn) & 1))
+		    ld(host_index)[ldn].cache_flag = 0;
+	       }
+	     if (!((info->retry_stat >> ldn) & 1))
+	       ld(host_index)[ldn].retry_flag = 0;
+	  }
+#ifdef IM_DEBUG_PROBE	
+	printk("IBM MCA SCSI: SCSI-Cache bits: ");
+	for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
+	  {
+	     printk("%d",ld(host_index)[ldn].cache_flag);
+	  }	
+	printk("\nIBM MCA SCSI: SCSI-Retry bits: ");
+	for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
+	  {
+	     printk("%d",ld(host_index)[ldn].retry_flag);
+	  }
+	printk("\n");	
+#endif		
+     }
+   return num_bus;
+}
+
 /* 
  The following routine probes the SCSI-devices in four steps:
  1. The current ldn -> pun,lun mapping is removed on the SCSI-adapter.
@@ -1072,27 +1436,31 @@
  The assignment of ALL ldns avoids dynamical remapping by the adapter
  itself.
  */
-static void check_devices (int host_index)
+static void check_devices (int host_index, int adaptertype)
 {
    int id, lun, ldn, ticks;
    int count_devices; /* local counter for connected device */
-   
+   int max_pun;
+   int num_bus;
+   int speedrun; /* local adapter_speed check variable */
+      
    /* assign default values to certain variables */
-
    ticks = 0;
    count_devices = 0;
    IBM_DS(host_index).dyn_flag = 0; /* normally no need for dynamical ldn management */
    IBM_DS(host_index).total_errors = 0; /* set errorcounter to 0 */
    next_ldn(host_index) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/
+
+   /* initialize the very important driver-informational arrays/structs */
+   memset (ld(host_index), 0, 
+	   sizeof(ld(host_index)));   
    for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
      {
 	last_scsi_command(host_index)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
 	last_scsi_type(host_index)[ldn] = 0;
+	ld(host_index)[ldn].cache_flag = 1;
+	ld(host_index)[ldn].retry_flag = 1;
      }
-
-   /* initialize the very important driver-informational arrays/structs */
-   memset (ld(host_index), 0, 
-	   sizeof(ld(host_index)));
    memset (get_ldn(host_index), TYPE_NO_DEVICE, 
 	   sizeof(get_ldn(host_index))); /* this is essential ! */
    memset (get_scsi(host_index), TYPE_NO_DEVICE,
@@ -1105,14 +1473,59 @@
 								ldn is active for all
 								luns. */
      }
+
+   probe_display(0); /* Supercool display usage during SCSI-probing. */
+                     /* This makes sense, when booting without any */
+                     /* monitor connected on model XX95. */
    
    /* STEP 1: */
+   adapter_speed(host_index) = global_adapter_speed;
+   speedrun = adapter_speed(host_index);
+   while (immediate_feature(host_index,speedrun,adapter_timeout)==2)
+     {
+	probe_display(1);
+	if (speedrun==7)
+	  panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n");
+	speedrun++;
+	if (speedrun>7) 
+	  speedrun=7;
+     }
+   adapter_speed(host_index) = speedrun;
+   /* Get detailed information about the current adapter, necessary for
+    * device operations: */
+   num_bus=probe_bus_mode(host_index);
+   
+   /* num_bus contains only valid data for the F/W adapter! */
+   if (adaptertype==IBM_SCSI2_FW) /* F/W SCSI adapter: */
+     {
+	/* F/W adapter PUN-space extension evaluation: */
+	if (num_bus)	  
+	  {	     
+	     printk("IBM MCA SCSI: Seperate bus mode (wide-addressing enabled)\n");
+	     subsystem_maxid(host_index) = 16;
+	  }	
+	else
+	  {	     
+	     printk("IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n");
+	     subsystem_maxid(host_index) = 8;
+	  }	
+	printk("IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n",
+	       ibmrate(speedrun,adaptertype));
+     }
+   else /* all other IBM SCSI adapters: */
+     printk("IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n",
+	    ibmrate(speedrun,adaptertype));
+   
+   /* assign correct PUN device space */
+   max_pun = subsystem_maxid(host_index);
+     
 #ifdef IM_DEBUG_PROBE
    printk("IBM MCA SCSI: Current SCSI-host index: %d\n",host_index);
 #endif
    printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
    for (ldn=0; ldn<MAX_LOG_DEV; ldn++)
      {
+	probe_display(1);
 #ifdef IM_DEBUG_PROBE
 	printk(".");
 #endif
@@ -1122,19 +1535,25 @@
    lun = 0; /* default lun is 0 */
    
    /* STEP 2: */
-   printk("\nIBM MCA SCSI: Probing SCSI-devices.");
-   for (id=0; id<8; id++)
+   printk("\nIBM MCA SCSI: Probing SCSI-devices");
+#ifndef IM_DEBUG_PROBE
+   printk(" (this can take up to 2 minutes)");
+#endif
+   printk(".");
+   
+   for (id=0; id<max_pun ; id++)
 #ifdef CONFIG_SCSI_MULTI_LUN
      for (lun=0; lun<8; lun++)
 #endif
      {
+	probe_display(1);
 #ifdef IM_DEBUG_PROBE
 	printk(".");
 #endif
 	if (id != subsystem_pun(host_index))
 	  {            /* if pun is not the adapter: */
 	     /*set ldn=0 to pun,lun*/
-	     immediate_assign(host_index,id,lun,PROBE_LDN,SET_LDN); 
+	     immediate_assign(host_index,id,lun,PROBE_LDN,SET_LDN);
 	     if (device_inquiry(host_index, PROBE_LDN)) /* probe device */
 	       {
 		  get_scsi(host_index)[id][lun]=
@@ -1144,7 +1563,7 @@
 		    count_devices++; /* a existing device is found */
 	       }
 	     /* remove ldn */
-	     immediate_assign(host_index,id,lun,PROBE_LDN,REMOVE_LDN); 
+	     immediate_assign(host_index,id,lun,PROBE_LDN,REMOVE_LDN);
 	  }
      }
    
@@ -1157,8 +1576,9 @@
 #ifdef CONFIG_SCSI_MULTI_LUN   
    for (lun=0; lun<8 && ldn<MAX_LOG_DEV; lun++)
 #endif
-     for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
+     for (id=0; id<max_pun && ldn<MAX_LOG_DEV; id++)
      {
+	probe_display(1);
 #ifdef IM_DEBUG_PROBE
 	printk(".");
 #endif
@@ -1208,11 +1628,12 @@
    
    /* map remaining ldns to non-existing devices */
    for (lun=1; lun<8 && ldn<MAX_LOG_DEV; lun++)
-     for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
+     for (id=0; id<max_pun && ldn<MAX_LOG_DEV; id++)
      {
 	if (get_scsi(host_index)[id][lun] == TYPE_NO_LUN ||
 	    get_scsi(host_index)[id][lun] == TYPE_NO_DEVICE)
 	  {
+	     probe_display(1);	     
 	     /* Map remaining ldns only to NON-existing pun,lun
 	      combinations to make sure an inquiry will fail. 
 	      For MULTI_LUN, it is needed to avoid adapter autonome
@@ -1234,7 +1655,7 @@
    printk("IBM MCA SCSI: Determined SCSI-device-mapping:\n");
    printk("    Physical SCSI-Device Map               Logical SCSI-Device Map\n");
    printk("ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
-   for (id=0; id<8; id++)
+   for (id=0; id<max_pun; id++)
      {
         printk("%2d     ",id);
 	for (lun=0; lun<8; lun++)
@@ -1261,6 +1682,8 @@
      printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
    
    /* reset the counters for statistics on the current adapter */
+   IBM_DS(host_index).scbs = 0;
+   IBM_DS(host_index).long_scbs = 0;
    IBM_DS(host_index).total_accesses = 0;
    IBM_DS(host_index).total_interrupts = 0;
    IBM_DS(host_index).dynamical_assignments = 0;
@@ -1276,7 +1699,7 @@
 	   sizeof (IBM_DS(host_index).ldn_modeselect_access));
    memset (IBM_DS(host_index).ldn_assignments, 0x0, 
 	   sizeof (IBM_DS(host_index).ldn_assignments));
-   
+   probe_display(0);
    return;
 }
 
@@ -1375,7 +1798,7 @@
    
 #ifdef CONFIG_SCSI_IBMMCA
 
-void ibmmca_scsi_setup (char *str, int *ints)
+void internal_ibmmca_scsi_setup (char *str, int *ints)
 {
    int i, j, io_base, id_base;
    char *token;
@@ -1389,36 +1812,30 @@
 	j = 0;
 	while (token)
 	  {
+	     if (!strcmp(token,"activity"))
+	       display_mode |= LED_ACTIVITY;
 	     if (!strcmp(token,"display"))
-	       {
-		  use_display = 1;
-	       }
+	       display_mode |= LED_DISP;
 	     if (!strcmp(token,"adisplay"))
-	       {
-		  use_adisplay = 1;
-	       }
+	       display_mode |= LED_ADISP;
 	     if (!strcmp(token,"bypass"))
-	       {
-		  bypass_controller = 1;
-	       }
+	       bypass_controller = 1;
 	     if (!strcmp(token,"normal"))
-	       {
-		  ibm_ansi_order = 0;
-	       }
+	       ibm_ansi_order = 0;
 	     if (!strcmp(token,"ansi"))
-	       {
-		  ibm_ansi_order = 1;
-	       }
+	       ibm_ansi_order = 1;
+	     if (!strcmp(token,"fast"))
+	       global_adapter_speed = 0;
+	     if (!strcmp(token,"medium"))
+	       global_adapter_speed = 4;
+	     if (!strcmp(token,"slow"))
+	       global_adapter_speed = 7;	     
 	     if ( (*token == '-') || (isdigit(*token)) )
 	       {
 		  if (!(j%2) && (io_base < IM_MAX_HOSTS))
-		    {
-		       io_port[io_base++] = simple_strtoul(token,NULL,0);
-		    }
+		    io_port[io_base++] = simple_strtoul(token,NULL,0);
 		  if ((j%2) && (id_base < IM_MAX_HOSTS))
-		    {
-		       scsi_id[id_base++] = simple_strtoul(token,NULL,0);
-		    }
+		    scsi_id[id_base++] = simple_strtoul(token,NULL,0);
 		  j++;
 	       }
 	     token = strtok(NULL,",");
@@ -1442,7 +1859,7 @@
 static int ibmmca_getinfo (char *buf, int slot, void *dev)
 {
    struct Scsi_Host *shpnt;
-   int len, special;
+   int len, speciale,connectore;
    unsigned int pos2, pos3;
    static unsigned long flags;
      
@@ -1456,21 +1873,22 @@
    shpnt = dev; /* assign host-structure to local pointer */
    len = 0; /* set filled text-buffer index to 0 */
    /* get the _special contents of the hostdata structure */
-   special = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special;
+   speciale = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special;
+   connectore = ((struct ibmmca_hostdata *)shpnt->hostdata)->_connector_size;
    pos2 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2;
    pos3 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3;
    
-   if (special == FORCED_DETECTION) /* forced detection */
+   if (speciale == FORCED_DETECTION) /* forced detection */
      {
-	len += sprintf (buf + len, "Adapter cathegory: forced detected\n");
+	len += sprintf (buf + len, "Adapter category: forced detected\n");
 	len += sprintf(buf + len, "***************************************\n");
 	len += sprintf(buf + len, "***  Forced detected SCSI Adapter   ***\n");
 	len += sprintf(buf + len, "***  No chip-information available  ***\n");
 	len += sprintf(buf + len, "***************************************\n");
      }
-   else if (special == INTEGRATED_SCSI)
+   else if (speciale == INTEGRATED_SCSI)
      { /* if the integrated subsystem has been found automatically: */
-	len += sprintf (buf + len, "Adapter cathegory: integrated\n");
+	len += sprintf (buf + len, "Adapter category: integrated\n");
 	len += sprintf (buf + len, "Chip revision level: %d\n",
 			((pos2 & 0xf0) >> 4));
 	len += sprintf (buf + len, "Chip status: %s\n",
@@ -1478,27 +1896,32 @@
 	len += sprintf (buf + len, "8 kByte NVRAM status: %s\n",
 			(pos2 & 2) ? "locked" : "accessible");
      }
-   else if ((special>=0)&&
-	   (special<(sizeof(subsys_list)/sizeof(struct subsys_list_struct))))
-     { /* if the subsystem is a slot adapter */
-	len += sprintf (buf + len, "Adapter cathegory: slot-card\n");
-	len += sprintf (buf + len, "Chip revision level: %d\n",
-			((pos2 & 0xf0) >> 4));
+   else if ((speciale>=0)&&
+	   (speciale<(sizeof(subsys_list)/sizeof(struct subsys_list_struct))))
+     { /* if the subsystem is a slot adapter */	
+	len += sprintf (buf + len, "Adapter category: slot-card\n");
+	len += sprintf (buf + len, "ROM Segment Address: ");
+	if ((pos2 & 0xf0) == 0xf0)
+	  len += sprintf (buf + len, "off\n");
+	else
+	  len += sprintf (buf + len, "0x%x\n",
+			((pos2 & 0xf0) << 13) + 0xc0000);
 	len += sprintf (buf + len, "Chip status: %s\n",
 			(pos2 & 1) ? "enabled" : "disabled");
-	len += sprintf (buf + len, "Port offset: 0x%x\n",
+	len += sprintf (buf + len, "Adapter I/O Offset: 0x%x\n",
 			((pos2 & 0x0e) << 2));
      }
    else
      {
-	len += sprintf (buf + len, "Adapter cathegory: unknown\n");
+	len += sprintf (buf + len, "Adapter category: unknown\n");
      }
    /* common subsystem information to write to the slotn file */
    len += sprintf (buf + len, "Subsystem PUN: %d\n", shpnt->this_id);
-   len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x",
+   len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x\n",
 		   (unsigned int)(shpnt->io_port), 
 		   (unsigned int)(shpnt->io_port+7));
-   /* Now make sure, the bufferlength is devideable by 4 to avoid
+   len += sprintf (buf + len, "MCA-slot size: %d bits",connectore);
+   /* Now make sure, the bufferlength is devidable by 4 to avoid
     * paging problems of the buffer. */
    while ( len % sizeof( int ) != ( sizeof ( int ) - 1 ) )
      {
@@ -1518,17 +1941,31 @@
 {
    struct Scsi_Host *shpnt;
    int port, id, i, j, list_size, slot;
+   int devices_on_irq_11 = 0;
+   int devices_on_irq_14 = 0;
+   int IRQ14_registered = 0;
+   int IRQ11_registered = 0;
    
    found = 0; /* make absolutely sure, that found is set to 0 */
-   
+
+   /* First of all, print the version number of the driver. This is 
+    * important to allow better user bugreports in case of already
+    * having problems with the MCA_bus probing. */
+   printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION);
    /* if this is not MCA machine, return "nothing found" */
    if (!MCA_bus)
      {
-	printk("IBM MCA SCSI: No Microchannel-bus support present -> Aborting.\n");
+	printk("IBM MCA SCSI: No Microchannel-bus present --> Aborting.\n");
+	printk("              This machine does not have any IBM MCA-bus\n");
+	printk("              or the MCA-Kernel-support is not enabled!\n");
 	return 0;
      }
-   else
-     printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION);
+
+#ifdef MODULE
+   /* If the driver is run as module, read from conf.modules or cmd-line */
+   if (boot_options) 
+     option_setup(boot_options);
+#endif   
    
    /* get interrupt request level */
 #ifdef OLDKERN
@@ -1542,7 +1979,9 @@
 	printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
 	return 0;
      }
-   
+   else
+     IRQ14_registered++;
+         
    /* if ibmmcascsi setup option was passed to kernel, return "found" */
    for (i = 0; i < IM_MAX_HOSTS; i++)
      if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8)
@@ -1550,16 +1989,21 @@
 	printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n",
 	       io_port[i], scsi_id[i]);
 	if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i],
+		     FORCED_DETECTION,
 		     "forced detected SCSI Adapter")))
 	  {
 	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = 0;
 	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = 0;
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = 0;
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = 0;
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = 0;	     
 	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = 
 	       FORCED_DETECTION;
 	     mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter");
 	     mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
 				    shpnt);
 	     mca_mark_as_used(MCA_INTEGSCSI);
+	     devices_on_irq_14++;
 	  }	
      }
    if (found) return found;
@@ -1592,12 +2036,14 @@
    for (j=0;j<8;j++) /* read the pos-information */
      pos[j] = mca_read_stored_pos(MCA_INTEGSCSI,j);
    /* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present  */
-   if (( pos[2] != 0xff) || (pos[3] != 0xff ))
+   /* if (( pos[2] != 0xff) || (pos[3] != 0xff )) */
+   /* Previous if-arguments do fail! Therefore, we use now the following to
+    * make sure, we see a real integrated onboard SCSI-interface: */
+   if ((!pos[0] && !pos[1] && pos[2]>0 && pos[3]>0 && !pos[4] && !pos[5] && !pos[6] && !pos[7]) ||
+       (pos[0]==0xff && pos[1]==0xff && pos[2]<0xff && pos[3]<0xff && pos[4]==0xff && pos[5]==0xff && pos[6]==0xff && pos[7]==0xff))
      {
 	if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
-	  {
-	     port = IM_IO_PORT;
-	  } 
+	  port = IM_IO_PORT;
 	else 
 	  { /* if disabled, no IRQs will be generated, as the chip won't
 	     * listen to the incomming commands and will do really nothing,
@@ -1622,16 +2068,21 @@
 
 	/* register the found integrated SCSI-subsystem */
 	if ((shpnt = ibmmca_register(scsi_template, port, id,
+		     INTEGRATED_SCSI,
 		     "IBM Integrated SCSI Controller")))
 	  {
 	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
 	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = pos[4];
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = pos[5];
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = pos[6];
 	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = 
 	       INTEGRATED_SCSI;
 	     mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller");
 	     mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
 				    shpnt);
 	     mca_mark_as_used(MCA_INTEGSCSI);
+	     devices_on_irq_14++;
 	  }
      }
    
@@ -1657,42 +2108,177 @@
 		  printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
 		  printk("              SCSI-operations may not work.\n");
 	       }      	     
-	     id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
+	     if ((i==IBM_SCSI2_FW)&&(pos[6]!=0))	       
+	       {
+		  printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+		  printk("              Impossible to determine adapter PUN!\n");
+		  printk("              Guessing adapter PUN = 7.\n");
+		  id = 7;
+	       }
+	     else
+	       {		  
+		  id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
+		  if (i==IBM_SCSI2_FW)
+		    {		       
+		       id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
+						    * for F/W adapters */
+		    }		  
+	       }	     
+	     if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
+	       {  /* IRQ11 is used by SCSI-2 F/W Adapter/A */
+		  printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+		  /* get interrupt request level */
+#ifdef OLDKERN
+		  if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ, 
+				   "ibmmcascsi", hosts))
+#else
+		  if (request_irq (IM_IRQ_FW, do_interrupt_handler, SA_SHIRQ,
+				   "ibmmcascsi", hosts))
+#endif
+		    {
+		       printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n",
+			      IM_IRQ_FW);
+		    }
+		  else
+		    IRQ11_registered++;		  
+	       }
 	     printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n",
 		     subsys_list[i].description, slot + 1, port, id);
-	     printk("              chip rev.=%d, port-offset=0x%x, subsystem=%s\n",
-		    ((pos[2] & 0xf0) >> 4), 
+	     if ((pos[2] & 0xf0) == 0xf0)
+	       printk("              ROM Addr.=off,");
+	     else
+	       printk("              ROM Addr.=0x%x,",
+		      ((pos[2] & 0xf0) << 13) + 0xc0000);
+	     printk(" port-offset=0x%x, subsystem=%s\n",
 		    ((pos[2] & 0x0e) << 2),
 		    (pos[2] & 1) ? "enabled." : "disabled.");
 	     
 	     /* register the hostadapter */
-	     if ((shpnt = ibmmca_register(scsi_template, port, id,
+	     if ((shpnt = ibmmca_register(scsi_template, port, id, i,
 		          subsys_list[i].description)))
 	       {
 		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
 		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = pos[4];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = pos[5];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = pos[6];
 		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i;
 
 		  mca_set_adapter_name (slot, subsys_list[i].description);
 		  mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo,
 					  shpnt);
 		  mca_mark_as_used(slot);
+		  if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
+		    devices_on_irq_11++;
+		  else
+		    devices_on_irq_14++;
 	       }
 	     slot++; /* advance to next slot */
 	  } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/
      }
+
    
-   if (!found) 
-     { /* maybe ESDI, or other producers' SCSI-hosts */
-	free_irq (IM_IRQ, hosts);
-	printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
-     }  
+   /* now look for SCSI-adapters, by bugs mapped to the integrated SCSI
+    * area. E.g. a W/Cache in MCA-slot 9 ???? Arrrrgh!! */
+   list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
+   for (i = 0; i < list_size; i++)
+     { /* scan each slot for a fitting adapter id */
+	slot = mca_find_adapter(subsys_list[i].mca_id, MCA_INTEGSCSI);
+	if (slot != MCA_NOTFOUND)
+	  { /* scan through all slots */
+	     for (j=0;j<8;j++) /* read the pos-information */
+	       pos[j] = mca_read_stored_pos(slot, j);
+	     if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
+	       { /* (explanations see above) */
+		  port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+	       } 
+	     else 
+	       { /* anyway, set the portnumber and warn */
+		  port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); 
+		  printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+		  printk("              SCSI-operations may not work.\n");
+	       }
+	     if ((i==IBM_SCSI2_FW)&&(pos[6]!=0))	       
+	       {
+		  printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+		  printk("              Impossible to determine adapter PUN!\n");
+		  printk("              Guessing adapter PUN = 7.\n");
+		  id = 7;
+	       }
+	     else
+	       {		  
+		  id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
+		  if (i==IBM_SCSI2_FW)
+		    {		       
+		       id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
+						    * for F/W adapters */
+		    }		  
+	       }	     
+	     if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
+	       {  /* IRQ11 is used by SCSI-2 F/W Adapter/A */
+		  printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+		  /* get interrupt request level */
+#ifdef OLDKERN
+		  if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ, 
+				   "ibmmcascsi", hosts))
+#else
+		  if (request_irq (IM_IRQ_FW, do_interrupt_handler, SA_SHIRQ,
+				   "ibmmcascsi", hosts))
+#endif
+		    {
+		       printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n",
+			      IM_IRQ_FW);
+		    }
+		  else
+		    IRQ11_registered++;		  
+	       }
+	     printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n",
+		     subsys_list[i].description, slot + 1, port, id);
+	     if ((pos[2] & 0xf0) == 0xf0)
+	       printk("              ROM Addr.=off,");
+	     else
+	       printk("              ROM Addr.=0x%x,",
+		      ((pos[2] & 0xf0) << 13) + 0xc0000);
+	     printk(" port-offset=0x%x, subsystem=%s\n",
+		    ((pos[2] & 0x0e) << 2),
+		    (pos[2] & 1) ? "enabled." : "disabled.");
+	     
+	     /* register the hostadapter */
+	     if ((shpnt = ibmmca_register(scsi_template, port, id, i,
+		          subsys_list[i].description)))
+	       {
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = pos[4];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = pos[5];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = pos[6];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i;
+
+		  mca_set_adapter_name (slot, subsys_list[i].description);
+		  mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo,
+					  shpnt);
+		  mca_mark_as_used(slot);
+		  if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
+		    devices_on_irq_11++;
+		  else
+		    devices_on_irq_14++;
+	       }
+	     slot++; /* advance to next slot */
+	  } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/
+     }
+   
+   if ( IRQ11_registered && !devices_on_irq_11 )
+     free_irq(IM_IRQ_FW, hosts); /* no devices on IRQ 11 */
+   if ( IRQ14_registered && !devices_on_irq_14 )
+     free_irq(IM_IRQ, hosts); /* no devices on IRQ 14 */
+   if ( !devices_on_irq_11 && !devices_on_irq_14 )
+     printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
    return found; /* return the number of found SCSI hosts. Should be 1 or 0. */
 }
 
 static struct Scsi_Host *
-ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id,
-		char *hostname)
+ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id, 
+		int adaptertype, char *hostname)
 {
    struct Scsi_Host *shpnt;
    int i, j;
@@ -1716,15 +2302,18 @@
    
    /* request I/O region */
    request_region(port, IM_N_IO_PORT, hostname);
-
+      
    hosts[found] = shpnt; /* add new found hostadapter to the list */
+   special(found) = adaptertype; /* important assignment or else crash! */
+   subsystem_connector_size(found) = 0; /* preset slot-size */
    shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */
    shpnt->io_port = port;
    shpnt->n_io_port = IM_N_IO_PORT;
    shpnt->this_id = id;
+   shpnt->max_id = 8; /* 8 PUNs are default */
    /* now, the SCSI-subsystem is connected to Linux */
-
-   ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */
+   
+   ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */   
 #ifdef IM_DEBUG_PROBE
    printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n",
 	  ctrl,inb(IM_STAT_REG(found)));
@@ -1738,13 +2327,14 @@
    
    reset_status(found) = IM_RESET_NOT_IN_PROGRESS;
 
-   for (i = 0; i < 8; i++) /* reset the tables */
+   for (i = 0; i < 16; i++) /* reset the tables */
      for (j = 0; j < 8; j++)
      get_ldn(found)[i][j] = MAX_LOG_DEV;
 
    /* check which logical devices exist */
-   local_checking_phase_flag(found) = 1;
-   check_devices(found); /* call by value, using the global variable hosts*/
+   /* after this line, local interrupting is possible: */
+   local_checking_phase_flag(found) = 1;   
+   check_devices(found,adaptertype); /* call by value, using the global variable hosts*/
    local_checking_phase_flag(found) = 0;
    
    found++; /* now increase index to be prepared for next found subsystem */
@@ -1802,30 +2392,43 @@
    int id,lun;
    int target;
    int host_index;
-   
-   if (ibm_ansi_order)
-     target = 6 - cmd->target;
-   else
-     target = cmd->target;
+   int max_pun;
+   int i;
+   struct scatterlist *sl;
    
    shpnt = cmd->host;
-   
+
    /* search for the right hostadapter */
    for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
    
    if (!hosts[host_index])
      { /* invalid hostadapter descriptor address */
 	cmd->result = DID_NO_CONNECT << 16;
-	done (cmd);
+	if (done)
+	  done (cmd);
 	return 0;
      }
    
+   max_pun = subsystem_maxid(host_index);
+   
+   if (ibm_ansi_order)
+     {	
+	target = max_pun - 1 - cmd->target;
+	if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index)))
+	  target--;
+	else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index)))
+	  target++;
+     }   	
+   else
+     target = cmd->target;
+   
    /*if (target,lun) is NO LUN or not existing at all, return error */
    if ((get_scsi(host_index)[target][cmd->lun] == TYPE_NO_LUN)||
        (get_scsi(host_index)[target][cmd->lun] == TYPE_NO_DEVICE))
      {
 	cmd->result = DID_NO_CONNECT << 16;
-	done (cmd);
+	if (done)
+	  done (cmd);
 	return 0;
      }
    
@@ -1848,13 +2451,14 @@
 		       printk("              Reporting DID_NO_CONNECT for device (%d,%d).\n",
 			      target, cmd->lun);
 		       cmd->result = DID_NO_CONNECT << 16;/* return no connect*/
-		       done (cmd);
+		       if (done)
+			 done (cmd);
 		       return 0;
 		    }
 	       }
 	     
 	     /* unmap non-processing ldn */
-	     for (id=0; id<8; id ++)
+	     for (id=0; id<max_pun; id ++)
 	       for (lun=0; lun<8; lun++)
 	       {
 		  if (get_ldn(host_index)[id][lun] == next_ldn(host_index))
@@ -1907,7 +2511,8 @@
 	else
 	  {  /* wall against Linux accesses to the subsystem adapter */	 
 	     cmd->result = DID_BAD_TARGET << 16;
-	     done (cmd);
+	     if (done)
+	       done (cmd);
 	     return 0;
 	  }
      }
@@ -1923,17 +2528,19 @@
    /*fill scb information independent of the scsi command */
    scb = &(ld(host_index)[ldn].scb);
    ld(host_index)[ldn].tsb.dev_status = 0;
-   scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR;
+   scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE;
    scb->tsb_adr = virt_to_bus(&(ld(host_index)[ldn].tsb));
+   scsi_cmd = cmd->cmnd[0];
+   
    if (cmd->use_sg)
      {
-	int i = cmd->use_sg;
-	struct scatterlist *sl = (struct scatterlist *) cmd->request_buffer;
+	i = cmd->use_sg;
+	sl = (struct scatterlist *)(cmd->request_buffer);
 	if (i > 16)
 	  panic ("IBM MCA SCSI: scatter-gather list too long.\n");
 	while (--i >= 0)
 	  {
-	     ld(host_index)[ldn].sge[i].address = (void *) virt_to_bus(sl[i].address);
+	     ld(host_index)[ldn].sge[i].address = (void *)(virt_to_bus(sl[i].address));
 	     ld(host_index)[ldn].sge[i].byte_length = sl[i].length;
 	  }
 	scb->enable |= IM_POINTER_TO_LIST;
@@ -1943,11 +2550,26 @@
    else
      {
 	scb->sys_buf_adr = virt_to_bus(cmd->request_buffer);
-	scb->sys_buf_length = cmd->request_bufflen;
+	/* recent Linux midlevel SCSI places 1024 byte for inquiry
+	 * command. Far too much for old PS/2 hardware. */	
+	switch (scsi_cmd)
+	  { /* avoid command errors by setting bufferlengths to
+	     * ANSI-standard. */
+	   case INQUIRY:
+	   case REQUEST_SENSE:
+	   case MODE_SENSE:
+	   case MODE_SELECT:
+	     scb->sys_buf_length = 255;
+	     break;
+	   case TEST_UNIT_READY:
+	     scb->sys_buf_length = 0;
+	     break;
+	   default:
+	     scb->sys_buf_length = cmd->request_bufflen;
+	     break;
+	  }
      }
-   
    /*fill scb information dependent on scsi command */
-   scsi_cmd = cmd->cmnd[0];
    
 #ifdef IM_DEBUG_CMD
    printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
@@ -1962,8 +2584,7 @@
    
    /* for possible panics store current command */
    last_scsi_command(host_index)[ldn] = scsi_cmd; 
-   last_scsi_type(host_index)[ldn] = IM_SCB;
-   
+   last_scsi_type(host_index)[ldn] = IM_SCB;   
    /* update statistical info */
    IBM_DS(host_index).total_accesses++;
    IBM_DS(host_index).ldn_access[ldn]++;
@@ -1976,16 +2597,9 @@
       case WRITE_10:
       case READ_12:
       case WRITE_12:       
-	/* statistics for proc_info */
-	if ((scsi_cmd == READ_6)||(scsi_cmd == READ_10)||(scsi_cmd == READ_12))
-	  IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
-	else if ((scsi_cmd == WRITE_6)||(scsi_cmd == WRITE_10)||
-		 (scsi_cmd == WRITE_12))
-	  IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/
-	
 	/* Distinguish between disk and other devices. Only disks (that are the
 	   most frequently accessed devices) should be supported by the 
-         IBM-SCSI-Subsystem commands. */
+           IBM-SCSI-Subsystem commands. */
 	switch (ld(host_index)[ldn].device_type)
 	  {
 	   case TYPE_DISK: /* for harddisks enter here ... */
@@ -1994,31 +2608,32 @@
 	     if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
 		 scsi_cmd == READ_12)
 	       { /* read command preparations */
+		  scb->enable |= IM_READ_CONTROL;
+		  IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
 		  if (bypass_controller)
 		    {
 		       scb->command = IM_OTHER_SCSI_CMD_CMD;
-		       scb->enable |= IM_READ_CONTROL;
+		       scb->enable |= IM_BYPASS_BUFFER;
 		       scb->u1.scsi_cmd_length = cmd->cmd_len;
 		       memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len);
+		       last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
 		    }
 		  else
-		    {
-		       scb->command = IM_READ_DATA_CMD;
-		       scb->enable |= IM_READ_CONTROL;
-		    }
+		    scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT;
 	       }
 	     else
 	       { /* write command preparations */
+		  IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/
 		  if (bypass_controller)
 		    {
 		       scb->command = IM_OTHER_SCSI_CMD_CMD;
+		       scb->enable |= IM_BYPASS_BUFFER;
 		       scb->u1.scsi_cmd_length = cmd->cmd_len;
 		       memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len);
+		       last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
 		    }
 		  else
-		    { 
-		       scb->command = IM_WRITE_DATA_CMD;
-		    }
+		    scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT;
 	       }
 	     
 	     if (!bypass_controller)
@@ -2039,6 +2654,8 @@
 		       scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) |
 			 (((unsigned) cmd->cmnd[7]) << 8);
 		    }
+		  last_scsi_logical_block(host_index)[ldn] = scb->u1.log_blk_adr;
+		  last_scsi_blockcount(host_index)[ldn] = scb->u2.blk.count;
 		  scb->u2.blk.length = ld(host_index)[ldn].block_length;
 	       }	    
 	     if (++disk_rw_in_progress == 1)
@@ -2052,8 +2669,7 @@
 	   case TYPE_PROCESSOR:
 	   case TYPE_WORM:
 	   case TYPE_SCANNER:
-	   case TYPE_MEDIUM_CHANGER:
-	     
+	   case TYPE_MEDIUM_CHANGER:	     
 	     /* If there is a sequential-device, IBM recommends to use
 	      IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE. 
 	      Good/modern CD-ROM-drives are capable of
@@ -2068,15 +2684,14 @@
 	     scb->command = IM_OTHER_SCSI_CMD_CMD;
 	     if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
 		 scsi_cmd == READ_12) /* enable READ */
-	       {
-		  scb->enable |= IM_READ_CONTROL;
-	       }
-	     
+	       scb->enable |= IM_READ_CONTROL;
+	     scb->enable |= IM_BYPASS_BUFFER;
 	     scb->u1.scsi_cmd_length = cmd->cmd_len;
 	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	     last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
 	     
 	     /* Read/write on this non-disk devices is also displayworthy, 
-	      so flash-up the LED/display. */
+	        so flash-up the LED/display. */
 	     if (++disk_rw_in_progress == 1)
 	       PS2_DISK_LED_ON (shpnt->host_no, target);
 	     break;
@@ -2087,17 +2702,27 @@
 	if (bypass_controller)
 	  {
 	     scb->command = IM_OTHER_SCSI_CMD_CMD;
-	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+	     scb->u1.log_blk_adr = 0;
 	     scb->u1.scsi_cmd_length = cmd->cmd_len;
 	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	     last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
 	  }
 	else
 	  {
 	     scb->command = IM_DEVICE_INQUIRY_CMD;
 	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	     scb->u1.log_blk_adr = 0;
 	  }
-	break;	
-
+	break;
+      case TEST_UNIT_READY:
+	scb->command = IM_OTHER_SCSI_CMD_CMD;
+	scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+	scb->u1.log_blk_adr = 0;
+	scb->u1.scsi_cmd_length = 6;
+	memcpy (scb->u2.scsi_command, cmd->cmnd, 6);
+	last_scsi_type(host_index)[ldn] = IM_LONG_SCB;	
+	break;
       case READ_CAPACITY:
 	/* the length of system memory buffer must be exactly 8 bytes */
 	if (scb->sys_buf_length > 8)
@@ -2105,55 +2730,67 @@
 	if (bypass_controller)
 	  {
 	     scb->command = IM_OTHER_SCSI_CMD_CMD;
-	     scb->enable |= IM_READ_CONTROL;
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
 	     scb->u1.scsi_cmd_length = cmd->cmd_len;
-	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);	     
+	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	     last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
 	  }
 	else
 	  {
 	     scb->command = IM_READ_CAPACITY_CMD;
-	     scb->enable |= IM_READ_CONTROL;
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
 	  }
 	break;
 	
-	/* Commands that need read-only-mode (system <- device): */
+      /* Commands that need read-only-mode (system <- device): */
       case REQUEST_SENSE:
-	if (bypass_controller)
+        if (bypass_controller)
 	  {
 	     scb->command = IM_OTHER_SCSI_CMD_CMD;
-	     scb->enable |= IM_READ_CONTROL;
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
 	     scb->u1.scsi_cmd_length = cmd->cmd_len;
 	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	     last_scsi_type(host_index)[ldn] = IM_LONG_SCB;	     
 	  }
 	else
 	  {
 	     scb->command = IM_REQUEST_SENSE_CMD;
-	     scb->enable |= IM_READ_CONTROL;
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
 	  }
 	break;
 	
-	/* Commands that need write-only-mode (system -> device): */
+      /* Commands that need write-only-mode (system -> device): */
       case MODE_SELECT:
       case MODE_SELECT_10:
 	IBM_DS(host_index).ldn_modeselect_access[ldn]++;
 	scb->command = IM_OTHER_SCSI_CMD_CMD;      
-	scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /*Select needs WRITE-enabled*/
+	scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; /*Select needs WRITE-enabled*/
 	scb->u1.scsi_cmd_length = cmd->cmd_len;
 	memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	last_scsi_type(host_index)[ldn] = IM_LONG_SCB;	
 	break;
 	
 	/* For other commands, read-only is useful. Most other commands are 
 	 running without an input-data-block. */
       default:
 	scb->command = IM_OTHER_SCSI_CMD_CMD;
-	scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
 	scb->u1.scsi_cmd_length = cmd->cmd_len;
 	memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	last_scsi_type(host_index)[ldn] = IM_LONG_SCB;	
 	break;
      }
-   
    /*issue scb command, and return */
-   issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+   if (last_scsi_type(host_index)[ldn] == IM_LONG_SCB)
+     {	
+	issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn);
+	IBM_DS(host_index).long_scbs++;
+     }   
+   else
+     {
+	issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+	IBM_DS(host_index).scbs++;
+     }
    return 0;
 }
 
@@ -2170,6 +2807,7 @@
    void (*saved_done) (Scsi_Cmnd *);
    int target;
    int host_index;
+   int max_pun;
    static unsigned long flags;
    unsigned long imm_command;
 
@@ -2180,12 +2818,7 @@
    cli();   
 #else
    spin_lock_irqsave(&abort_lock, flags);
-#endif         
-   if (ibm_ansi_order)
-     target = 6 - cmd->target;
-   else
-     target = cmd->target;
-   
+#endif            
    shpnt = cmd->host;
 
    /* search for the right hostadapter */
@@ -2195,9 +2828,22 @@
      { /* invalid hostadapter descriptor address */
 	cmd->result = DID_NO_CONNECT << 16;
 	if (cmd->scsi_done)
-	  (cmd->done) (cmd);
+	  (cmd->scsi_done) (cmd);
 	return SCSI_ABORT_SNOOZE;
      }
+   
+   max_pun = subsystem_maxid(host_index);
+       
+   if (ibm_ansi_order)
+     {
+	target = max_pun - 1 - cmd->target;
+	if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index)))
+	  target--;
+	else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index)))
+	  target++;		
+     }   
+   else
+     target = cmd->target;
  
    /*get logical device number, and disable system interrupts */
    printk ("IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n",
@@ -2294,7 +2940,12 @@
    int host_index;
    static unsigned long flags;
    unsigned long imm_command;
-   
+
+   if (cmd == NULL)
+     {
+	printk("IBM MCA SCSI: Reset called with NULL-command!\n");
+	return(SCSI_RESET_SNOOZE);
+     }      
 #ifdef OLDKERN   
    save_flags(flags);
    cli();   
@@ -2310,9 +2961,19 @@
      { /* invalid hostadapter descriptor address */
 	if (!local_checking_phase_flag(host_index))
 	  {
-	     cmd->result = DID_NO_CONNECT << 16;
-	     if (cmd->scsi_done)
-	       (cmd->done) (cmd);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
+	     if (flags & SCSI_RESET_SYNCHRONOUS)
+	       {
+#ifdef OLDKERN	
+		  restore_flags(flags);
+#else
+		  spin_unlock_irqrestore(&reset_lock, flags);
+#endif				  
+		  cmd->result = DID_NO_CONNECT << 16;	     
+		  if (cmd->scsi_done)
+		    (cmd->scsi_done) (cmd);
+	       }	     
+#endif	     
 	  }
 	return SCSI_ABORT_SNOOZE;
      }
@@ -2399,7 +3060,7 @@
    }
    
    /* so reset finished ok - call outstanding done's, and return success */
-   printk ("IBM MCA SCSI: Reset completed without known error.\n");
+   printk ("IBM MCA SCSI: Reset successfully completed.\n");
 #ifdef OLDKERN   
    restore_flags(flags);
 #else
@@ -2412,10 +3073,22 @@
 	  {
 	     ld(host_index)[i].cmd = NULL;
 	     cmd_aid->result = DID_RESET << 16;
-	     (cmd_aid->scsi_done) (cmd_aid);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
+	     if (flags & SCSI_RESET_SYNCHRONOUS)
+	       {
+		  cmd_aid->result = DID_BUS_BUSY << 16;
+		  if (cmd_aid->scsi_done)
+		    (cmd_aid->scsi_done) (cmd_aid);
+	       }	     
+#endif	     
 	  }
      }
-   return SCSI_RESET_SUCCESS;
+   if (flags & SCSI_RESET_SUGGEST_HOST_RESET)
+     return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
+   else if (flags & SCSI_RESET_SUGGEST_BUS_RESET)
+     return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
+   else
+     return SCSI_RESET_SUCCESS;
 }
 
 /*--------------------------------------------------------------------*/
@@ -2492,7 +3165,8 @@
    int i,id,lun,host_index;
    struct Scsi_Host *shpnt;
    unsigned long flags;
-
+   int max_pun;
+   
 #ifdef OLDKERN   
    save_flags(flags);
    cli();
@@ -2504,10 +3178,11 @@
    shpnt = hosts[i];
    host_index = i;
    if (!shpnt) {
-       len += sprintf(buffer+len, "\nCan't find adapter for host number %d\n", hostno);
+       len += sprintf(buffer+len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n", hostno);
        return len;
    }
-
+   max_pun = subsystem_maxid(host_index);
+   
    len += sprintf(buffer+len, "\n             IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n",
 		  IBMMCA_SCSI_DRIVER_VERSION);
    len += sprintf(buffer+len, " SCSI Access-Statistics:\n");
@@ -2528,8 +3203,12 @@
 		  (bypass_controller) ? "software" : "hardware integrated");
    len += sprintf(buffer+len, "               Total Interrupts.........: %d\n",
 		  IBM_DS(host_index).total_interrupts);
-   len += sprintf(buffer+len, "               Total SCSI Accesses......: %d\n",
+   len += sprintf(buffer+len, "               Total SCSI Accesses......: %d\n",		  
 		  IBM_DS(host_index).total_accesses);
+   len += sprintf(buffer+len, "               Total short SCBs.........: %d\n",
+		  IBM_DS(host_index).scbs);
+   len += sprintf(buffer+len, "               Total long SCBs..........: %d\n",
+		  IBM_DS(host_index).long_scbs);   
    len += sprintf(buffer+len, "                 Total SCSI READ/WRITE..: %d\n",
 		  ldn_access_total_read_write(host_index));
    len += sprintf(buffer+len, "                 Total SCSI Inquiries...: %d\n",
@@ -2554,7 +3233,7 @@
    len += sprintf(buffer+len, " Dynamical-LDN-Assignment-Statistics:\n");
    len += sprintf(buffer+len, "               Number of physical SCSI-devices..: %d (+ Adapter)\n",
 		  IBM_DS(host_index).total_scsi_devices);
-   len += sprintf(buffer+len, "               Dynamical Assignment necessaray..: %s\n", 
+   len += sprintf(buffer+len, "               Dynamical Assignment necessary...: %s\n", 
 		  IBM_DS(host_index).dyn_flag ? "Yes" : "No ");
    len += sprintf(buffer+len, "               Next LDN to be assigned..........: 0x%x\n",
 		  next_ldn(host_index));
@@ -2564,7 +3243,7 @@
    len += sprintf(buffer+len, "\n Current SCSI-Device-Mapping:\n");
    len += sprintf(buffer+len, "        Physical SCSI-Device Map               Logical SCSI-Device Map\n");
    len += sprintf(buffer+len, "    ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
-   for (id=0; id<=7; id++)
+   for (id=0; id<max_pun; id++)
      {
 	len += sprintf(buffer+len, "    %2d     ",id);
 	for (lun=0; lun<8; lun++)
@@ -2590,6 +3269,30 @@
 #endif   
    return len;
 }
+
+void ibmmca_scsi_setup (char *str, int *ints)
+{
+   internal_ibmmca_scsi_setup (str, ints);
+}
+
+static int option_setup(char *str)
+{
+   int ints[IM_MAX_HOSTS];
+   char *cur = str;
+   int i = 1;
+   
+   while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) {
+      ints[i++] = simple_strtoul(cur, NULL, 0);
+      if ((cur = strchr(cur,',')) != NULL) cur++;
+   }   
+   ints[0] = i - 1;
+   internal_ibmmca_scsi_setup(cur, ints);
+   return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18)
+__setup("ibmmcascsi=", option_setup);
+#endif
 
 #ifdef MODULE
 /* Eventually this will go into an include file, but this will be later */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ibmmca.h linux.18p8/drivers/scsi/ibmmca.h
--- linux.vanilla/drivers/scsi/ibmmca.h	Wed May  3 22:31:20 2000
+++ linux.18p8/drivers/scsi/ibmmca.h	Fri Sep 15 15:13:38 2000
@@ -1,3 +1,9 @@
+/* 
+ * Low Level Driver for the IBM Microchannel SCSI Subsystem
+ * (Headerfile, see README.ibmmca for description of the IBM MCA SCSI-driver
+ * For use under the GNU public license within the Linux-kernel project.
+ */
+
 #ifndef _IBMMCA_H
 #define _IBMMCA_H
 
@@ -5,18 +11,15 @@
 #include <linux/version.h>
 #endif
 
-#ifndef ibmmca_header_linux_version
-#define ibmmca_header_linux_version(v,p,s) (((v)<<16)+((p)<<8)+(s))
-#endif
-
-/* 
- * Low Level Driver for the IBM Microchannel SCSI Subsystem
- * (Headerfile, see README.ibmmca for description of the IBM MCA SCSI-driver)
- */
+/* Note to the Linux-toplevel-maintainers: 
+ * This file contains the unified header for all available Linux-distributions.
+ * For reasons of maintenance, it is recommended to keep this unmodified to
+ * be downward compatible until I no longer get any requests from people 
+ * using older kernel releases on their PS/2 machines. (23 Apr 2000, M.Lang) */
 
 /* Common forward declarations for all Linux-versions: */
 
-/*services provided to the higher level of Linux SCSI driver */
+/* Interfaces to the midlevel Linux SCSI driver */
 extern int ibmmca_proc_info (char *, char **, off_t, int, int, int);
 extern int ibmmca_detect (Scsi_Host_Template *);
 extern int ibmmca_release (struct Scsi_Host *);
@@ -29,16 +32,18 @@
 /*structure for /proc filesystem */
 extern struct proc_dir_entry proc_scsi_ibmmca;
 
-#if LINUX_VERSION_CODE >= ibmmca_header_linux_version(2,1,0)
-/* Stuff for Linux >= 2.1.0: */
-/*initialization for Scsi_host_template type (Linux >= 2.1.0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,75)
+/* Stuff for Linux >= 2.1.75: */
 /*
  * 2/8/98
  * Note to maintainer of IBMMCA.  Do not change this initializer back to
  * the old format.  Please ask eric@andante.jic.com if you have any questions
  * about this, but it will break things in the future.
  */
-#define IBMMCA {						      \
+/*initialization for Scsi_host_template type (Linux >= 2.1.75 && < 2.3.27) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27)
+#define IBMMCA {                                                      \
           proc_dir:       &proc_scsi_ibmmca,    /*proc_dir*/          \
 	  proc_info:	  ibmmca_proc_info,     /*proc info fn*/      \
           name:           "IBM SCSI-Subsystem", /*name*/              \
@@ -56,11 +61,30 @@
           unchecked_isa_dma: 0,                 /*32-Bit Busmaster */ \
           use_clustering: ENABLE_CLUSTERING     /*use_clustering*/    \
           }
-
 #else
-/* Stuff for Linux < 2.1.0: */
+#define IBMMCA {                                                      \
+          proc_name:      "ibmmca",             /*proc_name*/         \
+	  proc_info:	  ibmmca_proc_info,     /*proc info fn*/      \
+          name:           "IBM SCSI-Subsystem", /*name*/              \
+          detect:         ibmmca_detect,        /*detect fn*/         \
+          release:        ibmmca_release,       /*release fn*/        \
+          command:        ibmmca_command,       /*command fn*/        \
+          queuecommand:   ibmmca_queuecommand,  /*queuecommand fn*/   \
+          abort:          ibmmca_abort,         /*abort fn*/          \
+          reset:          ibmmca_reset,         /*reset fn*/          \
+          bios_param:     ibmmca_biosparam,     /*bios fn*/           \
+          can_queue:      16,                   /*can_queue*/         \
+          this_id:        7,                    /*set by detect*/     \
+          sg_tablesize:   16,                   /*sg_tablesize*/      \
+          cmd_per_lun:    1,                    /*cmd_per_lun*/       \
+          unchecked_isa_dma: 0,                 /*32-Bit Busmaster */ \
+          use_clustering: ENABLE_CLUSTERING     /*use_clustering*/    \
+          }
+#endif
+#else
+/* Stuff for Linux < 2.1.75: */
 
-/*initialization for Scsi_host_template type (Linux < 2.1.0) */
+/*initialization for Scsi_host_template type (Linux < 2.1.75) */
 #define IBMMCA {                                      \
           NULL,                 /*next*/              \
           NULL,                 /*usage_count*/       \
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ips.c linux.18p8/drivers/scsi/ips.c
--- linux.vanilla/drivers/scsi/ips.c	Sun Jun 11 21:44:15 2000
+++ linux.18p8/drivers/scsi/ips.c	Tue Sep  5 21:54:35 2000
@@ -77,18 +77,41 @@
 /*            2.3.18 and later                                               */
 /*          - Sync with other changes from the 2.3 kernels                   */
 /* 4.00.06  - Fix timeout with initial FFDC command                          */
+/* 4.10.00  - Add support for ServeRAID 4M/4L                                */
+/* 4.10.13  - Fix for dynamic unload and proc file system                    */
+/* 4.20.03  - Rename version to coincide with new release schedules          */
+/*            Performance fixes                                              */
+/*            Fix truncation of /proc files with cat                         */
+/*            Merge in changes through kernel 2.4.0test1ac21                 */
+/* 4.20.13  - Fix some failure cases / reset code                            */
+/*          - Hook into the reboot_notifier to flush the controller cache    */
 /*                                                                           */
 /*****************************************************************************/
 
 /*
  * Conditional Compilation directives for this driver:
  *
- * NO_IPS_RESET         - Don't reset the controller (no matter what)
- * IPS_DEBUG            - More verbose error messages
- * IPS_PCI_PROBE_DEBUG  - Print out more detail on the PCI probe
+ * IPS_DEBUG            - Turn on debugging info
  *
+ *
+ * Parameters:
+ *
+ * debug:<number>       - Set debug level to <number>
+ *                        NOTE: only works when IPS_DEBUG compile directive
+ *                              is used.
+ *
+ *       1              - Normal debug messages
+ *       2              - Verbose debug messages
+ *       11             - Method trace (non interrupt)
+ *       12             - Method trace (includes interrupt)
+ *
+ * noreset              - Don't reset the controller
+ * nocmdline            - Turn off passthru support
+ * noi2o                - Don't use I2O Queues (ServeRAID 4 only)
+ * nommap               - Don't use memory mapped I/O
  */
 
+
 #if defined (MODULE)
    #include <linux/module.h>
 #endif /* MODULE */
@@ -102,10 +125,12 @@
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
+#include <linux/reboot.h>
 
 #include <linux/blk.h>
 #include <linux/types.h>
@@ -128,25 +153,29 @@
 #include <asm/spinlock.h>
 #endif
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#include <linux/init.h>
+#endif
+
 #include <linux/smp.h>
 
+#ifdef MODULE
+   static char *ips = NULL;
+   MODULE_PARM(ips, "s");
+#endif
+
 /*
  * DRIVER_VER
  */
-#define IPS_VERSION_HIGH        "4.00"  /* MUST be 4 chars */
-#define IPS_VERSION_LOW         ".06 "  /* MUST be 4 chars */
+#define IPS_VERSION_HIGH        "4.20"
+#define IPS_VERSION_LOW         ".20 "
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
 struct proc_dir_entry proc_scsi_ips = {
-#if !defined(PROC_SCSI_IPS)
-   0,                                /* Use dynamic inode allocation */
-#else
-   PROC_SCSI_IPS,
-#endif
+   0,
    3, "ips",
    S_IFDIR | S_IRUGO | S_IXUGO, 2
-}
-;
+};
 #endif
 
 #if !defined(__i386__)
@@ -161,12 +190,14 @@
    #error "To use the command-line interface you need to define SG_BIG_BUFF"
 #endif
 
-#if IPS_DEBUG >= 12
-   #define DBG(s)       printk(KERN_NOTICE s "\n"); MDELAY(2*IPS_ONE_SEC)
-#elif IPS_DEBUG >= 11
-   #define DBG(s)       printk(KERN_NOTICE s "\n")
+#ifdef IPS_DEBUG
+   #define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
+   #define DEBUG(i, s)           if (ips_debug >= i) printk(KERN_NOTICE s "\n");
+   #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v);
 #else
-   #define DBG(s)
+   #define METHOD_TRACE(s, i)
+   #define DEBUG(i, s)
+   #define DEBUG_VAR(i, s, v...)
 #endif
 
 /*
@@ -175,11 +206,26 @@
 static const char * ips_name = "ips";
 static struct Scsi_Host * ips_sh[IPS_MAX_ADAPTERS];  /* Array of host controller structures */
 static ips_ha_t * ips_ha[IPS_MAX_ADAPTERS];          /* Array of HA structures */
+static unsigned int ips_next_controller = 0;
 static unsigned int ips_num_controllers = 0;
+static unsigned int ips_released_controllers = 0;
 static int          ips_cmd_timeout = 60;
 static int          ips_reset_timeout = 60 * 5;
+static int          ips_force_memio = 1;             /* Always use Memory Mapped I/O    */
+static int          ips_force_i2o = 1;               /* Always use I2O command delivery */
+static int          ips_resetcontroller = 1;         /* Reset the controller            */
+static int          ips_cmdline = 1;                 /* Support for passthru            */
+
+#ifdef IPS_DEBUG
+static int          ips_debug = 0;                   /* Debug mode                      */
+#endif
+
+/*
+ * Necessary forward function protoypes
+ */
+static int ips_halt(struct notifier_block *nb, ulong event, void *buf);
 
-#define MAX_ADAPTER_NAME 7
+#define MAX_ADAPTER_NAME 9
 
 static char ips_adapter_name[][30] = {
    "ServeRAID",
@@ -188,7 +234,13 @@
    "ServeRAID on motherboard",
    "ServeRAID 3H",
    "ServeRAID 3L",
-   "ServeRAID 4H"
+   "ServeRAID 4H",
+   "ServeRAID 4M",
+   "ServeRAID 4L"
+};
+
+static struct notifier_block ips_notifier = {
+   ips_halt, NULL, 0
 };
 
 /*
@@ -253,8 +305,6 @@
  */
 int ips_detect(Scsi_Host_Template *);
 int ips_release(struct Scsi_Host *);
-int ips_abort(Scsi_Cmnd *);
-int ips_reset(Scsi_Cmnd *, unsigned int);
 int ips_eh_abort(Scsi_Cmnd *);
 int ips_eh_reset(Scsi_Cmnd *);
 int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
@@ -262,21 +312,26 @@
 const char * ips_info(struct Scsi_Host *);
 void do_ipsintr(int, void *, struct pt_regs *);
 static int ips_hainit(ips_ha_t *);
-static int ips_map_status(ips_scb_t *, ips_stat_t *);
+static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
 static int ips_send(ips_ha_t *, ips_scb_t *, ips_scb_callback);
 static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
 static int ips_send_cmd(ips_ha_t *, ips_scb_t *);
-static int ips_chkstatus(ips_ha_t *);
 static int ips_online(ips_ha_t *, ips_scb_t *);
 static int ips_inquiry(ips_ha_t *, ips_scb_t *);
 static int ips_rdcap(ips_ha_t *, ips_scb_t *);
 static int ips_msense(ips_ha_t *, ips_scb_t *);
 static int ips_reqsen(ips_ha_t *, ips_scb_t *);
 static int ips_allocatescbs(ips_ha_t *);
-static int ips_reset_adapter(ips_ha_t *);
-static int ips_statupd(ips_ha_t *);
-static int ips_issue(ips_ha_t *, ips_scb_t *);
-static int ips_isintr(ips_ha_t *);
+static int ips_reset_copperhead(ips_ha_t *);
+static int ips_reset_copperhead_memio(ips_ha_t *);
+static int ips_reset_morpheus(ips_ha_t *);
+static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *);
+static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *);
+static int ips_issue_i2o(ips_ha_t *, ips_scb_t *);
+static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *);
+static int ips_isintr_copperhead(ips_ha_t *);
+static int ips_isintr_copperhead_memio(ips_ha_t *);
+static int ips_isintr_morpheus(ips_ha_t *);
 static int ips_wait(ips_ha_t *, int, int);
 static int ips_write_driver_status(ips_ha_t *, int);
 static int ips_read_adapter_status(ips_ha_t *, int);
@@ -284,7 +339,22 @@
 static int ips_read_config(ips_ha_t *, int);
 static int ips_clear_adapter(ips_ha_t *, int);
 static int ips_readwrite_page5(ips_ha_t *, int, int);
-static void ips_intr(ips_ha_t *);
+static int ips_init_copperhead(ips_ha_t *);
+static int ips_init_copperhead_memio(ips_ha_t *);
+static int ips_init_morpheus(ips_ha_t *);
+static int ips_isinit_copperhead(ips_ha_t *);
+static int ips_isinit_copperhead_memio(ips_ha_t *);
+static int ips_isinit_morpheus(ips_ha_t *);
+static u32 ips_statupd_copperhead(ips_ha_t *);
+static u32 ips_statupd_copperhead_memio(ips_ha_t *);
+static u32 ips_statupd_morpheus(ips_ha_t *);
+static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
+static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
+static void ips_enable_int_copperhead(ips_ha_t *);
+static void ips_enable_int_copperhead_memio(ips_ha_t *);
+static void ips_enable_int_morpheus(ips_ha_t *);
+static void ips_intr_copperhead(ips_ha_t *);
+static void ips_intr_morpheus(ips_ha_t *);
 static void ips_next(ips_ha_t *, int);
 static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);
 static void ipsintr_done(ips_ha_t *, struct ips_scb *);
@@ -293,6 +363,7 @@
 static void ips_init_scb(ips_ha_t *, ips_scb_t *);
 static void ips_freescb(ips_ha_t *, ips_scb_t *);
 static void ips_statinit(ips_ha_t *);
+static void ips_statinit_memio(ips_ha_t *);
 static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);
 static void ips_ffdc_reset(ips_ha_t *, int);
 static void ips_ffdc_time(ips_ha_t *, int);
@@ -312,6 +383,9 @@
 static int ips_erase_bios(ips_ha_t *);
 static int ips_program_bios(ips_ha_t *, char *, int);
 static int ips_verify_bios(ips_ha_t *, char *, int);
+static int ips_erase_bios_memio(ips_ha_t *);
+static int ips_program_bios_memio(ips_ha_t *, char *, int);
+static int ips_verify_bios_memio(ips_ha_t *, char *, int);
 
 #ifndef NO_IPS_CMDLINE
 static int ips_is_passthru(Scsi_Cmnd *);
@@ -332,6 +406,76 @@
 
 /****************************************************************************/
 /*                                                                          */
+/* Routine Name: ips_setup                                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   setup parameters to the driver                                         */
+/*                                                                          */
+/****************************************************************************/
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+static int
+ips_setup(char *ips_str) {
+#else
+void
+ips_setup(char *ips_str, int *dummy) {
+#endif
+   int        i;
+   char      *p;
+   char      *key;
+   char      *value;
+   char       tokens[3] = {',', '.', 0};
+   IPS_OPTION options[] = {
+      {"noreset", &ips_resetcontroller, 0},
+#ifdef IPS_DEBUG
+      {"debug", &ips_debug, 1},
+#endif
+      {"noi2o", &ips_force_i2o, 0},
+      {"nommap", &ips_force_memio, 0},
+      {"nocmdline", &ips_cmdline, 0},
+   };
+
+   METHOD_TRACE("ips_setup", 1);
+
+   for (key = strtok(ips_str, tokens); key; key = strtok(NULL, tokens)) {
+      p = key;
+
+      /* Search for value */
+      while ((p) && (*p != ':'))
+         p++;
+
+      if (p) {
+         *p = '\0';
+         value = p+1;
+      } else
+         value = NULL;
+
+      /*
+       * We now have key/value pairs.
+       * Update the variables
+       */
+      for (i = 0; i < (sizeof(options) / sizeof(options[0])); i++) {
+         if (strnicmp(key, options[i].option_name, strlen(ips_str)) == 0) {
+            if (value)
+               *options[i].option_flag = simple_strtoul(value, NULL, 0);
+            else
+               *options[i].option_flag = options[i].option_value;
+
+            break;
+         }
+      }
+   }
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+   return (1);
+#endif
+}
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+__setup("ips=", ips_setup);
+#endif
+
+/****************************************************************************/
+/*                                                                          */
 /* Routine Name: ips_detect                                                 */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -346,15 +490,38 @@
    struct Scsi_Host *sh;
    ips_ha_t         *ha;
    u32               io_addr;
+   u32               mem_addr;
+   u32               io_len;
+   u32               mem_len;
    u16               planer;
    u8                revision_id;
    u8                bus;
    u8                func;
    u8                irq;
-   int               index;
-   struct pci_dev   *dev = NULL;
-
-   DBG("ips_detect");
+   u16               deviceID[2];
+   int               i;
+   int               j;
+   char             *ioremap_ptr;
+   char             *mem_ptr;
+   struct pci_dev   *dev[2];
+   struct pci_dev   *morpheus = NULL;
+   struct pci_dev   *trombone = NULL;
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,14)
+   u32               currbar;
+   u32               maskbar;
+   u8                barnum;
+#endif
+
+   METHOD_TRACE("ips_detect", 1);
+
+#ifdef MODULE
+   if (ips)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+      ips_setup(ips);
+#else
+      ips_setup(ips, NULL);
+#endif
+#endif
 
    SHT->proc_info = ips_proc_info;
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
@@ -367,232 +534,522 @@
 
    /* initalize number of controllers */
    ips_num_controllers = 0;
+   ips_next_controller = 0;
+   ips_released_controllers = 0;
 
    if (!pci_present())
       return (0);
 
-   for (index = 0; index < IPS_MAX_ADAPTERS; index++) {
+   morpheus = pci_find_device(IPS_VENDORID, IPS_MORPHEUS_DEVICEID, morpheus);
+   trombone = pci_find_device(IPS_VENDORID, IPS_COPPERHEAD_DEVICEID, trombone);
 
-      if (!(dev = pci_find_device(IPS_VENDORID, IPS_DEVICEID, dev)))
-         break;
+   /* determine which controller to probe first */
+   if (!morpheus) {
+      /* we only have trombone */
+      dev[0] = trombone;
+      dev[1] = NULL;
+      deviceID[0] = IPS_COPPERHEAD_DEVICEID;
+   } else if (!trombone) {
+      /* we only have morpheus */
+      dev[0] = morpheus;
+      dev[1] = NULL;
+      deviceID[0] = IPS_MORPHEUS_DEVICEID;
+   } else {
+      /* we have both in the system */
+      if (trombone->bus < morpheus->bus) {
+         dev[0] = trombone;
+         dev[1] = morpheus;
+         deviceID[0] = IPS_COPPERHEAD_DEVICEID;
+         deviceID[1] = IPS_MORPHEUS_DEVICEID;
+      } else if (trombone->bus > morpheus->bus) {
+         dev[0] = morpheus;
+         dev[1] = trombone;
+         deviceID[0] = IPS_MORPHEUS_DEVICEID;
+         deviceID[1] = IPS_COPPERHEAD_DEVICEID;
+      } else {
+         /* further detection required */
+         if (trombone->devfn < morpheus->devfn) {
+            dev[0] = trombone;
+            dev[1] = morpheus;
+            deviceID[0] = IPS_COPPERHEAD_DEVICEID;
+            deviceID[1] = IPS_MORPHEUS_DEVICEID;
+         } else {
+            dev[0] = morpheus;
+            dev[1] = trombone;
+            deviceID[0] = IPS_MORPHEUS_DEVICEID;
+            deviceID[1] = IPS_COPPERHEAD_DEVICEID;
+         }
+      }
+   }
 
-      /* stuff that we get in dev */
-      irq = dev->irq;
-      bus = dev->bus->number;
-      func = dev->devfn;
+   /* Now scan the controllers */
+   for (i = 0; i < 2; i++) {
+      if (!dev[i])
+         break;
 
-      /* get planer status */
-      if (pci_read_config_word(dev, 0x04, &planer)) {
-         printk(KERN_WARNING "(%s%d) can't get planer status.\n",
-                ips_name, index);
+      do {
+         if (ips_next_controller >= IPS_MAX_ADAPTERS)
+            break;
 
-         continue;
-      }
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+         if (pci_enable_device(dev[i]))
+            break;
+#endif
 
-      /* check I/O address */
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,13)
-      io_addr = dev->base_address[0];
+         /* stuff that we get in dev */
+         irq = dev[i]->irq;
+         bus = dev[i]->bus->number;
+         func = dev[i]->devfn;
+
+         /* Init MEM/IO addresses to 0 */
+         mem_addr = 0;
+         io_addr = 0;
+         mem_len = 0;
+         io_len = 0;
+
+         for (j = 0; j < 2; j++) {
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
+            if (!pci_resource_start(dev[i], j))
+               break;
 
-      if ((io_addr & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
-         continue;
+            if (pci_resource_flags(dev[i], j) & IORESOURCE_IO) {
+               io_addr = pci_resource_start(dev[i], j);
+               io_len = pci_resource_len(dev[i], j);
+            } else {
+               mem_addr = pci_resource_start(dev[i], j);
+               mem_len = pci_resource_len(dev[i], j);
+            }
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,3,14)
+            if (!dev[i]->resource[j].start)
+               break;
 
-      /* get the BASE IO Address */
-      io_addr &= PCI_BASE_ADDRESS_IO_MASK;
+            if ((dev[i]->resource[j].start & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+               io_addr = dev[i]->resource[j].start;
+               io_len = dev[i]->resource[j].end - dev[i]->resource[j].start + 1;
+            } else {
+               mem_addr = dev[i]->resource[j].start;
+               mem_len = dev[i]->resource[j].end - dev[i]->resource[j].start + 1;
+            }
 #else
-      io_addr = dev->resource[0].start;
+            if (!dev[i]->base_address[j])
+               break;
 
-      if ((dev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
-         continue;
+            if ((dev[i]->base_address[j] & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+               barnum = PCI_BASE_ADDRESS_0 + (j * 4);
+               io_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_IO_MASK;
+
+               /* Get Size */
+               pci_read_config_dword(dev[i], barnum, &currbar);
+               pci_write_config_dword(dev[i], barnum, ~0);
+               pci_read_config_dword(dev[i], barnum, &maskbar);
+               pci_write_config_dword(dev[i], barnum, currbar);
+
+               io_len = ~(maskbar & PCI_BASE_ADDRESS_IO_MASK) + 1;
+            } else {
+               barnum = PCI_BASE_ADDRESS_0 + (j * 4);
+               mem_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_MEM_MASK;
+
+               /* Get Size */
+               pci_read_config_dword(dev[i], barnum, &currbar);
+               pci_write_config_dword(dev[i], barnum, ~0);
+               pci_read_config_dword(dev[i], barnum, &maskbar);
+               pci_write_config_dword(dev[i], barnum, currbar);
+
+               mem_len = ~(maskbar & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+            }
 #endif
+         }
 
-      /* check to see if an onboard planer controller is disabled */
-      if (!(planer & 0x000C)) {
+         /* setup memory mapped area (if applicable) */
+         if (mem_addr) {
+            u32 base;
+            u32 offs;
+
+            DEBUG_VAR(1, "(%s%d) detect, Memory region %x, size: %d",
+                      ips_name, ips_next_controller, mem_addr, mem_len);
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
+            if (check_mem_region(mem_addr, mem_len)) {
+               /* Couldn't allocate io space */
+               printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n",
+                      ips_name, ips_next_controller, io_addr, io_len);
 
-   #ifdef IPS_PCI_PROBE_DEBUG
-         printk(KERN_NOTICE "(%s%d) detect, Onboard ServeRAID disabled by BIOS\n",
-                ips_name, index);
-   #endif
+               ips_next_controller++;
 
-         continue;
-      }
+               continue;
+            }
 
-   #ifdef IPS_PCI_PROBE_DEBUG
-      printk(KERN_NOTICE "(%s%d) detect bus %d, func %x, irq %d, io %x\n",
-             ips_name, index, bus, func, irq, io_addr);
-   #endif
-
-      /* get the revision ID */
-      if (pci_read_config_byte(dev, 0x08, &revision_id)) {
-         printk(KERN_WARNING "(%s%d) can't get revision id.\n",
-                ips_name, index);
+            request_mem_region(mem_addr, mem_len, "ips");
+#endif
 
-         continue;
-      }
+            base = mem_addr & PAGE_MASK;
+            offs = mem_addr - base;
 
-      /* found a controller */
-      sh = scsi_register(SHT, sizeof(ips_ha_t));
+            ioremap_ptr = ioremap(base, PAGE_SIZE);
+            mem_ptr = ioremap_ptr + offs;
+         } else {
+            ioremap_ptr = NULL;
+            mem_ptr = NULL;
+         }
 
-      if (sh == NULL) {
-         printk(KERN_WARNING "(%s%d) Unable to register controller with SCSI subsystem - skipping controller\n",
-                ips_name, index);
+         /* setup I/O mapped area (if applicable) */
+         if (io_addr) {
+            DEBUG_VAR(1, "(%s%d) detect, IO region %x, size: %d",
+                      ips_name, ips_next_controller, io_addr, io_len);
+
+            if (check_region(io_addr, io_len)) {
+               /* Couldn't allocate io space */
+               printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n",
+                      ips_name, ips_next_controller, io_addr, io_len);
 
-         continue;
-      }
+               ips_next_controller++;
 
-      ha = IPS_HA(sh);
-      memset(ha, 0, sizeof(ips_ha_t));
+               continue;
+            }
 
-      /* Initialize spin lock */
-      spin_lock_init(&ha->scb_lock);
-      spin_lock_init(&ha->copp_lock);
-      spin_lock_init(&ha->ips_lock);
-      spin_lock_init(&ha->copp_waitlist.lock);
-      spin_lock_init(&ha->scb_waitlist.lock);
-      spin_lock_init(&ha->scb_activelist.lock);
-
-      ips_sh[ips_num_controllers] = sh;
-      ips_ha[ips_num_controllers] = ha;
-      ips_num_controllers++;
-      ha->active = 1;
-
-      ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_KERNEL|GFP_DMA);
-
-      if (!ha->enq) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n",
-                ips_name, index);
+            request_region(io_addr, io_len, "ips");
+         }
 
-         ha->active = 0;
+         /* get planer status */
+         if (pci_read_config_word(dev[i], 0x04, &planer)) {
+            printk(KERN_WARNING "(%s%d) can't get planer status.\n",
+                   ips_name, ips_next_controller);
 
-         continue;
-      }
+            ips_next_controller++;
 
-      ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_KERNEL|GFP_DMA);
+            continue;
+         }
 
-      if (!ha->adapt) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host adapt structure - skipping controller\n",
-                ips_name, index);
+         /* check to see if an onboard planer controller is disabled */
+         if (!(planer & 0x000C)) {
 
-         ha->active = 0;
+            DEBUG_VAR(1, "(%s%d) detect, Onboard ServeRAID disabled by BIOS",
+                      ips_name, ips_next_controller);
 
-         continue;
-      }
+            ips_next_controller++;
 
-      ha->conf = kmalloc(sizeof(IPS_CONF), GFP_KERNEL|GFP_DMA);
+            continue;
+         }
 
-      if (!ha->conf) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n",
-                ips_name, index);
+         DEBUG_VAR(1, "(%s%d) detect bus %d, func %x, irq %d, io %x, mem: %x, ptr: %x",
+                   ips_name, ips_next_controller, bus, func, irq, io_addr, mem_addr, (u32) mem_ptr);
 
-         ha->active = 0;
+         /* get the revision ID */
+         if (pci_read_config_byte(dev[i], 0x08, &revision_id)) {
+            printk(KERN_WARNING "(%s%d) can't get revision id.\n",
+                   ips_name, ips_next_controller);
 
-         continue;
-      }
+            ips_next_controller++;
 
-      ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_KERNEL|GFP_DMA);
+            continue;
+         }
 
-      if (!ha->nvram) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n",
-                ips_name, index);
+         /* found a controller */
+         sh = scsi_register(SHT, sizeof(ips_ha_t));
 
-         ha->active = 0;
+         if (sh == NULL) {
+            printk(KERN_WARNING "(%s%d) Unable to register controller with SCSI subsystem - skipping controller\n",
+                   ips_name, ips_next_controller);
 
-         continue;
-      }
+            ips_next_controller++;
 
-      ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_KERNEL|GFP_DMA);
+            continue;
+         }
 
-      if (!ha->subsys) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n",
-                ips_name, index);
+         ha = IPS_HA(sh);
+         memset(ha, 0, sizeof(ips_ha_t));
 
-         ha->active = 0;
+         /* Initialize spin lock */
+         spin_lock_init(&ha->scb_lock);
+         spin_lock_init(&ha->copp_lock);
+         spin_lock_init(&ha->ips_lock);
+         spin_lock_init(&ha->copp_waitlist.lock);
+         spin_lock_init(&ha->scb_waitlist.lock);
+         spin_lock_init(&ha->scb_activelist.lock);
+
+         ips_sh[ips_next_controller] = sh;
+         ips_ha[ips_next_controller] = ha;
+         ips_num_controllers++;
+         ha->active = 1;
+
+         ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_ATOMIC|GFP_DMA);
+
+         if (!ha->enq) {
+            printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            ips_next_controller++;
+            ips_num_controllers--;
 
-         continue;
-      }
+            continue;
+         }
 
-      ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_KERNEL|GFP_DMA);
+         ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_ATOMIC|GFP_DMA);
 
-      if (!ha->dummy) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate host dummy structure - skipping controller\n",
-                ips_name, index);
+         if (!ha->adapt) {
+            printk(KERN_WARNING "(%s%d) Unable to allocate host adapt structure - skipping controller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            ips_next_controller++;
+            ips_num_controllers--;
 
-         ha->active = 0;
+            continue;
+         }
 
-         continue;
-      }
+         ha->conf = kmalloc(sizeof(IPS_CONF), GFP_ATOMIC|GFP_DMA);
 
-      ha->ioctl_data = kmalloc(IPS_IOCTL_SIZE, GFP_KERNEL|GFP_DMA);
-      ha->ioctl_datasize = IPS_IOCTL_SIZE;
-      if (!ha->ioctl_data) {
-         printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data - skipping controller\n",
-                ips_name, index);
+         if (!ha->conf) {
+            printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            ips_next_controller++;
+            ips_num_controllers--;
 
-         ha->active = 0;
+            continue;
+         }
 
-         continue;
-      }
+         ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_ATOMIC|GFP_DMA);
 
-      /* Store away needed values for later use */
-      sh->io_port = io_addr;
-      sh->n_io_port = 255;
-      sh->unique_id = io_addr;
-      sh->irq = irq;
-      sh->select_queue_depths = NULL;
-      sh->sg_tablesize = sh->hostt->sg_tablesize;
-      sh->can_queue = sh->hostt->can_queue;
-      sh->cmd_per_lun = sh->hostt->cmd_per_lun;
-      sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
-      sh->use_clustering = sh->hostt->use_clustering;
-
-      /* Store info in HA structure */
-      ha->io_addr = io_addr;
-      ha->irq = irq;
-      ha->host_num = index;
-      ha->revision_id = revision_id;
-
-      /* install the interrupt handler */
-      if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
-         printk(KERN_WARNING "(%s%d) unable to install interrupt handler - skipping controller\n",
-                ips_name, index);
+         if (!ha->nvram) {
+            printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            ips_next_controller++;
+            ips_num_controllers--;
 
-         ha->active = 0;
+            continue;
+         }
 
-         continue;
-      }
+         ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_ATOMIC|GFP_DMA);
 
-      /*
-       * Allocate a temporary SCB for initialization
-       */
-      ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_KERNEL|GFP_DMA);
-      if (!ha->scbs) {
-         /* couldn't allocate a temp SCB */
-         printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
-                ips_name, index);
+         if (!ha->subsys) {
+            printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            ips_next_controller++;
+            ips_num_controllers--;
 
-         ha->active = 0;
+            continue;
+         }
 
-         continue;
-      }
+         ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_ATOMIC|GFP_DMA);
 
-      memset(ha->scbs, 0, sizeof(ips_scb_t));
-      ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_KERNEL|GFP_DMA);
-      if (!ha->scbs->sg_list) {
-         /* couldn't allocate a temp SCB S/G list */
-         printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
-                ips_name, index);
+         if (!ha->dummy) {
+            printk(KERN_WARNING "(%s%d) Unable to allocate host dummy structure - skipping controller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            ips_next_controller++;
+            ips_num_controllers--;
 
-         ha->active = 0;
+            continue;
+         }
+
+         ha->ioctl_data = kmalloc(IPS_IOCTL_SIZE, GFP_ATOMIC|GFP_DMA);
+         ha->ioctl_datasize = IPS_IOCTL_SIZE;
+         if (!ha->ioctl_data) {
+            printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data - skipping controller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            ips_next_controller++;
+            ips_num_controllers--;
+
+            continue;
+         }
+
+         /* Store away needed values for later use */
+         sh->io_port = io_addr;
+         sh->n_io_port = io_addr ? 255 : 0;
+         sh->unique_id = (io_addr) ? io_addr : mem_addr;
+         sh->irq = irq;
+         sh->select_queue_depths = ips_select_queue_depth;
+         sh->sg_tablesize = sh->hostt->sg_tablesize;
+         sh->can_queue = sh->hostt->can_queue;
+         sh->cmd_per_lun = sh->hostt->cmd_per_lun;
+         sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
+         sh->use_clustering = sh->hostt->use_clustering;
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,32)
+         sh->wish_block = FALSE;
+#endif
+
+         /* Store info in HA structure */
+         ha->irq = irq;
+         ha->io_addr = io_addr;
+         ha->io_len = io_len;
+         ha->mem_addr = mem_addr;
+         ha->mem_len = mem_len;
+         ha->mem_ptr = mem_ptr;
+         ha->ioremap_ptr = ioremap_ptr;
+         ha->host_num = ips_next_controller;
+         ha->revision_id = revision_id;
+         ha->device_id = deviceID[i];
+         ha->pcidev = dev[i];
+
+         /*
+          * Setup Functions
+          */
+         if (IPS_IS_MORPHEUS(ha)) {
+            /* morpheus */
+            ha->func.isintr = ips_isintr_morpheus;
+            ha->func.isinit = ips_isinit_morpheus;
+            ha->func.issue = ips_issue_i2o_memio;
+            ha->func.init = ips_init_morpheus;
+            ha->func.statupd = ips_statupd_morpheus;
+            ha->func.reset = ips_reset_morpheus;
+            ha->func.intr = ips_intr_morpheus;
+            ha->func.enableint = ips_enable_int_morpheus;
+         } else if (IPS_USE_MEMIO(ha)) {
+            /* copperhead w/MEMIO */
+            ha->func.isintr = ips_isintr_copperhead_memio;
+            ha->func.isinit = ips_isinit_copperhead_memio;
+            ha->func.init = ips_init_copperhead_memio;
+            ha->func.statupd = ips_statupd_copperhead_memio;
+            ha->func.statinit = ips_statinit_memio;
+            ha->func.reset = ips_reset_copperhead_memio;
+            ha->func.intr = ips_intr_copperhead;
+            ha->func.erasebios = ips_erase_bios_memio;
+            ha->func.programbios = ips_program_bios_memio;
+            ha->func.verifybios = ips_verify_bios_memio;
+            ha->func.enableint = ips_enable_int_copperhead_memio;
+
+            if (IPS_USE_I2O_DELIVER(ha))
+               ha->func.issue = ips_issue_i2o_memio;
+            else
+               ha->func.issue = ips_issue_copperhead_memio;
+         } else {
+            /* copperhead */
+            ha->func.isintr = ips_isintr_copperhead;
+            ha->func.isinit = ips_isinit_copperhead;
+            ha->func.init = ips_init_copperhead;
+            ha->func.statupd = ips_statupd_copperhead;
+            ha->func.statinit = ips_statinit;
+            ha->func.reset = ips_reset_copperhead;
+            ha->func.intr = ips_intr_copperhead;
+            ha->func.erasebios = ips_erase_bios;
+            ha->func.programbios = ips_program_bios;
+            ha->func.verifybios = ips_verify_bios;
+            ha->func.enableint = ips_enable_int_copperhead;
+
+            if (IPS_USE_I2O_DELIVER(ha))
+               ha->func.issue = ips_issue_i2o;
+            else
+               ha->func.issue = ips_issue_copperhead;
+         }
+
+         /*
+          * Initialize the card if it isn't already
+          */
+         if (!(*ha->func.isinit)(ha)) {
+            if (!(*ha->func.init)(ha)) {
+               /*
+                * Initialization failed
+                */
+               printk(KERN_WARNING "(%s%d) unable to initialize controller - skipping controller\n",
+                      ips_name, ips_next_controller);
+
+               ha->active = 0;
+               ips_free(ha);
+               ips_next_controller++;
+               ips_num_controllers--;
+
+               continue;
+            }
+         }
+
+         /* install the interrupt handler */
+         if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+            printk(KERN_WARNING "(%s%d) unable to install interrupt handler - skipping controller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            ips_next_controller++;
+            ips_num_controllers--;
+
+            continue;
+         }
+
+         /*
+          * Allocate a temporary SCB for initialization
+          */
+         ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA);
+         if (!ha->scbs) {
+            /* couldn't allocate a temp SCB */
+            printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            free_irq(ha->irq, ha);
+            ips_next_controller++;
+            ips_num_controllers--;
+
+            continue;
+         }
+
+         memset(ha->scbs, 0, sizeof(ips_scb_t));
+         ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC|GFP_DMA);
+         if (!ha->scbs->sg_list) {
+            /* couldn't allocate a temp SCB S/G list */
+            printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
+                   ips_name, ips_next_controller);
+
+            ha->active = 0;
+            ips_free(ha);
+            free_irq(ha->irq, ha);
+            ips_next_controller++;
+            ips_num_controllers--;
+
+            continue;
+         }
+
+         ha->max_cmds = 1;
+
+         ips_next_controller++;
+      } while ((dev[i] = pci_find_device(IPS_VENDORID, deviceID[i], dev[i])));
+   }
+
+   /*
+    * Do Phase 2 Initialization
+    * Controller init
+    */
+   for (i = 0; i < ips_next_controller; i++) {
+      ha = ips_ha[i];
+      sh = ips_sh[i];
+
+      if (!ha->active) {
+         scsi_unregister(sh);
+         ips_ha[i] = NULL;
+         ips_sh[i] = NULL;
 
          continue;
       }
 
-      ha->max_cmds = 1;
-
       if (!ips_hainit(ha)) {
          printk(KERN_WARNING "(%s%d) unable to initialize controller - skipping\n",
-                ips_name, index);
+                ips_name, i);
 
          ha->active = 0;
+         ips_free(ha);
+         free_irq(ha->irq, ha);
+         scsi_unregister(sh);
+         ips_ha[i] = NULL;
+         ips_sh[i] = NULL;
+         ips_num_controllers--;
 
          continue;
       }
@@ -607,9 +1064,15 @@
       /* allocate CCBs */
       if (!ips_allocatescbs(ha)) {
          printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n",
-                ips_name, index);
+                ips_name, i);
 
          ha->active = 0;
+         ips_free(ha);
+         free_irq(ha->irq, ha);
+         scsi_unregister(sh);
+         ips_ha[i] = NULL;
+         ips_sh[i] = NULL;
+         ips_num_controllers--;
 
          continue;
       }
@@ -617,9 +1080,12 @@
       /* finish setting values */
       sh->max_id = ha->ntargets;
       sh->max_lun = ha->nlun;
-      sh->max_channel = ha->nbus;
+      sh->max_channel = ha->nbus - 1;
       sh->can_queue = ha->max_cmds-1;
-   } /* end for */
+   }
+
+   if (ips_num_controllers > 0)
+      register_reboot_notifier(&ips_notifier);
 
    return (ips_num_controllers);
 
@@ -645,7 +1111,7 @@
    ips_ha_t  *ha;
    int        i;
 
-   DBG("ips_release");
+   METHOD_TRACE("ips_release", 1);
 
    for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++);
 
@@ -688,17 +1154,85 @@
    /* free extra memory */
    ips_free(ha);
 
+   /* Free I/O Region */
+   if (ha->io_addr)
+      release_region(ha->io_addr, ha->io_len);
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
+   if (ha->mem_addr)
+      release_mem_region(ha->mem_addr, ha->mem_len);
+#endif
+
    /* free IRQ */
    free_irq(ha->irq, ha);
 
-   /* unregister with SCSI sub system */
-   scsi_unregister(sh);
+   ips_released_controllers++;
+
+   if (ips_num_controllers == ips_released_controllers)
+      unregister_reboot_notifier(&ips_notifier);
 
    return (FALSE);
 }
 
 /****************************************************************************/
 /*                                                                          */
+/* Routine Name: ips_halt                                                   */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Perform cleanup when the system reboots                                */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_halt(struct notifier_block *nb, ulong event, void *buf) {
+   ips_scb_t *scb;
+   ips_ha_t  *ha;
+   int        i;
+
+   if ((event != SYS_RESTART) && (event != SYS_HALT) &&
+       (event != SYS_POWER_OFF))
+      return (NOTIFY_DONE);
+
+   for (i = 0; i < ips_next_controller; i++) {
+      ha = (ips_ha_t *) ips_ha[i];
+
+      if (!ha)
+         continue;
+
+      if (!ha->active)
+         continue;
+
+      /* flush the cache on the controller */
+      scb = &ha->scbs[ha->max_cmds-1];
+
+      ips_init_scb(ha, scb);
+
+      scb->timeout = ips_cmd_timeout;
+      scb->cdb[0] = IPS_CMD_FLUSH;
+
+      scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
+      scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
+      scb->cmd.flush_cache.state = IPS_NORM_STATE;
+      scb->cmd.flush_cache.reserved = 0;
+      scb->cmd.flush_cache.reserved2 = 0;
+      scb->cmd.flush_cache.reserved3 = 0;
+      scb->cmd.flush_cache.reserved4 = 0;
+
+      printk("(%s%d) Flushing Cache.\n", ips_name, ha->host_num);
+
+      /* send command */
+      if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
+         printk("(%s%d) Incomplete Flush.\n", ips_name, ha->host_num);
+      else
+         printk("(%s%d) Flushing Complete.\n", ips_name, ha->host_num);
+   }
+
+   unregister_reboot_notifier(&ips_notifier);
+   return (NOTIFY_OK);
+}
+
+/****************************************************************************/
+/*                                                                          */
 /* Routine Name: ips_eh_abort                                               */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -711,7 +1245,7 @@
    ips_ha_t         *ha;
    ips_copp_wait_item_t *item;
 
-   DBG("ips_eh_abort");
+   METHOD_TRACE("ips_eh_abort", 1);
 
    if (!SC)
       return (FAILED);
@@ -726,9 +1260,7 @@
 
    if (SC->serial_number != SC->serial_number_at_timeout) {
       /* HMM, looks like a bogus command */
-#if IPS_DEBUG >= 1
-      printk(KERN_NOTICE "Abort called with bogus scsi command\n");
-#endif
+      DEBUG(1, "Abort called with bogus scsi command");
 
       return (FAILED);
    }
@@ -767,121 +1299,49 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_abort                                                  */
+/* Routine Name: ips_eh_reset                                               */
 /*                                                                          */
 /* Routine Description:                                                     */
 /*                                                                          */
-/*   Abort a command                                                        */
+/*   Reset the controller (with new eh error code)                          */
+/*                                                                          */
+/* NOTE: this routine is called under the io_request_lock spinlock          */
 /*                                                                          */
 /****************************************************************************/
 int
-ips_abort(Scsi_Cmnd *SC) {
-   ips_ha_t         *ha;
+ips_eh_reset(Scsi_Cmnd *SC) {
+   int                   ret;
+   int                   i;
+   u32                   cpu_flags;
+   ips_ha_t             *ha;
+   ips_scb_t            *scb;
    ips_copp_wait_item_t *item;
 
-   DBG("ips_abort");
+   METHOD_TRACE("ips_eh_reset", 1);
 
-   if (!SC)
-      return (SCSI_ABORT_SNOOZE);
+#ifdef NO_IPS_RESET
+   return (FAILED);
+#else
 
-   ha = (ips_ha_t *) SC->host->hostdata;
+   if (!SC) {
+      DEBUG(1, "Reset called with NULL scsi command");
 
-   if (!ha)
-      return (SCSI_ABORT_SNOOZE);
+      return (FAILED);
+   }
 
-   if (!ha->active)
-      return (SCSI_ABORT_SNOOZE);
+   ha = (ips_ha_t *) SC->host->hostdata;
 
-   if (SC->serial_number != SC->serial_number_at_timeout) {
-      /* HMM, looks like a bogus command */
-#if IPS_DEBUG >= 1
-      printk(KERN_NOTICE "Abort called with bogus scsi command\n");
-#endif
+   if (!ha) {
+      DEBUG(1, "Reset called with NULL ha struct");
 
-      return (SCSI_ABORT_NOT_RUNNING);
+      return (FAILED);
    }
 
-   if (test_and_set_bit(IPS_IN_ABORT, &ha->flags))
-      return (SCSI_ABORT_SNOOZE);
-
-   /* See if the command is on the copp queue */
-   IPS_QUEUE_LOCK(&ha->copp_waitlist);
-   item = ha->copp_waitlist.head;
-   while ((item) && (item->scsi_cmd != SC))
-      item = item->next;
-   IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
-
-   if (item) {
-      /* Found it */
-      ips_removeq_copp(&ha->copp_waitlist, item);
-      clear_bit(IPS_IN_ABORT, &ha->flags);
-
-      return (SCSI_ABORT_PENDING);
-   }
-
-   /* See if the command is on the wait queue */
-   if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
-      /* command not sent yet */
-      clear_bit(IPS_IN_ABORT, &ha->flags);
-
-      return (SCSI_ABORT_PENDING);
-   } else {
-      /* command must have already been sent */
-      clear_bit(IPS_IN_ABORT, &ha->flags);
-
-      return (SCSI_ABORT_SNOOZE);
-   }
-}
-
-/****************************************************************************/
-/*                                                                          */
-/* Routine Name: ips_eh_reset                                               */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Reset the controller (with new eh error code)                          */
-/*                                                                          */
-/* NOTE: this routine is called under the io_request_lock spinlock          */
-/*                                                                          */
-/****************************************************************************/
-int
-ips_eh_reset(Scsi_Cmnd *SC) {
-   u32                   cpu_flags;
-   ips_ha_t             *ha;
-   ips_scb_t            *scb;
-   ips_copp_wait_item_t *item;
-
-   DBG("ips_eh_reset");
-
-#ifdef NO_IPS_RESET
-   return (FAILED);
-#else
-
-   if (!SC) {
-
-#if IPS_DEBUG >= 1
-      printk(KERN_NOTICE "Reset called with NULL scsi command\n");
-#endif
-
-      return (FAILED);
-   }
-
-   ha = (ips_ha_t *) SC->host->hostdata;
-
-   if (!ha) {
-
-#if IPS_DEBUG >= 1
-      printk(KERN_NOTICE "Reset called with NULL ha struct\n");
-#endif
-
-      return (FAILED);
-   }
-
-   if (!ha->active)
-      return (FAILED);
-
-   if (test_and_set_bit(IPS_IN_RESET, &ha->flags))
-      return (FAILED);
+   if (!ha->active)
+      return (FAILED);
+
+   if (test_and_set_bit(IPS_IN_RESET, &ha->flags))
+      return (FAILED);
 
    /* See if the command is on the copp queue */
    IPS_QUEUE_LOCK(&ha->copp_waitlist);
@@ -910,149 +1370,72 @@
     * command must have already been sent
     * reset the controller
     */
-   if (!ips_reset_adapter(ha)) {
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
-      return (FAILED);
-   }
-
-   if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
-      clear_bit(IPS_IN_RESET, &ha->flags);
-
-      return (FAILED);
-   }
-
-   /* FFDC */
-   if (ha->subsys->param[3] & 0x300000) {
-      struct timeval tv;
-
-      do_gettimeofday(&tv);
-      IPS_HA_LOCK(cpu_flags);
-      ha->last_ffdc = tv.tv_sec;
-      ha->reset_count++;
-      IPS_HA_UNLOCK(cpu_flags);
-      ips_ffdc_reset(ha, IPS_INTR_IORL);
-   }
-
-   /* Now fail all of the active commands */
-#if IPS_DEBUG >= 1
-   printk(KERN_WARNING "(%s%d) Failing active commands\n",
+   printk(KERN_NOTICE "(%s%d) Resetting controller.\n",
           ips_name, ha->host_num);
-#endif
-   while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
-      scb->scsi_cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
-      scb->scsi_cmd->scsi_done(scb->scsi_cmd);
-      ips_freescb(ha, scb);
-   }
-
-   /* Reset the number of active IOCTLs */
-   IPS_HA_LOCK(cpu_flags);
-   ha->num_ioctl = 0;
-   IPS_HA_UNLOCK(cpu_flags);
-
-   clear_bit(IPS_IN_RESET, &ha->flags);
-
-   if (!test_bit(IPS_IN_INTR, &ha->flags)) {
-      /*
-       * Only execute the next command when
-       * we are not being called from the
-       * interrupt handler.  The interrupt
-       * handler wants to do this and since
-       * interrupts are turned off here....
-       */
-      ips_next(ha, IPS_INTR_IORL);
-   }
-
-   return (SUCCESS);
-
-#endif /* NO_IPS_RESET */
-
-}
-
-/****************************************************************************/
-/*                                                                          */
-/* Routine Name: ips_reset                                                  */
-/*                                                                          */
-/* Routine Description:                                                     */
-/*                                                                          */
-/*   Reset the controller                                                   */
-/*                                                                          */
-/* NOTE: this routine is called under the io_request_lock spinlock          */
-/*                                                                          */
-/****************************************************************************/
-int
-ips_reset(Scsi_Cmnd *SC, unsigned int flags) {
-   u32                   cpu_flags;
-   ips_ha_t             *ha;
-   ips_scb_t            *scb;
-   ips_copp_wait_item_t *item;
-
-   DBG("ips_reset");
+   ret = (*ha->func.reset)(ha);
 
-#ifdef NO_IPS_RESET
-   return (SCSI_RESET_SNOOZE);
-#else
+   if (!ret) {
+      Scsi_Cmnd *scsi_cmd;
 
-   if (!SC) {
+      printk(KERN_NOTICE 
+             "(%s%d) Controller reset failed - controller now offline.\n",
+             ips_name, ha->host_num);
 
-#if IPS_DEBUG >= 1
-      printk(KERN_NOTICE "Reset called with NULL scsi command\n");
-#endif
+      /* Now fail all of the active commands */
+      DEBUG_VAR(1, "(%s%d) Failing active commands",
+                ips_name, ha->host_num);
 
-      return (SCSI_RESET_SNOOZE);
-   }
+      while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
+         scb->scsi_cmd->result = DID_ERROR << 16;
+         scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+         ips_freescb(ha, scb);
+      }
 
-   ha = (ips_ha_t *) SC->host->hostdata;
+      /* Now fail all of the pending commands */
+      DEBUG_VAR(1, "(%s%d) Failing pending commands",
+                ips_name, ha->host_num);
 
-   if (!ha) {
+      while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
+         scsi_cmd->result = DID_ERROR;
+         scsi_cmd->scsi_done(scsi_cmd);
+      }
 
-#if IPS_DEBUG >= 1
-      printk(KERN_NOTICE "Reset called with NULL ha struct\n");
-#endif
+      ha->active = FALSE;
+      clear_bit(IPS_IN_RESET, &ha->flags);
 
-      return (SCSI_RESET_SNOOZE);
+      return (FAILED);
    }
 
-   if (!ha->active)
-      return (SCSI_RESET_SNOOZE);
-
-   if (test_and_set_bit(IPS_IN_RESET, &ha->flags))
-      return (SCSI_RESET_SNOOZE);
-
-   /* See if the command is on the copp queue */
-   IPS_QUEUE_LOCK(&ha->copp_waitlist);
-   item = ha->copp_waitlist.head;
-   while ((item) && (item->scsi_cmd != SC))
-      item = item->next;
-   IPS_QUEUE_UNLOCK(&ha->copp_waitlist);
-
-   if (item) {
-      /* Found it */
-      ips_removeq_copp(&ha->copp_waitlist, item);
-      clear_bit(IPS_IN_RESET, &ha->flags);
+   if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
+      Scsi_Cmnd *scsi_cmd;
 
-      return (SCSI_RESET_SNOOZE);
-   }
+      printk(KERN_NOTICE 
+             "(%s%d) Controller reset failed - controller now offline.\n",
+             ips_name, ha->host_num);
 
-   /* See if the command is on the wait queue */
-   if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
-      /* command not sent yet */
-      clear_bit(IPS_IN_RESET, &ha->flags);
+      /* Now fail all of the active commands */
+      DEBUG_VAR(1, "(%s%d) Failing active commands",
+                ips_name, ha->host_num);
 
-      return (SCSI_RESET_SNOOZE);
-   }
+      while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
+         scb->scsi_cmd->result = DID_ERROR << 16;
+         scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+         ips_freescb(ha, scb);
+      }
 
-   /* reset the controller */
-   if (!ips_reset_adapter(ha)) {
-      clear_bit(IPS_IN_RESET, &ha->flags);
+      /* Now fail all of the pending commands */
+      DEBUG_VAR(1, "(%s%d) Failing pending commands",
+                ips_name, ha->host_num);
 
-      return (SCSI_RESET_ERROR);
-   }
+      while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
+         scsi_cmd->result = DID_ERROR << 16;
+         scsi_cmd->scsi_done(scsi_cmd);
+      }
 
-   if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
+      ha->active = FALSE;
       clear_bit(IPS_IN_RESET, &ha->flags);
 
-      return (SCSI_RESET_ERROR);
+      return (FAILED);
    }
 
    /* FFDC */
@@ -1068,16 +1451,19 @@
    }
 
    /* Now fail all of the active commands */
-#if IPS_DEBUG >= 1
-   printk(KERN_WARNING "(%s%d) Failing active commands\n",
-          ips_name, ha->host_num);
-#endif
+   DEBUG_VAR(1, "(%s%d) Failing active commands",
+             ips_name, ha->host_num);
+
    while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
       scb->scsi_cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
       scb->scsi_cmd->scsi_done(scb->scsi_cmd);
       ips_freescb(ha, scb);
    }
 
+   /* Reset DCDB active command bits */
+   for (i = 1; i < ha->nbus; i++)
+      ha->dcdb_active[i-1] = 0;
+
    /* Reset the number of active IOCTLs */
    IPS_HA_LOCK(cpu_flags);
    ha->num_ioctl = 0;
@@ -1096,7 +1482,7 @@
       ips_next(ha, IPS_INTR_IORL);
    }
 
-   return (SCSI_RESET_SUCCESS);
+   return (SUCCESS);
 
 #endif /* NO_IPS_RESET */
 
@@ -1124,7 +1510,7 @@
    DECLARE_MUTEX_LOCKED(sem);
 #endif
 
-   DBG("ips_queue");
+   METHOD_TRACE("ips_queue", 1);
 
    ha = (ips_ha_t *) SC->host->hostdata;
 
@@ -1132,7 +1518,7 @@
       return (1);
 
    if (!ha->active)
-      return (1);
+      return (DID_ERROR);
 
 #ifndef NO_IPS_CMDLINE
    if (ips_is_passthru(SC)) {
@@ -1165,24 +1551,28 @@
 
    SC->scsi_done = done;
 
-#if IPS_DEBUG >= 10
-   printk(KERN_NOTICE "%s: ips_queue: cmd 0x%X (%d %d %d)\n",
-          ips_name,
-          SC->cmnd[0],
-          SC->channel,
-          SC->target,
-          SC->lun);
-#if IPS_DEBUG >= 11
-        MDELAY(2*IPS_ONE_SEC);
-#endif
-#endif
+   DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)",
+             ips_name,
+             ha->host_num,
+             SC->cmnd[0],
+             SC->channel,
+             SC->target,
+             SC->lun);
+
+   /* Check for command to initiator IDs */
+   if ((SC->channel > 0) && (SC->target == ha->ha_id[SC->channel])) {
+      SC->result = DID_NO_CONNECT << 16;
+      done(SC);
+
+      return (0);
+   }
 
 #ifndef NO_IPS_CMDLINE
    if (ips_is_passthru(SC)) {
       ips_copp_wait_item_t *scratch;
 
       /* allocate space for the scribble */
-      scratch = kmalloc(sizeof(ips_copp_wait_item_t), GFP_KERNEL);
+      scratch = kmalloc(sizeof(ips_copp_wait_item_t), GFP_ATOMIC);
 
       if (!scratch) {
          SC->result = DID_ERROR << 16;
@@ -1238,10 +1628,8 @@
       datasize = *((u32 *) &SC->cmnd[8]);
 
       if (copy_to_user(user_area, kern_area, datasize) > 0) {
-#if IPS_DEBUG_PT >= 1
-         printk(KERN_NOTICE "(%s%d) passthru failed - unable to copy out user data\n",
-                ips_name, ha->host_num);
-#endif
+         DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data",
+                   ips_name, ha->host_num);
 
          SC->result = DID_ERROR << 16;
          SC->scsi_done(SC);
@@ -1269,7 +1657,7 @@
    int               sectors;
    int               cylinders;
 
-   DBG("ips_biosparam");
+   METHOD_TRACE("ips_biosparam", 1);
 
    ha = (ips_ha_t *) disk->device->host->hostdata;
 
@@ -1295,10 +1683,8 @@
 
    cylinders = disk->capacity / (heads * sectors);
 
-#if IPS_DEBUG >= 2
-   printk(KERN_NOTICE "Geometry: heads: %d, sectors: %d, cylinders: %d\n",
-          heads, sectors, cylinders);
-#endif
+   DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
+             heads, sectors, cylinders);
 
    geom[0] = heads;
    geom[1] = sectors;
@@ -1309,6 +1695,40 @@
 
 /****************************************************************************/
 /*                                                                          */
+/* Routine Name: ips_select_queue_depth                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Select queue depths for the devices on the contoller                   */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs) {
+   Scsi_Device *device;
+   ips_ha_t    *ha;
+   int          count = 0;
+
+   ha = IPS_HA(host);
+
+   for (device = scsi_devs; device; device = device->next) {
+     if (device->host == host) {
+        if ((device->channel == 0) && (device->type == 0))
+           count++;
+     }
+   }
+
+   for (device = scsi_devs; device; device = device->next) {
+      if (device->host == host) {
+         if ((device->channel == 0) && (device->type == 0))
+            device->queue_depth = ha->max_cmds / count - 1;
+         else
+            device->queue_depth = 2;
+      }
+   }
+}
+
+/****************************************************************************/
+/*                                                                          */
 /* Routine Name: do_ipsintr                                                 */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -1321,7 +1741,7 @@
    ips_ha_t         *ha;
    u32               cpu_flags;
 
-   DBG("do_ipsintr");
+   METHOD_TRACE("do_ipsintr", 2);
 
    ha = (ips_ha_t *) dev_id;
 
@@ -1347,7 +1767,7 @@
       return;
    }
 
-   ips_intr(ha);
+   (*ha->func.intr)(ha);
 
    clear_bit(IPS_IN_INTR, &ha->flags);
 
@@ -1359,7 +1779,7 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_intr                                                   */
+/* Routine Name: ips_intr_copperhead                                        */
 /*                                                                          */
 /* Routine Description:                                                     */
 /*                                                                          */
@@ -1369,13 +1789,14 @@
 /*                                                                          */
 /****************************************************************************/
 void
-ips_intr(ips_ha_t *ha) {
+ips_intr_copperhead(ips_ha_t *ha) {
    ips_stat_t       *sp;
    ips_scb_t        *scb;
-   int               status;
+   IPS_STATUS        cstatus;
+   int               intrstatus;
    u32               cpu_flags;
 
-   DBG("ips_intr");
+   METHOD_TRACE("ips_intr", 2);
 
    if (!ha)
       return;
@@ -1384,16 +1805,36 @@
       return;
 
    IPS_HA_LOCK(cpu_flags);
-   while (ips_isintr(ha)) {
+
+   intrstatus = (*ha->func.isintr)(ha);
+
+   if (!intrstatus) {
+      /*
+       * Unexpected/Shared interrupt
+       */
+      IPS_HA_UNLOCK(cpu_flags);
+
+      return;
+   }
+
+   while (TRUE) {
       sp = &ha->sp;
 
-      if ((status = ips_chkstatus(ha)) < 0) {
-         /* unexpected interrupt - no ccb */
+      intrstatus = (*ha->func.isintr)(ha);
+
+      if (!intrstatus)
+         break;
+      else
+         cstatus.value = (*ha->func.statupd)(ha);
+
+      if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
          printk(KERN_WARNING "(%s%d) Spurious interrupt; no ccb.\n",
                 ips_name, ha->host_num);
-         continue ;
+
+         continue;
       }
 
+      ips_chkstatus(ha, &cstatus);
       scb = (ips_scb_t *) sp->scb_addr;
 
       /*
@@ -1403,27 +1844,103 @@
       IPS_HA_UNLOCK(cpu_flags);
       (*scb->callback) (ha, scb);
       IPS_HA_LOCK(cpu_flags);
-   }
+   } /* end while */
 
    IPS_HA_UNLOCK(cpu_flags);
 }
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_info                                                   */
+/* Routine Name: ips_intr_morpheus                                          */
 /*                                                                          */
 /* Routine Description:                                                     */
 /*                                                                          */
-/*   Return info about the driver                                           */
+/*   Polling interrupt handler                                              */
+/*                                                                          */
+/*   ASSUMES interrupts are disabled                                        */
 /*                                                                          */
 /****************************************************************************/
-const char *
-ips_info(struct Scsi_Host *SH) {
-   static char  buffer[256];
-   char        *bp;
-   ips_ha_t    *ha;
-
-   DBG("ips_info");
+void
+ips_intr_morpheus(ips_ha_t *ha) {
+   ips_stat_t       *sp;
+   ips_scb_t        *scb;
+   IPS_STATUS        cstatus;
+   int               intrstatus;
+   u32               cpu_flags;
+
+   METHOD_TRACE("ips_intr_morpheus", 2);
+
+   if (!ha)
+      return;
+
+   if (!ha->active)
+      return;
+
+   IPS_HA_LOCK(cpu_flags);
+
+   intrstatus = (*ha->func.isintr)(ha);
+
+   if (!intrstatus) {
+      /*
+       * Unexpected/Shared interrupt
+       */
+      IPS_HA_UNLOCK(cpu_flags);
+
+      return;
+   }
+
+   while (TRUE) {
+      sp = &ha->sp;
+
+      intrstatus = (*ha->func.isintr)(ha);
+
+      if (!intrstatus)
+         break;
+      else
+         cstatus.value = (*ha->func.statupd)(ha);
+
+      if (cstatus.value == 0xffffffff)
+         /* No more to process */
+         break;
+
+      if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
+         printk(KERN_WARNING "(%s%d) Spurious interrupt; no ccb.\n",
+                ips_name, ha->host_num);
+
+         continue;
+      }
+
+      ips_chkstatus(ha, &cstatus);
+      scb = (ips_scb_t *) sp->scb_addr;
+
+      /*
+       * use the callback function to finish things up
+       * NOTE: interrupts are OFF for this
+       */
+      IPS_HA_UNLOCK(cpu_flags);
+      (*scb->callback) (ha, scb);
+      IPS_HA_LOCK(cpu_flags);
+   } /* end while */
+
+   IPS_HA_UNLOCK(cpu_flags);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_info                                                   */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Return info about the driver                                           */
+/*                                                                          */
+/****************************************************************************/
+const char *
+ips_info(struct Scsi_Host *SH) {
+   static char  buffer[256];
+   char        *bp;
+   ips_ha_t    *ha;
+
+   METHOD_TRACE("ips_info", 1);
 
    ha = IPS_HA(SH);
 
@@ -1463,10 +1980,10 @@
    int           ret;
    ips_ha_t     *ha = NULL;
 
-   DBG("ips_proc_info");
+   METHOD_TRACE("ips_proc_info", 1);
 
    /* Find our host structure */
-   for (i = 0; i < ips_num_controllers; i++) {
+   for (i = 0; i < ips_next_controller; i++) {
       if (ips_sh[i] && ips_sh[i]->host_no == hostno) {
          ha = (ips_ha_t *) ips_sh[i]->hostdata;
 
@@ -1508,7 +2025,7 @@
 /****************************************************************************/
 static int
 ips_is_passthru(Scsi_Cmnd *SC) {
-   DBG("ips_is_passthru");
+   METHOD_TRACE("ips_is_passthru", 1);
 
    if (!SC)
       return (0);
@@ -1542,24 +2059,20 @@
 ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb) {
    ips_passthru_t *pt;
 
-   DBG("ips_make_passthru");
+   METHOD_TRACE("ips_make_passthru", 1);
 
    if (!SC->request_bufflen || !SC->request_buffer) {
       /* no data */
-#if IPS_DEBUG_PT >= 1
-      printk(KERN_NOTICE "(%s%d) No passthru structure\n",
-             ips_name, ha->host_num);
-#endif
+      DEBUG_VAR(1, "(%s%d) No passthru structure",
+                ips_name, ha->host_num);
 
       return (IPS_FAILURE);
    }
 
    if (SC->request_bufflen < sizeof(ips_passthru_t)) {
       /* wrong size */
-#if IPS_DEBUG_PT >= 1
-      printk(KERN_NOTICE "(%s%d) Passthru structure wrong size\n",
+      DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
              ips_name, ha->host_num);
-#endif
 
       return (IPS_FAILURE);
    }
@@ -1569,10 +2082,8 @@
        (((char *) SC->request_buffer)[2] != 'P') ||
        (((char *) SC->request_buffer)[3] != 'P')) {
       /* signature doesn't match */
-#if IPS_DEBUG_PT >= 1
-      printk(KERN_NOTICE "(%s%d) Wrong signature on passthru structure.\n",
-             ips_name, ha->host_num);
-#endif
+      DEBUG_VAR(1, "(%s%d) Wrong signature on passthru structure.",
+                ips_name, ha->host_num);
 
       return (IPS_FAILURE);
    }
@@ -1616,10 +2127,8 @@
       if (SC->cmnd[0] == IPS_IOCTL_COMMAND) {
          if (SC->request_bufflen < (sizeof(ips_passthru_t) + pt->CmdBSize)) {
             /* wrong size */
-   #if IPS_DEBUG_PT >= 1
-            printk(KERN_NOTICE "(%s%d) Passthru structure wrong size\n",
-                   ips_name, ha->host_num);
-   #endif
+            DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
+                      ips_name, ha->host_num);
 
             return (IPS_FAILURE);
          }
@@ -1631,10 +2140,8 @@
       } else if (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) {
          if (SC->request_bufflen < (sizeof(ips_passthru_t))) {
             /* wrong size */
-   #if IPS_DEBUG_PT >= 1
-            printk(KERN_NOTICE "(%s%d) Passthru structure wrong size\n",
-                   ips_name, ha->host_num);
-   #endif
+            DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
+                      ips_name, ha->host_num);
 
             return (IPS_FAILURE);
          }
@@ -1653,14 +2160,23 @@
          return (IPS_FAILURE);
 
       /* don't flash the BIOS on future cards */
-      if (ha->revision_id > IPS_REVID_TROMBONE64) {
-#if IPS_DEBUG_PT >= 1
-         printk(KERN_NOTICE "(%s%d) flash bios failed - unsupported controller\n",
-                ips_name, ha->host_num);
-#endif
+      if ((ha->device_id != IPS_COPPERHEAD_DEVICEID) ||
+          (ha->revision_id > IPS_REVID_TROMBONE64)) {
+         DEBUG_VAR(1, "(%s%d) flash bios failed - unsupported controller",
+                   ips_name, ha->host_num);
+
          return (IPS_FAILURE);
       }
 
+      /*
+       * Check to make sure we have functions
+       * to handle the request
+       */
+      if ((!ha->func.programbios) ||
+          (!ha->func.erasebios) ||
+          (!ha->func.verifybios))
+         return (IPS_FAILURE);
+
       /* copy in the size/buffer ptr from the scsi command */
       memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4);
       memcpy(&pt->CmdBSize, &SC->cmnd[8], 4);
@@ -1674,7 +2190,7 @@
          void *bigger_struct;
 
          /* try to allocate a bigger struct */
-         bigger_struct = kmalloc(pt->CmdBSize, GFP_KERNEL|GFP_DMA);
+         bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA);
          if (bigger_struct) {
             /* free the old memory */
             kfree(ha->ioctl_data);
@@ -1688,37 +2204,29 @@
 
       /* copy in the buffer */
       if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) {
-#if IPS_DEBUG_PT >= 1
-         printk(KERN_NOTICE "(%s%d) flash bios failed - unable to copy user buffer\n",
-                ips_name, ha->host_num);
-#endif
+         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer",
+                   ips_name, ha->host_num);
 
          return (IPS_FAILURE);
       }
 
-      if (ips_erase_bios(ha)) {
-#if IPS_DEBUG_PT >= 1
-         printk(KERN_NOTICE "(%s%d) flash bios failed - unable to erase flash\n",
-                ips_name, ha->host_num);
-#endif
+      if ((*ha->func.erasebios)(ha)) {
+         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash",
+                   ips_name, ha->host_num);
 
          return (IPS_FAILURE);
       }
 
-      if (ips_program_bios(ha, ha->ioctl_data, pt->CmdBSize)) {
-#if IPS_DEBUG_PT >= 1
-         printk(KERN_NOTICE "(%s%d) flash bios failed - unable to program flash\n",
-                ips_name, ha->host_num);
-#endif
+      if ((*ha->func.programbios)(ha, ha->ioctl_data, pt->CmdBSize)) {
+         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash",
+                   ips_name, ha->host_num);
 
          return (IPS_FAILURE);
       }
 
-      if (ips_verify_bios(ha, ha->ioctl_data, pt->CmdBSize)) {
-#if IPS_DEBUG_PT >= 1
-         printk(KERN_NOTICE "(%s%d) flash bios failed - unable to verify flash\n",
-                ips_name, ha->host_num);
-#endif
+      if ((*ha->func.verifybios)(ha, ha->ioctl_data, pt->CmdBSize)) {
+         DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash",
+                   ips_name, ha->host_num);
 
          return (IPS_FAILURE);
       }
@@ -1742,7 +2250,7 @@
 ips_usrcmd(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb) {
    IPS_SG_LIST *sg_list;
 
-   DBG("ips_usrcmd");
+   METHOD_TRACE("ips_usrcmd", 1);
 
    if ((!scb) || (!pt) || (!ha))
       return (0);
@@ -1825,7 +2333,7 @@
    char           *kern_area;
    u32             datasize;
 
-   DBG("ips_usrcmd");
+   METHOD_TRACE("ips_usrcmd", 1);
 
    if ((!scb) || (!pt) || (!ha))
       return (0);
@@ -1862,7 +2370,7 @@
          void *bigger_struct;
 
          /* try to allocate a bigger struct */
-         bigger_struct = kmalloc(pt->CmdBSize, GFP_KERNEL|GFP_DMA);
+         bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA);
          if (bigger_struct) {
             /* free the old memory */
             kfree(ha->ioctl_data);
@@ -1883,10 +2391,8 @@
       datasize = *((u32 *) &scb->scsi_cmd->cmnd[8]);
 
       if (copy_from_user(kern_area, user_area, datasize) > 0) {
-#if IPS_DEBUG_PT >= 1
-         printk(KERN_NOTICE "(%s%d) passthru failed - unable to copy in user data\n",
-                ips_name, ha->host_num);
-#endif
+         DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy in user data",
+                   ips_name, ha->host_num);
 
          return (0);
       }
@@ -1937,12 +2443,11 @@
 ips_cleanup_passthru(ips_ha_t *ha, ips_scb_t *scb) {
    ips_passthru_t *pt;
 
-   DBG("ips_cleanup_passthru");
+   METHOD_TRACE("ips_cleanup_passthru", 1);
 
    if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) {
-#if IPS_DEBUG_PT >= 1
-      printk(KERN_NOTICE "IPS couldn't cleanup\n");
-#endif
+      DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
+                ips_name, ha->host_num);
 
       return ;
    }
@@ -1976,12 +2481,13 @@
 ips_host_info(ips_ha_t *ha, char *ptr, off_t offset, int len) {
    IPS_INFOSTR info;
 
-   DBG("ips_host_info");
+   METHOD_TRACE("ips_host_info", 1);
 
    info.buffer = ptr;
    info.length = len;
    info.offset = offset;
    info.pos = 0;
+   info.localpos = 0;
 
    copy_info(&info, "\nIBM ServeRAID General Information:\n\n");
 
@@ -1991,7 +2497,16 @@
    else
       copy_info(&info, "\tController Type                   : Unknown\n");
 
-   copy_info(&info, "\tIO port address                   : 0x%lx\n", ha->io_addr);
+   if (ha->io_addr)
+      copy_info(&info, "\tIO region                         : 0x%lx (%d bytes)\n",
+                ha->io_addr, ha->io_len);
+
+   if (ha->mem_addr) {
+      copy_info(&info, "\tMemory region                     : 0x%lx (%d bytes)\n",
+                ha->mem_addr, ha->mem_len);
+      copy_info(&info, "\tShared memory address             : 0x%lx\n", ha->mem_ptr);
+   }
+
    copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
 
    if (ha->nvram->signature == IPS_NVRAM_P5_SIG)
@@ -2031,7 +2546,7 @@
 
    copy_info(&info, "\n");
 
-   return (info.pos > info.offset ? info.pos - info.offset : 0);
+   return (info.localpos);
 }
 
 /****************************************************************************/
@@ -2045,10 +2560,7 @@
 /****************************************************************************/
 static void
 copy_mem_info(IPS_INFOSTR *info, char *data, int len) {
-   DBG("copy_mem_info");
-
-   if (info->pos + len > info->length)
-      len = info->length - info->pos;
+   METHOD_TRACE("copy_mem_info", 1);
 
    if (info->pos + len < info->offset) {
       info->pos += len;
@@ -2057,12 +2569,17 @@
 
    if (info->pos < info->offset) {
       data += (info->offset - info->pos);
-      len  -= (info->offset - info->pos);
+      len -= (info->offset - info->pos);
+      info->pos += (info->offset - info->pos);
    }
 
+   if (info->localpos + len > info->length)
+      len = info->length - info->localpos;
+
    if (len > 0) {
-      memcpy(info->buffer + info->pos, data, len);
+      memcpy(info->buffer + info->localpos, data, len);
       info->pos += len;
+      info->localpos += len;
    }
 }
 
@@ -2078,10 +2595,10 @@
 static int
 copy_info(IPS_INFOSTR *info, char *fmt, ...) {
    va_list args;
-   char buf[81];
+   char buf[128];
    int len;
 
-   DBG("copy_info");
+   METHOD_TRACE("copy_info", 1);
 
    va_start(args, fmt);
    len = vsprintf(buf, fmt, args);
@@ -2105,57 +2622,32 @@
 /****************************************************************************/
 static int
 ips_hainit(ips_ha_t *ha) {
-   int       i;
+   int            i;
+   struct timeval tv;
 
-   DBG("ips_hainit");
+   METHOD_TRACE("ips_hainit", 1);
 
    if (!ha)
       return (0);
 
-   /* initialize status queue */
-   ips_statinit(ha);
+   if (ha->func.statinit)
+      (*ha->func.statinit)(ha);
+
+   if (ha->func.enableint)
+      (*ha->func.enableint)(ha);
 
+   /* Send FFDC */
    ha->reset_count = 1;
+   do_gettimeofday(&tv);
+   ha->last_ffdc = tv.tv_sec;
+   ips_ffdc_reset(ha, IPS_INTR_IORL);
 
-   /* Setup HBA ID's */
    if (!ips_read_config(ha, IPS_INTR_IORL)) {
-
-#ifndef NO_IPS_RESET
-
-      ha->reset_count++;
-
-      /* Try to reset the controller and try again */
-      if (!ips_reset_adapter(ha)) {
-         printk(KERN_WARNING "(%s%d) unable to reset controller.\n",
-                ips_name, ha->host_num);
-
-         return (0);
-      }
-
-      if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
-         printk(KERN_WARNING "(%s%d) unable to initialize controller.\n",
-                ips_name, ha->host_num);
-
-         return (0);
-      }
-
-#endif
-
-      if (!ips_read_config(ha, IPS_INTR_IORL)) {
-         printk(KERN_WARNING "(%s%d) unable to read config from controller.\n",
-                ips_name, ha->host_num);
-
-         return (0);
-      }
-   } /* end if */
-
-   /* write driver version */
-   if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
-      printk(KERN_WARNING "(%s%d) unable to write driver info to controller.\n",
+      printk(KERN_WARNING "(%s%d) unable to read config from controller.\n",
              ips_name, ha->host_num);
 
       return (0);
-   }
+   } /* end if */
 
    if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) {
       printk(KERN_WARNING "(%s%d) unable to read controller status.\n",
@@ -2171,19 +2663,18 @@
       return (0);
    }
 
-   /* FFDC */
-   if (ha->subsys->param[3] & 0x300000) {
-      struct timeval tv;
+   /* write nvram user page 5 */
+   if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
+      printk(KERN_WARNING "(%s%d) unable to write driver info to controller.\n",
+             ips_name, ha->host_num);
 
-      do_gettimeofday(&tv);
-      ha->last_ffdc = tv.tv_sec;
-      ips_ffdc_reset(ha, IPS_INTR_IORL);
+      return (0);
    }
 
    /* set limits on SID, LUN, BUS */
    ha->ntargets = IPS_MAX_TARGETS + 1;
    ha->nlun = 1;
-   ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS);
+   ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1;
 
    switch (ha->conf->logical_drive[0].ucStripeSize) {
    case 4:
@@ -2254,13 +2745,14 @@
    ips_scb_t            *scb;
    Scsi_Cmnd            *SC;
    Scsi_Cmnd            *p;
+   Scsi_Cmnd            *q;
    ips_copp_wait_item_t *item;
    int                   ret;
    int                   intr_status;
    u32                   cpu_flags;
    u32                   cpu_flags2;
 
-   DBG("ips_next");
+   METHOD_TRACE("ips_next", 1);
 
    if (!ha)
       return ;
@@ -2406,7 +2898,8 @@
 
       IPS_HA_UNLOCK(cpu_flags);
 
-      SC = ips_removeq_wait(&ha->scb_waitlist, p);
+      q = p;
+      SC = ips_removeq_wait(&ha->scb_waitlist, q);
 
       SC->result = DID_OK;
       SC->host_scribble = NULL;
@@ -2433,28 +2926,41 @@
 
          sg = SC->request_buffer;
 
-         for (i = 0; i < SC->use_sg; i++) {
-            scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
-            scb->sg_list[i].length = sg[i].length;
+         if (SC->use_sg == 1) {
+            if (sg[0].length > ha->max_xfer) {
+               scb->breakup = 1;
+               scb->data_len = ha->max_xfer;
+            } else
+               scb->data_len = sg[0].length;
 
-            if (scb->data_len + sg[i].length > ha->max_xfer) {
-               /*
-                * Data Breakup required
-                */
-               scb->breakup = i;
-               break;
-            }
+            scb->dcdb.transfer_length = scb->data_len;
+            scb->data_busaddr = VIRT_TO_BUS(sg[0].address);
+            scb->sg_len = 0;
+         } else {
 
-            scb->data_len += sg[i].length;
-         }
+            for (i = 0; i < SC->use_sg; i++) {
+               scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
+               scb->sg_list[i].length = sg[i].length;
 
-         if (!scb->breakup)
-            scb->sg_len = SC->use_sg;
-         else
-            scb->sg_len = scb->breakup;
+               if (scb->data_len + sg[i].length > ha->max_xfer) {
+                  /*
+                   * Data Breakup required
+                   */
+                  scb->breakup = i;
+                  break;
+               }
+
+               scb->data_len += sg[i].length;
+            }
+
+            if (!scb->breakup)
+               scb->sg_len = SC->use_sg;
+            else
+               scb->sg_len = scb->breakup;
 
-         scb->dcdb.transfer_length = scb->data_len;
-         scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
+            scb->dcdb.transfer_length = scb->data_len;
+            scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
+         }
       } else {
          if (SC->request_bufflen) {
             if (SC->request_bufflen > ha->max_xfer) {
@@ -2541,7 +3047,7 @@
 /****************************************************************************/
 static inline void
 ips_putq_scb_head(ips_scb_queue_t *queue, ips_scb_t *item) {
-   DBG("ips_putq_scb_head");
+   METHOD_TRACE("ips_putq_scb_head", 1);
 
    if (!item)
       return ;
@@ -2572,7 +3078,7 @@
 /****************************************************************************/
 static inline void
 ips_putq_scb_tail(ips_scb_queue_t *queue, ips_scb_t *item) {
-   DBG("ips_putq_scb_tail");
+   METHOD_TRACE("ips_putq_scb_tail", 1);
 
    if (!item)
       return ;
@@ -2609,7 +3115,7 @@
 ips_removeq_scb_head(ips_scb_queue_t *queue) {
    ips_scb_t  *item;
 
-   DBG("ips_removeq_scb_head");
+   METHOD_TRACE("ips_removeq_scb_head", 1);
 
    IPS_QUEUE_LOCK(queue);
 
@@ -2649,7 +3155,7 @@
 ips_removeq_scb(ips_scb_queue_t *queue, ips_scb_t *item) {
    ips_scb_t  *p;
 
-   DBG("ips_removeq_scb");
+   METHOD_TRACE("ips_removeq_scb", 1);
 
    if (!item)
       return (NULL);
@@ -2700,7 +3206,7 @@
 /****************************************************************************/
 static inline void
 ips_putq_wait_head(ips_wait_queue_t *queue, Scsi_Cmnd *item) {
-   DBG("ips_putq_wait_head");
+   METHOD_TRACE("ips_putq_wait_head", 1);
 
    if (!item)
       return ;
@@ -2731,7 +3237,7 @@
 /****************************************************************************/
 static inline void
 ips_putq_wait_tail(ips_wait_queue_t *queue, Scsi_Cmnd *item) {
-   DBG("ips_putq_wait_tail");
+   METHOD_TRACE("ips_putq_wait_tail", 1);
 
    if (!item)
       return ;
@@ -2768,7 +3274,7 @@
 ips_removeq_wait_head(ips_wait_queue_t *queue) {
    Scsi_Cmnd  *item;
 
-   DBG("ips_removeq_wait_head");
+   METHOD_TRACE("ips_removeq_wait_head", 1);
 
    IPS_QUEUE_LOCK(queue);
 
@@ -2808,7 +3314,7 @@
 ips_removeq_wait(ips_wait_queue_t *queue, Scsi_Cmnd *item) {
    Scsi_Cmnd  *p;
 
-   DBG("ips_removeq_wait");
+   METHOD_TRACE("ips_removeq_wait", 1);
 
    if (!item)
       return (NULL);
@@ -2859,7 +3365,7 @@
 /****************************************************************************/
 static inline void
 ips_putq_copp_head(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) {
-   DBG("ips_putq_copp_head");
+   METHOD_TRACE("ips_putq_copp_head", 1);
 
    if (!item)
       return ;
@@ -2890,7 +3396,7 @@
 /****************************************************************************/
 static inline void
 ips_putq_copp_tail(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) {
-   DBG("ips_putq_copp_tail");
+   METHOD_TRACE("ips_putq_copp_tail", 1);
 
    if (!item)
       return ;
@@ -2927,7 +3433,7 @@
 ips_removeq_copp_head(ips_copp_queue_t *queue) {
    ips_copp_wait_item_t *item;
 
-   DBG("ips_removeq_copp_head");
+   METHOD_TRACE("ips_removeq_copp_head", 1);
 
    IPS_QUEUE_LOCK(queue);
 
@@ -2967,7 +3473,7 @@
 ips_removeq_copp(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) {
    ips_copp_wait_item_t *p;
 
-   DBG("ips_removeq_copp");
+   METHOD_TRACE("ips_removeq_copp", 1);
 
    if (!item)
       return (NULL);
@@ -3016,7 +3522,7 @@
 /****************************************************************************/
 static void
 ipsintr_blocking(ips_ha_t *ha, ips_scb_t *scb) {
-   DBG("ipsintr_blocking");
+   METHOD_TRACE("ipsintr_blocking", 2);
 
    if ((ha->waitflag == TRUE) &&
        (ha->cmd_in_progress == scb->cdb[0])) {
@@ -3037,7 +3543,14 @@
 /****************************************************************************/
 static void
 ipsintr_done(ips_ha_t *ha, ips_scb_t *scb) {
-   DBG("ipsintr_done");
+   METHOD_TRACE("ipsintr_done", 2);
+
+   if (!scb) {
+      printk(KERN_WARNING "(%s%d) Spurious interrupt; scb NULL.\n",
+             ips_name, ha->host_num);
+
+      return ;
+   }
 
    if (scb->scsi_cmd == NULL) {
       /* unexpected interrupt */
@@ -3064,7 +3577,7 @@
    int ret;
    u32 cpu_flags;
 
-   DBG("ips_done");
+   METHOD_TRACE("ips_done", 1);
 
    if (!scb)
       return ;
@@ -3096,31 +3609,46 @@
 
             sg = scb->scsi_cmd->request_buffer;
 
-            scb->data_len = 0;
-
-            for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) {
-               scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address);
-               scb->sg_list[i - bk_save].length = sg[i].length;
-
-               if (scb->data_len + sg[i].length > ha->max_xfer) {
-                  /*
-                   * Data Breakup required
-                   */
-                  scb->breakup = i;
-                  break;
+            if (scb->scsi_cmd->use_sg == 1) {
+               if (sg[0].length - (bk_save * ha->max_xfer)) {
+                  /* Further breakup required */
+                  scb->data_len = ha->max_xfer;
+                  scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer));
+                  scb->breakup = bk_save + 1;
+               } else {
+                  scb->data_len = sg[0].length - (bk_save * ha->max_xfer);
+                  scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer));
                }
 
-               scb->data_len += sg[i].length;
-            }
+               scb->dcdb.transfer_length = scb->data_len;
+               scb->sg_len = 0;
+            } else {
+               scb->data_len = 0;
 
-            if (!scb->breakup)
-               scb->sg_len = scb->scsi_cmd->use_sg - bk_save;
-            else
-               scb->sg_len = scb->breakup - bk_save;
+               for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) {
+                  scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address);
+                  scb->sg_list[i - bk_save].length = sg[i].length;
+
+                  if (scb->data_len + sg[i].length > ha->max_xfer) {
+                     /*
+                      * Data Breakup required
+                      */
+                     scb->breakup = i;
+                     break;
+                  }
 
-            scb->dcdb.transfer_length = scb->data_len;
-            scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
-         } else {
+                  scb->data_len += sg[i].length;
+               }
+
+               if (!scb->breakup)
+                  scb->sg_len = scb->scsi_cmd->use_sg - bk_save;
+               else
+                  scb->sg_len = scb->breakup - bk_save;
+
+               scb->dcdb.transfer_length = scb->data_len;
+               scb->data_busaddr = VIRT_TO_BUS(scb->sg_list);
+           }
+        } else {
             /* Non S/G Request */
             if (scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) {
                /* Further breakup required */
@@ -3199,31 +3727,29 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_map_status(ips_scb_t *scb, ips_stat_t *sp) {
+ips_map_status(ips_ha_t *ha, ips_scb_t *scb, ips_stat_t *sp) {
    int       errcode;
+   int       device_error;
 
-   DBG("ips_map_status");
+   METHOD_TRACE("ips_map_status", 1);
 
    if (scb->bus) {
-#if IPS_DEBUG >= 10
-      printk(KERN_NOTICE "(%s) Physical device error: %x %x, Sense Key: %x, ASC: %x, ASCQ: %x\n",
-             ips_name,
-             scb->basic_status,
-             scb->extended_status,
-             scb->dcdb.sense_info[2] & 0xf,
-             scb->dcdb.sense_info[12],
-             scb->dcdb.sense_info[13]);
-#endif
-
-      /* copy SCSI status and sense data for DCDB commands */
-      memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
-             sizeof(scb->scsi_cmd->sense_buffer));
-      scb->scsi_cmd->result = scb->dcdb.scsi_status;
-   } else
-      scb->scsi_cmd->result = 0;
+      DEBUG_VAR(2, "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x",
+                ips_name,
+                ha->host_num,
+                scb->scsi_cmd->channel,
+                scb->scsi_cmd->target,
+                scb->scsi_cmd->lun,
+                scb->basic_status,
+                scb->extended_status,
+                scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0,
+                scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0,
+                scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0);
+   }
 
    /* default driver error */
    errcode = DID_ERROR;
+   device_error = 0;
 
    switch (scb->basic_status & IPS_GSC_STATUS_MASK) {
    case IPS_CMD_TIMEOUT:
@@ -3238,25 +3764,19 @@
       break;
 
    case IPS_PHYS_DRV_ERROR:
-      /*
-       * For physical drive errors that
-       * are not on a logical drive should
-       * be DID_OK.  The SCSI errcode will
-       * show what the real error is.
-       */
-      if (scb->bus)
-         errcode = DID_OK;
-
       switch (scb->extended_status) {
       case IPS_ERR_SEL_TO:
-         if (scb->bus) {
-            scb->scsi_cmd->result |= DID_TIME_OUT << 16;
+         if (scb->bus)
+            errcode = DID_NO_CONNECT;
 
-            return (0);
-         }
          break;
+
       case IPS_ERR_OU_RUN:
          if ((scb->bus) && (scb->dcdb.transfer_length < scb->data_len)) {
+            /* Underrun - set default to no error */
+            errcode = DID_OK;
+
+            /* Restrict access to physical DASD */
             if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
                 ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == TYPE_DISK)) {
                /* underflow -- no error               */
@@ -3264,23 +3784,16 @@
                errcode = DID_TIME_OUT;
                break;
             }
-
-            /* normal underflow Occured */
-            if (scb->dcdb.transfer_length >= scb->scsi_cmd->underflow) {
-               scb->scsi_cmd->result |= DID_OK << 16;
-
-               return (0);
-            }
-         }
+         } else
+            errcode = DID_ERROR;
 
          break;
+
       case IPS_ERR_RECOVERY:
          /* don't fail recovered errors */
-         if (scb->bus) {
-            scb->scsi_cmd->result |= DID_OK << 16;
+         if (scb->bus)
+            errcode = DID_OK;
 
-            return (0);
-         }
          break;
 
       case IPS_ERR_HOST_RESET:
@@ -3289,11 +3802,25 @@
          break;
 
       case IPS_ERR_CKCOND:
+         if (scb->bus) {
+            memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info,
+                   sizeof(scb->scsi_cmd->sense_buffer));
+
+            device_error = 2; /* check condition */
+         }
+
+         errcode = DID_OK;
+
+         break;
+
+      default:
+         errcode = DID_ERROR;
          break;
+
       } /* end switch */
    } /* end switch */
 
-   scb->scsi_cmd->result |= (errcode << 16);
+   scb->scsi_cmd->result = device_error | (errcode << 16);
 
    return (1);
 }
@@ -3311,7 +3838,7 @@
 ips_send(ips_ha_t *ha, ips_scb_t *scb, ips_scb_callback callback) {
    int ret;
 
-   DBG("ips_send");
+   METHOD_TRACE("ips_send", 1);
 
    scb->callback = callback;
 
@@ -3333,7 +3860,7 @@
 ips_send_wait(ips_ha_t *ha, ips_scb_t *scb, int timeout, int intr) {
    int       ret;
 
-   DBG("ips_send_wait");
+   METHOD_TRACE("ips_send_wait", 1);
 
    ha->waitflag = TRUE;
    ha->cmd_in_progress = scb->cdb[0];
@@ -3361,7 +3888,7 @@
 ips_send_cmd(ips_ha_t *ha, ips_scb_t *scb) {
    int       ret;
 
-   DBG("ips_send_cmd");
+   METHOD_TRACE("ips_send_cmd", 1);
 
    ret = IPS_SUCCESS;
 
@@ -3590,7 +4117,7 @@
       memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len);
    }
 
-   return (ips_issue(ha, scb));
+   return ((*ha->func.issue)(ha, scb));
 }
 
 /****************************************************************************/
@@ -3602,60 +4129,57 @@
 /*   Check the status of commands to logical drives                         */
 /*                                                                          */
 /****************************************************************************/
-static int
-ips_chkstatus(ips_ha_t *ha) {
+static void
+ips_chkstatus(ips_ha_t *ha, IPS_STATUS *pstatus) {
    ips_scb_t  *scb;
-   ips_stat_t *sp = &ha->sp;
+   ips_stat_t *sp;
    u8          basic_status;
    u8          ext_status;
-   int         command_id;
    int         errcode;
-   int         ret;
 
-   DBG("ips_chkstatus");
+   METHOD_TRACE("ips_chkstatus", 1);
 
-   command_id = ips_statupd(ha);
+   scb = &ha->scbs[pstatus->fields.command_id];
+   scb->basic_status = basic_status = pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK;
+   scb->extended_status = ext_status = pstatus->fields.extended_status;
 
-   if (command_id > (IPS_MAX_CMDS-1)) {
-      printk(KERN_NOTICE "(%s%d) invalid command id received: %d\n",
-             ips_name, ha->host_num, command_id);
-
-      return (-1);
-   }
-
-   scb = &ha->scbs[command_id];
-   sp->scb_addr = (u32) scb;
+   sp = &ha->sp;
    sp->residue_len = 0;
-   scb->basic_status = basic_status = ha->adapt->p_status_tail->basic_status & IPS_BASIC_STATUS_MASK;
-   scb->extended_status = ext_status = ha->adapt->p_status_tail->extended_status;
+   sp->scb_addr = (u32) scb;
 
    /* Remove the item from the active queue */
    ips_removeq_scb(&ha->scb_activelist, scb);
 
    if (!scb->scsi_cmd)
       /* internal commands are handled in do_ipsintr */
-      return (0);
+      return ;
+
+   DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)",
+             ips_name,
+             ha->host_num,
+             scb->cdb[0],
+             scb->cmd.basic_io.command_id,
+             scb->bus,
+             scb->target_id,
+             scb->lun);
 
 #ifndef NO_IPS_CMDLINE
    if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd)))
       /* passthru - just returns the raw result */
-      return (0);
+      return ;
 #endif
 
    errcode = DID_OK;
-   ret = 0;
 
    if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) ||
        ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) {
 
       if (scb->bus == 0) {
-#if IPS_DEBUG >= 1
          if ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR) {
-            printk(KERN_NOTICE "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x\n",
-                   ips_name, ha->host_num,
-                   scb->cmd.basic_io.op_code, basic_status, ext_status);
+            DEBUG_VAR(1, "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
+                      ips_name, ha->host_num,
+                      scb->cmd.basic_io.op_code, basic_status, ext_status);
          }
-#endif
 
          switch (scb->scsi_cmd->cmnd[0]) {
          case ALLOW_MEDIUM_REMOVAL:
@@ -3664,7 +4188,6 @@
          case WRITE_FILEMARKS:
          case SPACE:
             errcode = DID_ERROR;
-            ret = 1;
             break;
 
          case START_STOP:
@@ -3673,7 +4196,6 @@
          case TEST_UNIT_READY:
             if (!ips_online(ha, scb)) {
                errcode = DID_TIME_OUT;
-               ret = 1;
             }
             break;
 
@@ -3682,7 +4204,6 @@
                ips_inquiry(ha, scb);
             } else {
                errcode = DID_TIME_OUT;
-               ret = 1;
             }
             break;
 
@@ -3701,7 +4222,6 @@
          case MODE_SENSE:
             if (!ips_online(ha, scb) || !ips_msense(ha, scb)) {
                errcode = DID_ERROR;
-               ret = 1;
             }
             break;
 
@@ -3710,7 +4230,6 @@
                ips_rdcap(ha, scb);
             else {
                errcode = DID_TIME_OUT;
-               ret = 1;
             }
             break;
 
@@ -3720,7 +4239,6 @@
 
          case FORMAT_UNIT:
             errcode = DID_ERROR;
-            ret = 1;
             break;
 
          case SEEK_10:
@@ -3732,7 +4250,6 @@
 
          default:
             errcode = DID_ERROR;
-            ret = 1;
          } /* end switch */
 
          scb->scsi_cmd->result = errcode << 16;
@@ -3742,23 +4259,17 @@
              ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == TYPE_DISK)) {
 
             scb->scsi_cmd->result = DID_TIME_OUT << 16;
-
-            ret = 1;
          }
       } /* else */
    } else { /* recovered error / success */
-#if IPS_DEBUG >= 1
       if (scb->bus == 0) {
-         printk(KERN_NOTICE "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x\n",
-                ips_name, ha->host_num,
-                scb->cmd.basic_io.op_code, basic_status, ext_status);
+         DEBUG_VAR(1, "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
+                   ips_name, ha->host_num,
+                   scb->cmd.basic_io.op_code, basic_status, ext_status);
       }
-#endif
 
-      ret = ips_map_status(scb, sp);
+      ips_map_status(ha, scb, sp);
    } /* else */
-
-   return (ret);
 }
 
 /****************************************************************************/
@@ -3772,7 +4283,7 @@
 /****************************************************************************/
 static int
 ips_online(ips_ha_t *ha, ips_scb_t *scb) {
-   DBG("ips_online");
+   METHOD_TRACE("ips_online", 1);
 
    if (scb->target_id >= IPS_MAX_LD)
       return (0);
@@ -3806,7 +4317,7 @@
 ips_inquiry(ips_ha_t *ha, ips_scb_t *scb) {
    IPS_INQ_DATA inq;
 
-   DBG("ips_inquiry");
+   METHOD_TRACE("ips_inquiry", 1);
 
    memset(&inq, 0, sizeof(IPS_INQ_DATA));
 
@@ -3837,7 +4348,7 @@
 ips_rdcap(ips_ha_t *ha, ips_scb_t *scb) {
    IPS_CAPACITY *cap;
 
-   DBG("ips_rdcap");
+   METHOD_TRACE("ips_rdcap", 1);
 
    if (scb->scsi_cmd->bufflen < 8)
       return (0);
@@ -3866,7 +4377,7 @@
    u32          cylinders;
    ips_mdata_t  mdata;
 
-   DBG("ips_msense");
+   METHOD_TRACE("ips_msense", 1);
 
    if (ha->enq->ulDriveSize[scb->target_id] > 0x400000 &&
        (ha->enq->ucMiscFlag & 0x8) == 0) {
@@ -3944,7 +4455,7 @@
 ips_reqsen(ips_ha_t *ha, ips_scb_t *scb) {
    char *sp;
 
-   DBG("ips_reqsen");
+   METHOD_TRACE("ips_reqsen", 1);
 
    sp = (char *) scb->scsi_cmd->sense_buffer;
    memset(sp, 0, sizeof(scb->scsi_cmd->sense_buffer));
@@ -3970,7 +4481,7 @@
 ips_free(ips_ha_t *ha) {
    int i;
 
-   DBG("ips_free");
+   METHOD_TRACE("ips_free", 1);
 
    if (ha) {
       if (ha->enq) {
@@ -4018,6 +4529,14 @@
          kfree(ha->scbs);
          ha->scbs = NULL;
       } /* end if */
+
+      /* free memory mapped (if applicable) */
+      if (ha->mem_ptr) {
+         iounmap(ha->ioremap_ptr);
+         ha->ioremap_ptr = NULL;
+         ha->mem_ptr = NULL;
+         ha->mem_addr = 0;
+      }
    }
 }
 
@@ -4035,10 +4554,10 @@
    ips_scb_t *scb_p;
    int        i;
 
-   DBG("ips_allocatescbs");
+   METHOD_TRACE("ips_allocatescbs", 1);
 
    /* Allocate memory for the CCBs */
-   ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_KERNEL|GFP_DMA);
+   ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA);
 
    memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t));
 
@@ -4046,7 +4565,7 @@
       scb_p = &ha->scbs[i];
 
       /* allocate S/G list */
-      scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_KERNEL|GFP_DMA);
+      scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC|GFP_DMA);
 
       if (! scb_p->sg_list)
          return (0);
@@ -4075,7 +4594,7 @@
 ips_init_scb(ips_ha_t *ha, ips_scb_t *scb) {
    IPS_SG_LIST *sg_list;
 
-   DBG("ips_init_scb");
+   METHOD_TRACE("ips_init_scb", 1);
 
    if (scb == NULL)
       return ;
@@ -4116,7 +4635,7 @@
    ips_scb_t     *scb;
    u32            cpu_flags;
 
-   DBG("ips_getscb");
+   METHOD_TRACE("ips_getscb", 1);
 
    IPS_SCB_LOCK(cpu_flags);
    if ((scb = ha->scb_freelist) == NULL) {
@@ -4150,7 +4669,7 @@
 ips_freescb(ips_ha_t *ha, ips_scb_t *scb) {
    u32          cpu_flags;
 
-   DBG("ips_freescb");
+   METHOD_TRACE("ips_freescb", 1);
 
    /* check to make sure this is not our "special" scb */
    if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
@@ -4163,7 +4682,7 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_reset_adapter                                          */
+/* Routine Name: ips_isinit_copperhead                                      */
 /*                                                                          */
 /* Routine Description:                                                     */
 /*                                                                          */
@@ -4171,21 +4690,402 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_reset_adapter(ips_ha_t *ha) {
-   u8  Isr;
+ips_isinit_copperhead(ips_ha_t *ha) {
+   u8 scpr;
+   u8 isr;
+
+   METHOD_TRACE("ips_isinit_copperhead", 1);
+
+   isr = inb(ha->io_addr + IPS_REG_HISR);
+   scpr = inb(ha->io_addr + IPS_REG_SCPR);
+
+   if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
+       return (0);
+   else
+       return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_isinit_copperhead_memio                                */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Reset the controller                                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isinit_copperhead_memio(ips_ha_t *ha) {
+   u8 isr;
+   u8 scpr;
+
+   METHOD_TRACE("ips_is_init_copperhead_memio", 1);
+
+   isr = readb(ha->mem_ptr + IPS_REG_HISR);
+   scpr = readb(ha->mem_ptr + IPS_REG_SCPR);
+
+   if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
+       return (0);
+   else
+       return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_isinit_morpheus                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Reset the controller                                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isinit_morpheus(ips_ha_t *ha) {
+   u32 post;
+   u32 bits;
+
+   METHOD_TRACE("ips_is_init_morpheus", 1);
+
+   post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+   bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+   if (post == 0)
+       return (0);
+   else if (bits & 0x3)
+       return (0);
+   else
+       return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_enable_int_copperhead                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Turn on interrupts                                                     */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_enable_int_copperhead(ips_ha_t *ha) {
+   METHOD_TRACE("ips_enable_int_copperhead", 1);
+
+   outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_enable_int_copperhead_memio                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Turn on interrupts                                                     */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_enable_int_copperhead_memio(ips_ha_t *ha) {
+   METHOD_TRACE("ips_enable_int_copperhead_memio", 1);
+
+   writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_enable_int_morpheus                                    */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Turn on interrupts                                                     */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_enable_int_morpheus(ips_ha_t *ha) {
+   u32              Oimr;
+
+   METHOD_TRACE("ips_enable_int_morpheus", 1);
+
+   Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
+   Oimr &= ~0x08;
+   writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_init_copperhead                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize a copperhead controller                                     */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_init_copperhead(ips_ha_t *ha) {
+   u8  Isr;
+   u8  Cbsp;
+   u8  PostByte[IPS_MAX_POST_BYTES];
+   u8  ConfigByte[IPS_MAX_CONFIG_BYTES];
+   int i, j;
+
+   METHOD_TRACE("ips_init_copperhead", 1);
+
+   for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
+      for (j = 0; j < 45; j++) {
+         Isr = inb(ha->io_addr + IPS_REG_HISR);
+         if (Isr & IPS_BIT_GHI)
+            break;
+
+         MDELAY(IPS_ONE_SEC);
+      }
+
+      if (j >= 45)
+         /* error occured */
+         return (0);
+
+      PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
+      outb(Isr, ha->io_addr + IPS_REG_HISR);
+   }
+
+   if (PostByte[0] < IPS_GOOD_POST_STATUS) {
+      printk(KERN_WARNING "(%s%d) reset controller fails (post status %x %x).\n",
+             ips_name, ha->host_num, PostByte[0], PostByte[1]);
+
+      return (0);
+   }
+
+   for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
+      for (j = 0; j < 240; j++) {
+         Isr = inb(ha->io_addr + IPS_REG_HISR);
+         if (Isr & IPS_BIT_GHI)
+            break;
+
+         MDELAY(IPS_ONE_SEC); /* 100 msec */
+      }
+
+      if (j >= 240)
+         /* error occured */
+         return (0);
+
+      ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
+      outb(Isr, ha->io_addr + IPS_REG_HISR);
+   }
+
+   for (i = 0; i < 240; i++) {
+      Cbsp = inb(ha->io_addr + IPS_REG_CBSP);
+
+      if ((Cbsp & IPS_BIT_OP) == 0)
+         break;
+
+      MDELAY(IPS_ONE_SEC);
+   }
+
+   if (i >= 240)
+      /* reset failed */
+      return (0);
+
+   /* setup CCCR */
+   outw(0x1010, ha->io_addr + IPS_REG_CCCR);
+
+   /* Enable busmastering */
+   outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
+
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      /* fix for anaconda64 */
+      outl(0, ha->io_addr + IPS_REG_NDAE);
+
+   /* Enable interrupts */
+   outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);
+
+   return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_init_copperhead_memio                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize a copperhead controller with memory mapped I/O              */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_init_copperhead_memio(ips_ha_t *ha) {
+   u8  Isr;
    u8  Cbsp;
    u8  PostByte[IPS_MAX_POST_BYTES];
    u8  ConfigByte[IPS_MAX_CONFIG_BYTES];
    int i, j;
+
+   METHOD_TRACE("ips_init_copperhead_memio", 1);
+
+   for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
+      for (j = 0; j < 45; j++) {
+         Isr = readb(ha->mem_ptr + IPS_REG_HISR);
+         if (Isr & IPS_BIT_GHI)
+            break;
+
+         MDELAY(IPS_ONE_SEC);
+      }
+
+      if (j >= 45)
+         /* error occured */
+         return (0);
+
+      PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
+      writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
+   }
+
+   if (PostByte[0] < IPS_GOOD_POST_STATUS) {
+      printk(KERN_WARNING "(%s%d) reset controller fails (post status %x %x).\n",
+             ips_name, ha->host_num, PostByte[0], PostByte[1]);
+
+      return (0);
+   }
+
+   for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
+      for (j = 0; j < 240; j++) {
+         Isr = readb(ha->mem_ptr + IPS_REG_HISR);
+         if (Isr & IPS_BIT_GHI)
+            break;
+
+         MDELAY(IPS_ONE_SEC); /* 100 msec */
+      }
+
+      if (j >= 240)
+         /* error occured */
+         return (0);
+
+      ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
+      writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
+   }
+
+   for (i = 0; i < 240; i++) {
+      Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP);
+
+      if ((Cbsp & IPS_BIT_OP) == 0)
+         break;
+
+      MDELAY(IPS_ONE_SEC);
+   }
+
+   if (i >= 240)
+      /* error occured */
+      return (0);
+
+   /* setup CCCR */
+   writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);
+
+   /* Enable busmastering */
+   writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
+
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      /* fix for anaconda64 */
+      writel(0, ha->mem_ptr + IPS_REG_NDAE);
+
+   /* Enable interrupts */
+   writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
+
+   /* if we get here then everything went OK */
+   return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_init_morpheus                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize a morpheus controller                                       */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_init_morpheus(ips_ha_t *ha) {
+   u32 Post;
+   u32 Config;
+   u32 Isr;
+   u32 Oimr;
+   int i;
+
+   METHOD_TRACE("ips_init_morpheus", 1);
+
+   /* Wait up to 45 secs for Post */
+   for (i = 0; i < 45; i++) {
+      Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+      if (Isr & IPS_BIT_I960_MSG0I)
+         break;
+
+      MDELAY(IPS_ONE_SEC);
+   }
+
+   if (i >= 45) {
+      /* error occured */
+      printk(KERN_WARNING "(%s%d) timeout waiting for post.\n",
+             ips_name, ha->host_num);
+
+      return (0);
+   }
+
+   Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+
+   /* Clear the interrupt bit */
+   Isr = (u32) IPS_BIT_I960_MSG0I;
+   writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
+
+   if (Post < (IPS_GOOD_POST_STATUS << 8)) {
+      printk(KERN_WARNING "(%s%d) reset controller fails (post status %x).\n",
+             ips_name, ha->host_num, Post);
+
+      return (0);
+   }
+
+   /* Wait up to 240 secs for config bytes */
+   for (i = 0; i < 240; i++) {
+      Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+      if (Isr & IPS_BIT_I960_MSG1I)
+         break;
+
+      MDELAY(IPS_ONE_SEC); /* 100 msec */
+   }
+
+   if (i >= 240) {
+      /* error occured */
+      printk(KERN_WARNING "(%s%d) timeout waiting for config.\n",
+             ips_name, ha->host_num);
+
+      return (0);
+   }
+
+   Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
+
+   /* Clear interrupt bit */
+   Isr = (u32) IPS_BIT_I960_MSG1I;
+   writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
+
+   /* Turn on the interrupts */
+   Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
+   Oimr &= ~0x8;
+   writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
+
+   /* if we get here then everything went OK */
+   return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_reset_copperhead                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Reset the controller                                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_reset_copperhead(ips_ha_t *ha) {
    int reset_counter;
    u32 cpu_flags;
 
-   DBG("ips_reset_adapter");
+   METHOD_TRACE("ips_reset_copperhead", 1);
 
-#if IPS_DEBUG >= 1
-   printk(KERN_WARNING "ips_reset_adapter: io addr: %x, irq: %d\n",
-          ha->io_addr, ha->irq);
-#endif
+   DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
+             ips_name, ha->host_num, ha->io_addr, ha->irq);
 
    IPS_HA_LOCK(cpu_flags);
 
@@ -4199,109 +5099,107 @@
       outb(0, ha->io_addr + IPS_REG_SCPR);
       MDELAY(IPS_ONE_SEC);
 
-      for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
-         for (j = 0; j < 45; j++) {
-            Isr = inb(ha->io_addr + IPS_REG_HISR);
-            if (Isr & IPS_BIT_GHI)
-               break;
-
-            MDELAY(IPS_ONE_SEC);
-         }
-
-         if (j >= 45) {
-            /* error occured */
-            if (reset_counter < 2)
-               continue;
-            else {
-               /* reset failed */
-               IPS_HA_UNLOCK(cpu_flags);
-
-               return (0);
-            }
-         }
+      if ((*ha->func.init)(ha))
+         break;
+      else if (reset_counter >= 2) {
+         IPS_HA_UNLOCK(cpu_flags);
 
-         PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
-         outb(Isr, ha->io_addr + IPS_REG_HISR);
+         return (0);
       }
+   }
 
-      if (PostByte[0] < IPS_GOOD_POST_STATUS) {
-         printk("(%s%d) reset controller fails (post status %x %x).\n",
-                ips_name, ha->host_num, PostByte[0], PostByte[1]);
+   IPS_HA_UNLOCK(cpu_flags);
 
-         IPS_HA_UNLOCK(cpu_flags);
+   return (1);
+}
 
-         return (0);
-      }
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_reset_copperhead_memio                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Reset the controller                                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_reset_copperhead_memio(ips_ha_t *ha) {
+   int reset_counter;
+   u32 cpu_flags;
 
-      for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
-         for (j = 0; j < 240; j++) {
-            Isr = inb(ha->io_addr + IPS_REG_HISR);
-            if (Isr & IPS_BIT_GHI)
-               break;
+   METHOD_TRACE("ips_reset_copperhead_memio", 1);
 
-            MDELAY(IPS_ONE_SEC); /* 100 msec */
-         }
+   DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
+             ips_name, ha->host_num, ha->mem_addr, ha->irq);
 
-         if (j >= 240) {
-            /* error occured */
-            if (reset_counter < 2)
-               continue;
-            else {
-               /* reset failed */
-               IPS_HA_UNLOCK(cpu_flags);
+   IPS_HA_LOCK(cpu_flags);
 
-               return (0);
-            }
-         }
+   reset_counter = 0;
 
-         ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
-         outb(Isr, ha->io_addr + IPS_REG_HISR);
-      }
+   while (reset_counter < 2) {
+      reset_counter++;
 
-      if (ConfigByte[0] == 0 && ConfigByte[1] == 2) {
-         printk("(%s%d) reset controller fails (status %x %x).\n",
-                ips_name, ha->host_num, ConfigByte[0], ConfigByte[1]);
+      writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
+      MDELAY(IPS_ONE_SEC);
+      writeb(0, ha->mem_ptr + IPS_REG_SCPR);
+      MDELAY(IPS_ONE_SEC);
 
+      if ((*ha->func.init)(ha))
+         break;
+      else if (reset_counter >= 2) {
          IPS_HA_UNLOCK(cpu_flags);
 
          return (0);
       }
+   }
 
-      for (i = 0; i < 240; i++) {
-         Cbsp = inb(ha->io_addr + IPS_REG_CBSP);
+   IPS_HA_UNLOCK(cpu_flags);
 
-         if ((Cbsp & IPS_BIT_OP) == 0)
-            break;
+   return (1);
+}
 
-         MDELAY(IPS_ONE_SEC);
-      }
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_reset_morpheus                                         */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Reset the controller                                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_reset_morpheus(ips_ha_t *ha) {
+   int reset_counter;
+   u8  junk;
+   u32 cpu_flags;
 
-      if (i >= 240) {
-         /* error occured */
-         if (reset_counter < 2)
-            continue;
-         else {
-            /* reset failed */
-            IPS_HA_UNLOCK(cpu_flags);
+   METHOD_TRACE("ips_reset_morpheus", 1);
 
-            return (0);
-         }
-      }
+   DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
+             ips_name, ha->host_num, ha->mem_addr, ha->irq);
 
-      /* setup CCCR */
-      outw(0x1010, ha->io_addr + IPS_REG_CCCR);
+   IPS_HA_LOCK(cpu_flags);
 
-      /* Enable busmastering */
-      outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
+   reset_counter = 0;
 
-      /* setup status queues */
-      ips_statinit(ha);
+   while (reset_counter < 2) {
+      reset_counter++;
 
-      /* Enable interrupts */
-      outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);
+      writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
 
-      /* if we get here then everything went OK */
-      break;
+      /* Delay for 300 msec */
+      MDELAY(300 * IPS_ONE_MSEC);
+
+      /* Do a PCI config read to wait for adapter */
+      pci_read_config_byte(ha->pcidev, 4, &junk);
+
+      if ((*ha->func.init)(ha))
+         break;
+      else if (reset_counter >= 2) {
+         IPS_HA_UNLOCK(cpu_flags);
+
+         return (0);
+      }
    }
 
    IPS_HA_UNLOCK(cpu_flags);
@@ -4322,7 +5220,7 @@
 ips_statinit(ips_ha_t *ha) {
    u32        phys_status_start;
 
-   DBG("ips_statinit");
+   METHOD_TRACE("ips_statinit", 1);
 
    ha->adapt->p_status_start = ha->adapt->status;
    ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
@@ -4340,18 +5238,45 @@
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_statupd                                                */
+/* Routine Name: ips_statinit_memio                                         */
 /*                                                                          */
 /* Routine Description:                                                     */
 /*                                                                          */
-/*   Remove an element from the status queue                                */
+/*   Initialize the status queues on the controller                         */
 /*                                                                          */
 /****************************************************************************/
-static int
-ips_statupd(ips_ha_t *ha) {
-   int       command_id;
+static void
+ips_statinit_memio(ips_ha_t *ha) {
+   u32        phys_status_start;
+
+   METHOD_TRACE("ips_statinit_memio", 1);
+
+   ha->adapt->p_status_start = ha->adapt->status;
+   ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
+   ha->adapt->p_status_tail = ha->adapt->status;
+
+   phys_status_start = VIRT_TO_BUS(ha->adapt->status);
+   writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);
+   writel(phys_status_start + IPS_STATUS_Q_SIZE, ha->mem_ptr + IPS_REG_SQER);
+   writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);
+   writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);
+
+   ha->adapt->hw_status_start = phys_status_start;
+   ha->adapt->hw_status_tail = phys_status_start;
+}
 
-   DBG("ips_statupd");
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_statupd_copperhead                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove an element from the status queue                                */
+/*                                                                          */
+/****************************************************************************/
+static u32
+ips_statupd_copperhead(ips_ha_t *ha) {
+   METHOD_TRACE("ips_statupd_copperhead", 1);
 
    if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
       ha->adapt->p_status_tail++;
@@ -4363,47 +5288,87 @@
 
    outl(ha->adapt->hw_status_tail, ha->io_addr + IPS_REG_SQTR);
 
-   command_id = ha->adapt->p_status_tail->command_id;
+   return (ha->adapt->p_status_tail->value);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_statupd_copperhead_memio                               */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove an element from the status queue                                */
+/*                                                                          */
+/****************************************************************************/
+static u32
+ips_statupd_copperhead_memio(ips_ha_t *ha) {
+   METHOD_TRACE("ips_statupd_copperhead_memio", 1);
+
+   if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
+      ha->adapt->p_status_tail++;
+      ha->adapt->hw_status_tail += sizeof(IPS_STATUS);
+   } else {
+      ha->adapt->p_status_tail = ha->adapt->p_status_start;
+      ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
+   }
+
+   writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);
 
-   return (command_id);
+   return (ha->adapt->p_status_tail->value);
 }
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_issue                                                  */
+/* Routine Name: ips_statupd_morpheus                                       */
 /*                                                                          */
 /* Routine Description:                                                     */
 /*                                                                          */
-/*   Send a command down to the controller                                  */
+/*   Remove an element from the status queue                                */
 /*                                                                          */
-/* ASSUMED to be called from within a lock                                  */
+/****************************************************************************/
+static u32
+ips_statupd_morpheus(ips_ha_t *ha) {
+   u32       val;
+
+   METHOD_TRACE("ips_statupd_morpheus", 1);
+
+   val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);
+
+   return (val);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_issue_copperhead                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command down to the controller                                  */
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_issue(ips_ha_t *ha, ips_scb_t *scb) {
+ips_issue_copperhead(ips_ha_t *ha, ips_scb_t *scb) {
    u32       TimeOut;
    u16       val;
    u32       cpu_flags;
 
-   DBG("ips_issue");
+   METHOD_TRACE("ips_issue_copperhead", 1);
 
-#if IPS_DEBUG >= 10
-   if (scb->scsi_cmd)
-      printk(KERN_NOTICE "%s: ips_issue: cmd 0x%X id %d (%d %d %d)\n",
-             ips_name,
-             scb->cdb[0],
-             scb->cmd.basic_io.command_id,
-             scb->bus,
-             scb->target_id,
-             scb->lun);
-   else
-      printk(KERN_NOTICE "%s: ips_issue: logical cmd id %d\n",
-             ips_name,
-             scb->cmd.basic_io.command_id);
-#if IPS_DEBUG >= 11
-      MDELAY(IPS_ONE_SEC);
-#endif
-#endif
+   if (scb->scsi_cmd) {
+      DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+                ips_name,
+                ha->host_num,
+                scb->cdb[0],
+                scb->cmd.basic_io.command_id,
+                scb->bus,
+                scb->target_id,
+                scb->lun);
+   } else {
+      DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d",
+                ips_name,
+                ha->host_num,
+                scb->cmd.basic_io.command_id);
+   }
 
    IPS_HA_LOCK(cpu_flags);
 
@@ -4430,14 +5395,189 @@
    outl(scb->scb_busaddr, ha->io_addr + IPS_REG_CCSAR);
    outw(IPS_BIT_START_CMD, ha->io_addr + IPS_REG_CCCR);
 
-   IPS_HA_UNLOCK(cpu_flags);
+   IPS_HA_UNLOCK(cpu_flags);
+
+   return (IPS_SUCCESS);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_issue_copperhead_memio                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command down to the controller                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_issue_copperhead_memio(ips_ha_t *ha, ips_scb_t *scb) {
+   u32       TimeOut;
+   u32       val;
+   u32       cpu_flags;
+
+   METHOD_TRACE("ips_issue_copperhead_memio", 1);
+
+   if (scb->scsi_cmd) {
+      DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+                ips_name,
+                ha->host_num,
+                scb->cdb[0],
+                scb->cmd.basic_io.command_id,
+                scb->bus,
+                scb->target_id,
+                scb->lun);
+   } else {
+      DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
+                ips_name,
+                ha->host_num,
+                scb->cmd.basic_io.command_id);
+   }
+
+   IPS_HA_LOCK(cpu_flags);
+
+   TimeOut = 0;
+
+   while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
+      UDELAY(1000);
+
+      if (++TimeOut >= IPS_SEM_TIMEOUT) {
+         if (!(val & IPS_BIT_START_STOP))
+            break;
+
+         printk(KERN_WARNING "(%s%d) ips_issue val [0x%x].\n",
+                ips_name, ha->host_num, val);
+         printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n",
+                ips_name, ha->host_num);
+
+         IPS_HA_UNLOCK(cpu_flags);
+
+         return (IPS_FAILURE);
+      } /* end if */
+   } /* end while */
+
+   writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
+   writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
+
+   IPS_HA_UNLOCK(cpu_flags);
+
+   return (IPS_SUCCESS);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_issue_i2o                                              */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command down to the controller                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_issue_i2o(ips_ha_t *ha, ips_scb_t *scb) {
+   u32       cpu_flags;
+
+   METHOD_TRACE("ips_issue_i2o", 1);
+
+   if (scb->scsi_cmd) {
+      DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+                ips_name,
+                ha->host_num,
+                scb->cdb[0],
+                scb->cmd.basic_io.command_id,
+                scb->bus,
+                scb->target_id,
+                scb->lun);
+   } else {
+      DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
+                ips_name,
+                ha->host_num,
+                scb->cmd.basic_io.command_id);
+   }
+
+   IPS_HA_LOCK(cpu_flags);
+
+   outl(scb->scb_busaddr, ha->io_addr + IPS_REG_I2O_INMSGQ);
+
+   IPS_HA_UNLOCK(cpu_flags);
+
+   return (IPS_SUCCESS);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_issue_i2o_memio                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command down to the controller                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_issue_i2o_memio(ips_ha_t *ha, ips_scb_t *scb) {
+   u32       cpu_flags;
+
+   METHOD_TRACE("ips_issue_i2o_memio", 1);
+
+   if (scb->scsi_cmd) {
+      DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+                ips_name,
+                ha->host_num,
+                scb->cdb[0],
+                scb->cmd.basic_io.command_id,
+                scb->bus,
+                scb->target_id,
+                scb->lun);
+   } else {
+      DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
+                ips_name,
+                ha->host_num,
+                scb->cmd.basic_io.command_id);
+   }
+
+   IPS_HA_LOCK(cpu_flags);
+
+   writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
+
+   IPS_HA_UNLOCK(cpu_flags);
+
+   return (IPS_SUCCESS);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_isintr_copperhead                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Test to see if an interrupt is for us                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isintr_copperhead(ips_ha_t *ha) {
+   u8 Isr;
+
+   METHOD_TRACE("ips_isintr_copperhead", 2);
+
+   Isr = inb(ha->io_addr + IPS_REG_HISR);
+
+   if (Isr == 0xFF)
+      /* ?!?! Nothing really there */
+      return (0);
 
-   return (IPS_SUCCESS);
+   if (Isr & IPS_BIT_SCE)
+      return (1);
+   else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
+      /* status queue overflow or GHI */
+      /* just clear the interrupt */
+      outb(Isr, ha->io_addr + IPS_REG_HISR);
+   }
+
+   return (0);
 }
 
 /****************************************************************************/
 /*                                                                          */
-/* Routine Name: ips_isintr                                                 */
+/* Routine Name: ips_isintr_copperhead_memio                                */
 /*                                                                          */
 /* Routine Description:                                                     */
 /*                                                                          */
@@ -4445,12 +5585,12 @@
 /*                                                                          */
 /****************************************************************************/
 static int
-ips_isintr(ips_ha_t *ha) {
+ips_isintr_copperhead_memio(ips_ha_t *ha) {
    u8 Isr;
 
-   DBG("ips_isintr");
+   METHOD_TRACE("ips_isintr_memio", 2);
 
-   Isr = inb(ha->io_addr + IPS_REG_HISR);
+   Isr = readb(ha->mem_ptr + IPS_REG_HISR);
 
    if (Isr == 0xFF)
       /* ?!?! Nothing really there */
@@ -4461,7 +5601,7 @@
    else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
       /* status queue overflow or GHI */
       /* just clear the interrupt */
-      outb(Isr, ha->io_addr + IPS_REG_HISR);
+      writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
    }
 
    return (0);
@@ -4469,6 +5609,29 @@
 
 /****************************************************************************/
 /*                                                                          */
+/* Routine Name: ips_isintr_morpheus                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Test to see if an interrupt is for us                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isintr_morpheus(ips_ha_t *ha) {
+   u32 Isr;
+
+   METHOD_TRACE("ips_isintr_morpheus", 2);
+
+   Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+   if (Isr & IPS_BIT_I2O_OPQI)
+      return (1);
+   else
+      return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
 /* Routine Name: ips_wait                                                   */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -4481,7 +5644,7 @@
    int        ret;
    u8         done;
 
-   DBG("ips_wait");
+   METHOD_TRACE("ips_wait", 1);
 
    ret = IPS_FAILURE;
    done = FALSE;
@@ -4516,7 +5679,7 @@
          while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
             UDELAY(1000);
 
-         ips_intr(ha);
+         (*ha->func.intr)(ha);
 
          clear_bit(IPS_IN_INTR, &ha->flags);
       } else if (intr == IPS_INTR_HAL) {
@@ -4542,7 +5705,7 @@
          while (test_and_set_bit(IPS_IN_INTR, &ha->flags))
             UDELAY(1000);
 
-         ips_intr(ha);
+         (*ha->func.intr)(ha);
 
          clear_bit(IPS_IN_INTR, &ha->flags);
 
@@ -4567,7 +5730,7 @@
 /****************************************************************************/
 static int
 ips_write_driver_status(ips_ha_t *ha, int intr) {
-   DBG("ips_write_driver_status");
+   METHOD_TRACE("ips_write_driver_status", 1);
 
    if (!ips_readwrite_page5(ha, FALSE, intr)) {
       printk(KERN_WARNING "(%s%d) unable to read NVRAM page 5.\n",
@@ -4579,21 +5742,18 @@
    /* check to make sure the page has a valid */
    /* signature */
    if (ha->nvram->signature != IPS_NVRAM_P5_SIG) {
-#if IPS_DEBUG >= 1
-      printk("(%s%d) NVRAM page 5 has an invalid signature: %X.\n",
-             ips_name, ha->host_num, ha->nvram->signature);
-#endif
+      DEBUG_VAR(1, "(%s%d) NVRAM page 5 has an invalid signature: %X.",
+                ips_name, ha->host_num, ha->nvram->signature);
+
       return (1);
    }
 
-#if IPS_DEBUG >= 2
-   printk("(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.\n",
-          ips_name, ha->host_num, ha->nvram->adapter_type, ha->nvram->adapter_slot,
-          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
-          ha->nvram->bios_high[2], ha->nvram->bios_high[3],
-          ha->nvram->bios_low[0], ha->nvram->bios_low[1],
-          ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
-#endif
+   DEBUG_VAR(2, "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.",
+             ips_name, ha->host_num, ha->nvram->adapter_type, ha->nvram->adapter_slot,
+             ha->nvram->bios_high[0], ha->nvram->bios_high[1],
+             ha->nvram->bios_high[2], ha->nvram->bios_high[3],
+             ha->nvram->bios_low[0], ha->nvram->bios_low[1],
+             ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
 
    /* save controller type */
    ha->ad_type = ha->nvram->adapter_type;
@@ -4628,7 +5788,7 @@
    ips_scb_t *scb;
    int        ret;
 
-   DBG("ips_read_adapter_status");
+   METHOD_TRACE("ips_read_adapter_status", 1);
 
    scb = &ha->scbs[ha->max_cmds-1];
 
@@ -4647,8 +5807,9 @@
    scb->cmd.basic_io.reserved = 0;
 
    /* send command */
-   ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
-   if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
+   if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
+       (ret == IPS_SUCCESS_IMM) ||
+       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
       return (0);
 
    return (1);
@@ -4668,7 +5829,7 @@
    ips_scb_t *scb;
    int        ret;
 
-   DBG("ips_read_subsystem_parameters");
+   METHOD_TRACE("ips_read_subsystem_parameters", 1);
 
    scb = &ha->scbs[ha->max_cmds-1];
 
@@ -4687,8 +5848,9 @@
    scb->cmd.basic_io.reserved = 0;
 
    /* send command */
-   ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
-   if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
+   if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
+       (ret == IPS_SUCCESS_IMM) ||
+       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
       return (0);
 
    return (1);
@@ -4709,7 +5871,7 @@
    int        i;
    int        ret;
 
-   DBG("ips_read_config");
+   METHOD_TRACE("ips_read_config", 1);
 
    /* set defaults for initiator IDs */
    ha->conf->init_id[0] = IPS_ADAPTER_ID;
@@ -4759,7 +5921,7 @@
    ips_scb_t *scb;
    int        ret;
 
-   DBG("ips_readwrite_page5");
+   METHOD_TRACE("ips_readwrite_page5", 1);
 
    scb = &ha->scbs[ha->max_cmds-1];
 
@@ -4803,7 +5965,7 @@
    ips_scb_t *scb;
    int        ret;
 
-   DBG("ips_clear_adapter");
+   METHOD_TRACE("ips_clear_adapter", 1);
 
    scb = &ha->scbs[ha->max_cmds-1];
 
@@ -4821,8 +5983,9 @@
    scb->cmd.config_sync.reserved3 = 0;
 
    /* issue command */
-   ret = ips_send_wait(ha, scb, ips_reset_timeout, intr);
-   if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
+   if (((ret = ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE) ||
+       (ret == IPS_SUCCESS_IMM) ||
+       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
       return (0);
 
    /* send unlock stripe command */
@@ -4840,8 +6003,9 @@
    scb->cmd.unlock_stripe.reserved3 = 0;
 
    /* issue command */
-   ret = ips_send_wait(ha, scb, ips_reset_timeout, intr);
-   if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
+   if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) ||
+       (ret == IPS_SUCCESS_IMM) ||
+       ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
       return (0);
 
    return (1);
@@ -4860,7 +6024,7 @@
 ips_ffdc_reset(ips_ha_t *ha, int intr) {
    ips_scb_t *scb;
 
-   DBG("ips_ffdc_reset");
+   METHOD_TRACE("ips_ffdc_reset", 1);
 
    scb = &ha->scbs[ha->max_cmds-1];
 
@@ -4893,12 +6057,10 @@
 ips_ffdc_time(ips_ha_t *ha, int intr) {
    ips_scb_t *scb;
 
-   DBG("ips_ffdc_time");
+   METHOD_TRACE("ips_ffdc_time", 1);
 
-#if IPS_DEBUG >= 1
-   printk(KERN_NOTICE "(%s%d) Sending time update.\n",
-          ips_name, ha->host_num);
-#endif
+   DEBUG_VAR(1, "(%s%d) Sending time update.",
+             ips_name, ha->host_num);
 
    scb = &ha->scbs[ha->max_cmds-1];
 
@@ -4947,6 +6109,8 @@
                                  {30, 30},
                                  {31, 31} };
 
+   METHOD_TRACE("ips_fix_ffdc_time", 1);
+
    days = current_time / IPS_SECS_DAY;
    rem = current_time % IPS_SECS_DAY;
 
@@ -4995,6 +6159,8 @@
    int   timeout;
    u8    status;
 
+   METHOD_TRACE("ips_erase_bios", 1);
+
    /* Clear the status register */
    outl(0, ha->io_addr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
@@ -5091,6 +6257,115 @@
 
 /****************************************************************************/
 /*                                                                          */
+/* Routine Name: ips_erase_bios_memio                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Erase the BIOS on the adapter                                          */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_erase_bios_memio(ips_ha_t *ha) {
+   int   timeout;
+   u8    status;
+
+   METHOD_TRACE("ips_erase_bios_memio", 1);
+
+   /* Clear the status register */
+   writel(0, ha->mem_ptr + IPS_REG_FLAP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   /* Erase Setup */
+   writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   /* Erase Confirm */
+   writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   /* Erase Status */
+   writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   timeout = 80000; /* 80 seconds */
+
+   while (timeout > 0) {
+      if (ha->revision_id == IPS_REVID_TROMBONE64) {
+         writel(0, ha->mem_ptr + IPS_REG_FLAP);
+         UDELAY(5); /* 5 us */
+      }
+
+      status = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+      if (status & 0x80)
+         break;
+
+      MDELAY(1);
+      timeout--;
+   }
+
+   /* check for timeout */
+   if (timeout <= 0) {
+      /* timeout */
+
+      /* try to suspend the erase */
+      writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
+      if (ha->revision_id == IPS_REVID_TROMBONE64)
+         UDELAY(5); /* 5 us */
+
+      /* wait for 10 seconds */
+      timeout = 10000;
+      while (timeout > 0) {
+         if (ha->revision_id == IPS_REVID_TROMBONE64) {
+            writel(0, ha->mem_ptr + IPS_REG_FLAP);
+            UDELAY(5); /* 5 us */
+         }
+
+         status = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+         if (status & 0xC0)
+            break;
+
+         MDELAY(1);
+         timeout--;
+      }
+
+      return (1);
+   }
+
+   /* check for valid VPP */
+   if (status & 0x08)
+      /* VPP failure */
+      return (1);
+
+   /* check for succesful flash */
+   if (status & 0x30)
+      /* sequence error */
+      return (1);
+
+   /* Otherwise, we were successful */
+   /* clear status */
+   writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   /* enable reads */
+   writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
 /* Routine Name: ips_program_bios                                           */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -5103,6 +6378,8 @@
    int   timeout;
    u8    status;
 
+   METHOD_TRACE("ips_program_bios", 1);
+
    for (i = 0; i < buffersize; i++) {
       /* write a byte */
       outl(i, ha->io_addr + IPS_REG_FLAP);
@@ -5176,6 +6453,93 @@
 
 /****************************************************************************/
 /*                                                                          */
+/* Routine Name: ips_program_bios_memio                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Program the BIOS on the adapter                                        */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_program_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) {
+   int   i;
+   int   timeout;
+   u8    status;
+
+   METHOD_TRACE("ips_program_bios_memio", 1);
+
+   for (i = 0; i < buffersize; i++) {
+      /* write a byte */
+      writel(i, ha->mem_ptr + IPS_REG_FLAP);
+      if (ha->revision_id == IPS_REVID_TROMBONE64)
+         UDELAY(5); /* 5 us */
+
+      writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
+      if (ha->revision_id == IPS_REVID_TROMBONE64)
+         UDELAY(5); /* 5 us */
+
+      writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
+      if (ha->revision_id == IPS_REVID_TROMBONE64)
+         UDELAY(5); /* 5 us */
+
+      /* wait up to one second */
+      timeout = 1000;
+      while (timeout > 0) {
+         if (ha->revision_id == IPS_REVID_TROMBONE64) {
+            writel(0, ha->mem_ptr + IPS_REG_FLAP);
+            UDELAY(5); /* 5 us */
+         }
+
+         status = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+         if (status & 0x80)
+            break;
+
+         MDELAY(1);
+         timeout--;
+      }
+
+      if (timeout == 0) {
+         /* timeout error */
+         writel(0, ha->mem_ptr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            UDELAY(5); /* 5 us */
+
+         writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            UDELAY(5); /* 5 us */
+
+         return (1);
+      }
+
+      /* check the status */
+      if (status & 0x18) {
+         /* programming error */
+         writel(0, ha->mem_ptr + IPS_REG_FLAP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            UDELAY(5); /* 5 us */
+
+         writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+         if (ha->revision_id == IPS_REVID_TROMBONE64)
+            UDELAY(5); /* 5 us */
+
+         return (1);
+      }
+   } /* end for */
+
+   /* Enable reading */
+   writel(0, ha->mem_ptr + IPS_REG_FLAP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
 /* Routine Name: ips_verify_bios                                            */
 /*                                                                          */
 /* Routine Description:                                                     */
@@ -5187,6 +6551,8 @@
    u8    checksum;
    int   i;
 
+   METHOD_TRACE("ips_verify_bios", 1);
+
    /* test 1st byte */
    outl(0, ha->io_addr + IPS_REG_FLAP);
    if (ha->revision_id == IPS_REVID_TROMBONE64)
@@ -5209,6 +6575,53 @@
          UDELAY(5); /* 5 us */
 
       checksum = (u8) checksum + inb(ha->io_addr + IPS_REG_FLDP);
+   }
+
+   if (checksum != 0)
+      /* failure */
+      return (1);
+   else
+      /* success */
+      return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_verify_bios_memio                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Verify the BIOS on the adapter                                         */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_verify_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) {
+   u8    checksum;
+   int   i;
+
+   METHOD_TRACE("ips_verify_bios_memio", 1);
+
+   /* test 1st byte */
+   writel(0, ha->mem_ptr + IPS_REG_FLAP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+
+   if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
+      return (1);
+
+   writel(1, ha->mem_ptr + IPS_REG_FLAP);
+   if (ha->revision_id == IPS_REVID_TROMBONE64)
+      UDELAY(5); /* 5 us */
+   if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
+      return (1);
+
+   checksum = 0xff;
+   for (i = 2; i < buffersize; i++) {
+
+      writel(i, ha->mem_ptr + IPS_REG_FLAP);
+      if (ha->revision_id == IPS_REVID_TROMBONE64)
+         UDELAY(5); /* 5 us */
+
+      checksum = (u8) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
    }
 
    if (checksum != 0)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ips.h linux.18p8/drivers/scsi/ips.h
--- linux.vanilla/drivers/scsi/ips.h	Sun Jun 11 21:44:17 2000
+++ linux.18p8/drivers/scsi/ips.h	Fri Sep 15 15:13:38 2000
@@ -1,5 +1,5 @@
 /*****************************************************************************/
-/* ips.h -- driver for the IBM ServeRAID adapter                             */
+/* ips.h -- driver for the IBM ServeRAID controller                          */
 /*                                                                           */
 /* Written By: Keith Mitchell, IBM Corporation                               */
 /*                                                                           */
@@ -47,14 +47,13 @@
 #ifndef _IPS_H_
    #define _IPS_H_
 
+   #include <linux/config.h>
    #include <asm/uaccess.h>
    #include <asm/io.h>
 
    /* Prototypes */
    extern int ips_detect(Scsi_Host_Template *);
    extern int ips_release(struct Scsi_Host *);
-   extern int ips_abort(Scsi_Cmnd *);
-   extern int ips_reset(Scsi_Cmnd *, unsigned int);
    extern int ips_eh_abort(Scsi_Cmnd *);
    extern int ips_eh_reset(Scsi_Cmnd *);
    extern int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *));
@@ -71,7 +70,21 @@
 
    #define IPS_HA(x)                   ((ips_ha_t *) x->hostdata)
    #define IPS_COMMAND_ID(ha, scb)     (int) (scb - ha->scbs)
-   
+   #define IPS_IS_TROMBONE(ha)         (((ha->device_id == IPS_COPPERHEAD_DEVICEID) && \
+                                         (ha->revision_id >= IPS_REVID_TROMBONE32) && \
+                                         (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0)
+   #define IPS_IS_CLARINET(ha)         (((ha->device_id == IPS_COPPERHEAD_DEVICEID) && \
+                                         (ha->revision_id >= IPS_REVID_CLARINETP1) && \
+                                         (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0)
+   #define IPS_IS_MORPHEUS(ha)         (ha->device_id == IPS_MORPHEUS_DEVICEID)
+   #define IPS_USE_I2O_DELIVER(ha)     ((IPS_IS_MORPHEUS(ha) || \
+                                         (IPS_IS_TROMBONE(ha) && \
+                                          (ips_force_i2o))) ? 1 : 0)
+   #define IPS_USE_I2O_STATUS(ha)      (IPS_IS_MORPHEUS(ha))
+   #define IPS_USE_MEMIO(ha)           ((IPS_IS_MORPHEUS(ha) || \
+                                         ((IPS_IS_TROMBONE(ha) || IPS_IS_CLARINET(ha)) && \
+                                          (ips_force_memio))) ? 1 : 0)
+
    #ifndef VIRT_TO_BUS
       #define VIRT_TO_BUS(x)           (unsigned int)virt_to_bus((void *) x)
    #endif
@@ -79,7 +92,7 @@
    #ifndef UDELAY
       #define UDELAY udelay
    #endif
-   
+
    #ifndef MDELAY
       #define MDELAY mdelay
    #endif
@@ -87,27 +100,27 @@
    #ifndef verify_area_20
       #define verify_area_20(t,a,sz)   (0) /* success */
    #endif
-   
+
    #ifndef PUT_USER
       #define PUT_USER                 put_user
    #endif
-   
+
    #ifndef __PUT_USER
       #define __PUT_USER               __put_user
    #endif
-   
+
    #ifndef PUT_USER_RET
       #define PUT_USER_RET             put_user_ret
    #endif
-   
+
    #ifndef GET_USER
       #define GET_USER                 get_user
    #endif
-   
+
    #ifndef __GET_USER
       #define __GET_USER               __get_user
    #endif
-   
+
    #ifndef GET_USER_RET
       #define GET_USER_RET             get_user_ret
    #endif
@@ -137,6 +150,14 @@
    #define IPS_REG_CBSP                 0x07    /* CBSP register               */
    #define IPS_REG_FLAP                 0x18    /* Flash address port          */
    #define IPS_REG_FLDP                 0x1C    /* Flash data port             */
+   #define IPS_REG_NDAE                 0x38    /* Anaconda 64 NDAE Register   */
+   #define IPS_REG_I2O_INMSGQ           0x40    /* I2O Inbound Message Queue   */
+   #define IPS_REG_I2O_OUTMSGQ          0x44    /* I2O Outbound Message Queue  */
+   #define IPS_REG_I2O_HIR              0x30    /* I2O Interrupt Status        */
+   #define IPS_REG_I960_IDR             0x20    /* i960 Inbound Doorbell       */
+   #define IPS_REG_I960_MSG0            0x18    /* i960 Outbound Reg 0         */
+   #define IPS_REG_I960_MSG1            0x1C    /* i960 Outbound Reg 1         */
+   #define IPS_REG_I960_OIMR            0x34    /* i960 Oubound Int Mask Reg   */
 
    /*
     * Adapter register bit equates
@@ -152,6 +173,9 @@
    #define IPS_BIT_EBM                  0x02    /* SCPR Enable Bus Master      */
    #define IPS_BIT_EI                   0x80    /* HISR Enable Interrupts      */
    #define IPS_BIT_OP                   0x01    /* OP bit in CBSP              */
+   #define IPS_BIT_I2O_OPQI             0x08    /* General Host Interrupt      */
+   #define IPS_BIT_I960_MSG0I           0x01    /* Message Register 0 Interrupt*/
+   #define IPS_BIT_I960_MSG1I           0x02    /* Message Register 1 Interrupt*/
 
    /*
     * Adapter Command ID Equates
@@ -202,13 +226,15 @@
    #define IPS_INTR_HAL                 2
    #define IPS_ADAPTER_ID               0xF
    #define IPS_VENDORID                 0x1014
-   #define IPS_DEVICEID                 0x002E
+   #define IPS_COPPERHEAD_DEVICEID      0x002E
+   #define IPS_MORPHEUS_DEVICEID        0x01BD
    #define IPS_IOCTL_SIZE               8192
    #define IPS_STATUS_SIZE              4
    #define IPS_STATUS_Q_SIZE            (IPS_MAX_CMDS+1) * IPS_STATUS_SIZE
+   #define IPS_MEMMAP_SIZE              128
    #define IPS_ONE_MSEC                 1
    #define IPS_ONE_SEC                  1000
-   
+
    /*
     * Geometry Settings
     */
@@ -336,10 +362,12 @@
    /*
     * Scsi_Host Template
     */
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
  #define IPS {                            \
     next : NULL,                          \
     module : NULL,                        \
     proc_info : NULL,                     \
+    proc_dir : NULL,                      \
     name : NULL,                          \
     detect : ips_detect,                  \
     release : ips_release,                \
@@ -351,8 +379,8 @@
     eh_device_reset_handler : NULL,       \
     eh_bus_reset_handler : NULL,          \
     eh_host_reset_handler : ips_eh_reset, \
-    abort : ips_abort,                    \
-    reset : ips_reset,                    \
+    abort : NULL,                         \
+    reset : NULL,                         \
     slave_attach : NULL,                  \
     bios_param : ips_biosparam,           \
     can_queue : 0,                        \
@@ -363,7 +391,37 @@
     unchecked_isa_dma : 0,                \
     use_clustering : ENABLE_CLUSTERING,   \
     use_new_eh_code : 1                   \
- }
+}
+#else
+ #define IPS {                            \
+    next : NULL,                          \
+    module : NULL,                        \
+    proc_info : NULL,                     \
+    name : NULL,                          \
+    detect : ips_detect,                  \
+    release : ips_release,                \
+    info : ips_info,                      \
+    command : NULL,                       \
+    queuecommand : ips_queue,             \
+    eh_strategy_handler : NULL,           \
+    eh_abort_handler : ips_eh_abort,      \
+    eh_device_reset_handler : NULL,       \
+    eh_bus_reset_handler : NULL,          \
+    eh_host_reset_handler : ips_eh_reset, \
+    abort : NULL,                         \
+    reset : NULL,                         \
+    slave_attach : NULL,                  \
+    bios_param : ips_biosparam,           \
+    can_queue : 0,                        \
+    this_id: -1,                          \
+    sg_tablesize : IPS_MAX_SG,            \
+    cmd_per_lun: 16,                      \
+    present : 0,                          \
+    unchecked_isa_dma : 0,                \
+    use_clustering : ENABLE_CLUSTERING,   \
+    use_new_eh_code : 1                   \
+}
+#endif
 
 /*
  * IBM PCI Raid Command Formats
@@ -531,11 +589,15 @@
    u8         reserved2[3];
 } IPS_DCDB_TABLE, *PIPS_DCDB_TABLE;
 
-typedef struct {
-   volatile u8      reserved;
-   volatile u8      command_id;
-   volatile u8      basic_status;
-   volatile u8      extended_status;
+typedef union {
+   struct {
+      volatile u8  reserved;
+      volatile u8  command_id;
+      volatile u8  basic_status;
+      volatile u8  extended_status;
+   } fields;
+
+   volatile u32    value;
 } IPS_STATUS, *PIPS_STATUS;
 
 typedef struct {
@@ -610,7 +672,7 @@
    u8        ucCompression;
    u8        ucNvramType;
    u32       ulNvramSize;
-} IPS_HARDWARE, *PIPS_HARDWARE;  
+} IPS_HARDWARE, *PIPS_HARDWARE;
 
 typedef struct {
    u8             ucLogDriveCount;
@@ -777,8 +839,15 @@
    int   length;
    int   offset;
    int   pos;
+   int   localpos;
 } IPS_INFOSTR;
 
+typedef struct {
+   char *option_name;
+   int  *option_flag;
+   int   option_value;
+} IPS_OPTION;
+
 /*
  * Status Info
  */
@@ -823,6 +892,24 @@
    spinlock_t                 lock;
 } ips_copp_queue_t;
 
+/* forward decl for host structure */
+struct ips_ha;
+
+typedef struct {
+   int  (*reset)(struct ips_ha *);
+   int  (*issue)(struct ips_ha *, struct ips_scb *);
+   int  (*isinit)(struct ips_ha *);
+   int  (*isintr)(struct ips_ha *);
+   int  (*init)(struct ips_ha *);
+   int  (*erasebios)(struct ips_ha *);
+   int  (*programbios)(struct ips_ha *, char *, int);
+   int  (*verifybios)(struct ips_ha *, char *, int);
+   u32  (*statupd)(struct ips_ha *);
+   void (*statinit)(struct ips_ha *);
+   void (*intr)(struct ips_ha *);
+   void (*enableint)(struct ips_ha *);
+} ips_hw_func_t;
+
 typedef struct ips_ha {
    u8                 ha_id[IPS_MAX_CHANNELS+1];
    u32                dcdb_active[IPS_MAX_CHANNELS];
@@ -857,12 +944,18 @@
    u16                reset_count;        /* number of resets           */
    u32                last_ffdc;          /* last time we sent ffdc info*/
    u8                 revision_id;        /* Revision level             */
-
-   #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
+   u16                device_id;          /* PCI device ID              */
+   u8                 reserved;
+   u32                mem_addr;           /* Memory mapped address      */
+   u32                io_len;             /* Size of IO Address         */
+   u32                mem_len;            /* Size of memory address     */
+   char              *mem_ptr;            /* Memory mapped Ptr          */
+   char              *ioremap_ptr;        /* ioremapped memory pointer  */
+   ips_hw_func_t      func;               /* hw function pointers       */
+   struct pci_dev    *pcidev;             /* PCI device handle          */
    spinlock_t         scb_lock;
    spinlock_t         copp_lock;
    spinlock_t         ips_lock;
-   #endif
 } ips_ha_t;
 
 typedef void (*ips_scb_callback) (ips_ha_t *, struct ips_scb *);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/megaraid.c linux.18p8/drivers/scsi/megaraid.c
--- linux.vanilla/drivers/scsi/megaraid.c	Sun Jun 11 21:44:17 2000
+++ linux.18p8/drivers/scsi/megaraid.c	Wed Sep 13 16:18:07 2000
@@ -2,19 +2,19 @@
  *
  *                    Linux MegaRAID device driver
  *
- * Copyright 1999 American Megatrends Inc.
+ * Copyright 2000  American Megatrends 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; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : 1.07b
+ * Version : 1b08b
  * 
  * Description: Linux device driver for AMI MegaRAID controller
  *
- * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 490
- * 
+ * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490
+ * 					493.
  * History:
  *
  * Version 0.90:
@@ -119,16 +119,67 @@
  *    Fixed the problem of unnecessary aborts in the abort entry point, which
  *      also enables the driver to handle large amount of I/O requests for
  *      long duration of time.
- *
+ * Version 1.06
+ * 		Intel Release
  * Version 1.07
  *    Removed the usage of uaccess.h file for kernel versions less than
  *    2.0.36, as this file is not present in those versions.
  *
- * Version 1.07b
- *    The MegaRAID 466 cards with 3.00 firmware lockup and seem to very
- *    occasionally hang. We check such cards and report them. You can
- *    get firmware upgrades to flash the board to 3.10 for free.
- *
+ * Version 108
+ *    Modified mega_ioctl so that 40LD megamanager would run
+ *    Made some changes for 2.3.XX compilation , esp wait structures
+ *    Code merge between 1.05 and 1.06 .
+ *    Bug fixed problem with ioctl interface for concurrency between 
+ *    8ld and 40ld firwmare
+ *    Removed the flawed semaphore logic for handling new config command
+ *    Added support for building own scatter / gather list for big user 
+ *    mode buffers
+ *    Added /proc file system support ,so that information is available in 
+ *    human readable format
+ *
+ * Version 1a08
+ *    Changes for IA64 kernels. Checked for CONFIG_PROC_FS flag 
+ *
+ * Version 1b08
+ *    Include file changes.
+ * Version 1b08b
+ *    Change PCI ID value for the 471 card, use #defines when searching
+ *    for megaraid cards.
+ *
+ * Version 1.10
+ *	  
+ *	I) Changes made to make following ioctl commands work in 0x81 interface
+ *		a)DCMD_DELETE_LOGDRV	
+ *		b)DCMD_GET_DISK_CONFIG
+ *		c)DCMD_DELETE_DRIVEGROUP
+ *		d)NC_SUBOP_ENQUIRY3
+ *		e)DCMD_CHANGE_LDNO	
+ *	 	f)DCMD_CHANGE_LOOPID
+ *		g)DCMD_FC_READ_NVRAM_CONFIG
+ *    	h)DCMD_WRITE_CONFIG
+ * 	II) Added mega_build_kernel_sg function
+ *  III)Firmware flashing option
 added
+ *	
+ * Version 1.10a
+ *
+ *	I)Dell updates included in the source code. 
+ * 		Note:	This change is not tested due to the unavailability of IA64 kernel 
+ *	and it is in the #ifdef DELL_MODIFICATION macro which is not defined
+ *				
+ * Version 1.10b
+ *
+ *	I)In IOCTL_CMD_NEW command the wrong way of copying the data 
+ *    to the user address corrected
+ *
+ * Version 1.10c
+ *
+ *	I) DCMD_GET_DISK_CONFIG opcode updated for the firmware changes. 
+ *
+ * Version 1.11
+ *	I)  Version number changed from 1.10c to 1.11
+ *  II)	DCMD_WRITE_CONFIG(0x0D) command in the driver changed from 
+ *  	scatter/gather list mode to direct pointer mode.. 
+ * 
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
  *     fails to detect the controller as a pci device on the system.
@@ -143,8 +194,8 @@
 #define CRLFSTR "\n"
 #define IOCTL_CMD_NEW  0x81
 
-#define MEGARAID_VERSION "v107 (December 22, 1999)"
-
+#define MEGARAID_VERSION "v1.11 (Aug 23, 2000)" 
+#define MEGARAID_IOCTL_VERSION 108
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -163,6 +214,7 @@
 
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
@@ -173,6 +225,8 @@
 #include <linux/wait.h>
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
 
 #include <linux/sched.h>
 #include <linux/stat.h>
@@ -181,7 +235,11 @@
 #if LINUX_VERSION_CODE < 0x20100
 #include <linux/bios32.h>
 #else
-#include <asm/spinlock.h>
+#if LINUX_VERSION_CODE < 0x20300
+# include <asm/spinlock.h>
+#else
+# include <linux/spinlock.h>
+#endif
 #endif
 
 #include <asm/io.h>
@@ -229,22 +287,22 @@
 #define COM_BASE 0x2f8
 
 
-u32 RDINDOOR (mega_host_config * megaCfg)
+ulong RDINDOOR (mega_host_config * megaCfg)
 {
   return readl (megaCfg->base + 0x20);
 }
 
-void WRINDOOR (mega_host_config * megaCfg, u32 value)
+void WRINDOOR (mega_host_config * megaCfg, ulong value)
 {
   writel (value, megaCfg->base + 0x20);
 }
 
-u32 RDOUTDOOR (mega_host_config * megaCfg)
+ulong RDOUTDOOR (mega_host_config * megaCfg)
 {
   return readl (megaCfg->base + 0x2C);
 }
 
-void WROUTDOOR (mega_host_config * megaCfg, u32 value)
+void WROUTDOOR (mega_host_config * megaCfg, ulong value)
 {
   writel (value, megaCfg->base + 0x2C);
 }
@@ -276,7 +334,12 @@
 
 
 #if LINUX_VERSION_CODE > 0x020100
+#if LINUX_VERSION_CODE < 0x20300
 #  include <asm/spinlock.h>
+# else
+#  include <linux/spinlock.h>
+#endif
+
 #  include <linux/smp.h>
 #  define cpuid smp_processor_id()
 #  if LINUX_VERSION_CODE < 0x020195
@@ -329,6 +392,19 @@
 static int ser_printk (const char *fmt,...);
 #endif
 
+#ifdef CONFIG_PROC_FS
+#define COPY_BACK if (offset > megaCfg->procidx) { \
+        *eof = TRUE; \
+        megaCfg->procidx = 0; \
+        megaCfg->procbuf[0] = 0; \
+	return 0;} \
+  if ((count + offset) > megaCfg->procidx) { \
+      count = megaCfg->procidx - offset; \
+      *eof = TRUE; } \
+      memcpy(page, &megaCfg->procbuf[offset], count); \
+      megaCfg->procidx = 0; \
+      megaCfg->procbuf[0] = 0; 
+#endif
 /*================================================================
  *
  *                    Global variables
@@ -340,6 +416,8 @@
     XX scsi id on each channel.  Used for Madrona motherboard, where SAF_TE
     processor id cannot be scanned */
 
+
+
 static char *megaraid;
 #if LINUX_VERSION_CODE > 0x20100
 #ifdef MODULE
@@ -350,6 +428,7 @@
 
 static int numCtlrs = 0;
 static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = {0};
+struct proc_dir_entry *mega_proc_dir_entry;
 
 #if DEBUG
 static u32 maxCmdTime = 0;
@@ -362,11 +441,20 @@
 volatile static spinlock_t serial_lock;
 #endif
 
+
+#if LINUX_VERSION_CODE < 0x20300
 struct proc_dir_entry proc_scsi_megaraid =
 {
   PROC_SCSI_MEGARAID, 8, "megaraid",
   S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
+#else
+struct proc_dir_entry *proc_scsi_megaraid;
+#endif
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry proc_root;
+#endif
 
 #if SERDEBUG
 static char strbuf[MAX_SERBUF + 1];
@@ -554,7 +642,7 @@
   return 0;
 }
 
-/* Run through the list of completed requests */
+/* Run through the list of completed requests  and finish it*/
 static void mega_rundoneq (mega_host_config *megaCfg)
 {
   Scsi_Cmnd *SCpnt;
@@ -597,6 +685,8 @@
   mega_passthru *pthru;
   mega_mailbox *mbox;
 
+
+
   if (pScb == NULL) {
 	TRACE(("NULL pScb in mega_cmd_done!"));
 	printk("NULL pScb in mega_cmd_done!");
@@ -628,6 +718,7 @@
 
 if ((SCpnt->cmnd[0] & 0x80) ) {/* i.e. ioctl cmd such as 0x80, 0x81 of megamgr*/
     switch (status) {
+      case 2:
       case 0xF0:
       case 0xF4:
 	SCpnt->result=(DID_BAD_TARGET<<16)|status;
@@ -662,12 +753,7 @@
     break;
   }
  }
-  if ( SCpnt->cmnd[0]!=IOCTL_CMD_NEW ) 
-  /* not IOCTL_CMD_NEW SCB, freeSCB()*/
-  /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue()
-   * after copy data back to user space*/
      mega_freeSCB(megaCfg, pScb);
-
   /* Add Scsi_Command to end of completed queue */
     if( megaCfg->qCompletedH == NULL ) {
       megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
@@ -698,8 +784,8 @@
   char islogical;
   char lun = SCpnt->lun;
 
-  if ((SCpnt->cmnd[0] == 0x80)  || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) )  /* ioctl */
-    return mega_ioctl (megaCfg, SCpnt);
+  if ((SCpnt->cmnd[0] == 0x80)  || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) )  
+    return mega_ioctl (megaCfg, SCpnt); /* Handle IOCTL command */
  
   islogical = (SCpnt->channel == megaCfg->host->max_channel);
 
@@ -715,7 +801,7 @@
 	return NULL;
   }
 
-  if ( islogical ) {
+  if (islogical) {
 	lun = (SCpnt->target * 8) + lun;
         if ( lun > FC_MAX_LOGICAL_DRIVES ){
             SCpnt->result = (DID_BAD_TARGET << 16);
@@ -797,6 +883,15 @@
 	  ((u32) SCpnt->cmnd[2] << 8) |
 	  (u32) SCpnt->cmnd[3];
 	mbox->lba &= 0x1FFFFF;
+
+        if (*SCpnt->cmnd == READ_6) { 
+		megaCfg->nReads[(int)lun]++;
+                megaCfg->nReadBlocks[(int)lun] += mbox->numsectors;
+        }
+        else {
+		megaCfg->nWrites[(int)lun]++;
+                megaCfg->nWriteBlocks[(int)lun] += mbox->numsectors;
+       }
       }
 
       /* 10-byte */
@@ -809,6 +904,15 @@
 	  ((u32) SCpnt->cmnd[3] << 16) |
 	  ((u32) SCpnt->cmnd[4] << 8) |
 	  (u32) SCpnt->cmnd[5];
+
+        if (*SCpnt->cmnd == READ_10) { 
+		megaCfg->nReads[(int)lun]++;
+                megaCfg->nReadBlocks[(int)lun] += mbox->numsectors;
+        }
+        else {
+		megaCfg->nWrites[(int)lun]++;
+                megaCfg->nWriteBlocks[(int)lun] += mbox->numsectors;
+        }
       }
 
       /* Calculate Scatter-Gather info */
@@ -865,6 +969,42 @@
   return NULL;
 }
 
+/* Handle Driver Level IOCTLs 
+ * Return value of 0 indicates this function could not handle , so continue
+ * processing 
+*/
+
+static int mega_driver_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+  unsigned char *data = (unsigned char *)SCpnt->request_buffer;
+  mega_driver_info driver_info;
+
+  /* If this is not our command dont do anything */
+  if (SCpnt->cmnd[0] != DRIVER_IOCTL_INTERFACE)
+	return 0;
+
+  switch(SCpnt->cmnd[1]) {
+  case GET_DRIVER_INFO:
+                if (SCpnt->request_bufflen < sizeof(driver_info)) {
+			SCpnt->result = DID_BAD_TARGET << 16 ;
+			callDone(SCpnt);
+			return 1;
+		}
+		
+		driver_info.size = sizeof(driver_info) - sizeof(int);
+		driver_info.version = MEGARAID_IOCTL_VERSION;
+		memcpy( data, &driver_info, sizeof(driver_info));
+		break;
+   default:
+		SCpnt->result = DID_BAD_TARGET << 16;
+  }  
+
+ callDone(SCpnt);
+ return 1;
+}
+  
+
+
 /*--------------------------------------------------------------------
  * build RAID commands for controller, passed down through ioctl()
  *--------------------------------------------------------------------*/
@@ -875,9 +1015,9 @@
   mega_mailbox *mailbox;
   mega_passthru *pthru;
   u8 *mboxdata;
-  long seg;
+  long seg, i;
   unsigned char *data = (unsigned char *)SCpnt->request_buffer;
-  int i;
+  
 
   if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
     SCpnt->result = (DID_ERROR << 16);
@@ -911,8 +1051,8 @@
 					 (u32 *) & pthru->dataxferaddr,
 					 (u32 *) & pthru->dataxferlen);
 
-    for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) {
-       data[i] = data[i+cdblen+7];
+    for (i = 0 ; i < (SCpnt->request_bufflen - cdblen - 7) ; i++) {
+       data[i] = data[i + cdblen + 7];
     }
 
     return pScb;
@@ -928,29 +1068,65 @@
  */
 
   if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) { 
-            /* use external data area for large xfers  */
+      /* use external data area for large xfers  */
      /* If cmnd[0] is set to IOCTL_CMD_NEW then *
       *   cmnd[4..7] = external user buffer     *
       *   cmnd[8..11] = length of buffer        *
       *                                         */
-      char *kern_area;
       char *user_area = *((char **)&SCpnt->cmnd[4]);
       u32 xfer_size = *((u32 *)&SCpnt->cmnd[8]);
-      if (verify_area(VERIFY_READ, user_area, xfer_size)) {
-          printk("megaraid: Got bad user address.\n");
+      switch (data[0])
+      {
+		case FW_FIRE_WRITE:
+		case FW_FIRE_FLASH:
+	     if ((ulong)user_area & (PAGE_SIZE - 1)) {
+          printk("megaraid:user address not aligned on 4K boundary.Error.\n");
+          SCpnt->result = (DID_ERROR << 16);
+          callDone (SCpnt);
+          return NULL;
+	     }
+	     break;
+		default:
+		 break;
+	  }
+      if(!(pScb->buff_ptr = kmalloc(xfer_size, GFP_KERNEL))) {
+          printk("megaraid: Insufficient mem for IOCTL_CMD_NEW.\n");
           SCpnt->result = (DID_ERROR << 16);
           callDone (SCpnt);
           return NULL;
       }
-      kern_area = kmalloc(xfer_size, GFP_ATOMIC | GFP_DMA);
-      if (kern_area == NULL) {
-          printk("megaraid: Couldn't allocate kernel mem.\n");
-	  SCpnt->result = (DID_ERROR << 16);
-	  callDone (SCpnt);
-	  return NULL;
-      }
-      copy_from_user(kern_area,user_area,xfer_size);
-      pScb->kern_area = kern_area;
+
+      copy_from_user(pScb->buff_ptr,user_area,xfer_size);
+      pScb->sgList[0].address = virt_to_bus(pScb->buff_ptr);
+      pScb->sgList[0].length = xfer_size;
+	  pScb->iDataSize = xfer_size;
+      mbox->xferaddr = virt_to_bus(pScb->sgList);
+      mbox->numsgelements = 1;
+	  
+      switch (data[0])
+      {
+		case DCMD_FC_CMD:
+		switch (data[1])
+		{
+  		  case DCMD_FC_READ_NVRAM_CONFIG: 
+      	  case DCMD_GET_DISK_CONFIG:
+          {
+	  		if ((ulong) pScb->buff_ptr & (PAGE_SIZE - 1)) {
+          	  printk("megaraid:user address not sufficient Error.\n");
+              SCpnt->result = (DID_ERROR << 16);
+              callDone (SCpnt);
+              return NULL;
+	        }
+			//building SG list
+     		mega_build_kernel_sg(pScb->buff_ptr, xfer_size, pScb, mbox);
+	        break;
+	    }
+	    default:
+		  break;
+	  }//switch (data[1])
+	  break;
+    }
+
   }
 #endif
 
@@ -961,16 +1137,59 @@
   mbox->logdrv = data[4];
 
   if(SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
-      if(data[0]==DCMD_FC_CMD){ /*i.e. 0xA1, then override some mbox data */
+      switch (data[0]) {
+        case FW_FIRE_WRITE:
+	      mbox->cmd = FW_FIRE_WRITE;
+	      mbox->channel = data[1]; /* Current Block Number */
+          mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+	      mbox->numsgelements = 0;
+	      break;
+		case FW_FIRE_FLASH:
+	      mbox->cmd = FW_FIRE_FLASH;
+	      mbox->channel = data[1] | 0x80 ; /* Origin */
+          mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+	      mbox->numsgelements = 0;
+	      break;
+		case DCMD_FC_CMD:
           *(mboxdata+0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD*/
-          *(mboxdata+2) = data[2]; /*sub command*/
-          *(mboxdata+3) = 0;       /*number of elements in SG list*/
-          mbox->xferaddr           /*i.e. mboxdata byte 0x8 to 0xb*/
-                        = virt_to_bus(pScb->kern_area);
-      }
-      else{
-         mbox->xferaddr = virt_to_bus(pScb->kern_area);
-         mbox->numsgelements = 0;
+          *(mboxdata+2) = data[1]; /*sub command*/
+	      switch (data[1]) 
+	      {
+			case DCMD_FC_READ_NVRAM_CONFIG: 
+              *(mboxdata+3) = mbox->numsgelements;       /*number of elements in SG list*/
+	          break;
+    		case DCMD_WRITE_CONFIG:
+	          mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+	          mbox->numsgelements = 0;
+			  break;
+        	case DCMD_GET_DISK_CONFIG:
+          	  *(mboxdata+3) = data[2];       /*number of elements in SG list*/
+          	  *(mboxdata+4) = mbox->numsgelements;       /*number of elements in SG list*/
+			  break;
+        	case DCMD_DELETE_LOGDRV:	
+        	case DCMD_DELETE_DRIVEGROUP:
+    		case NC_SUBOP_ENQUIRY3:
+              *(mboxdata+3) = data[2]; 
+	          mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+	          mbox->numsgelements = 0;
+			  break;
+        	case DCMD_CHANGE_LDNO:	
+        	case DCMD_CHANGE_LOOPID:
+              *(mboxdata+3) = data[2]; 
+              *(mboxdata+4) = data[3]; 
+	          mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+	    	  mbox->numsgelements = 0;
+			  break;
+			default:
+	          mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+	          mbox->numsgelements = 0;
+			  break;
+	      }//switch
+		  break;
+		default:
+          mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+          mbox->numsgelements = 0;
+		  break;
       }
   } 
   else {
@@ -987,6 +1206,37 @@
   return (pScb);
 }
 
+void mega_build_kernel_sg(char *barea, ulong xfersize, mega_scb *pScb,
+			 mega_ioctl_mbox *mbox) 
+{
+    ulong i, buffer_area, len, end, end_page, x, idx = 0;
+
+    buffer_area = (ulong)barea;
+    i = buffer_area;
+    end = buffer_area + xfersize;
+    end_page = (end) & ~(PAGE_SIZE - 1);
+
+    do {
+    	len =  PAGE_SIZE - (i % PAGE_SIZE);
+    	x = pScb->sgList[idx].address = virt_to_bus((volatile void *)i);
+    	pScb->sgList[idx].length = len;
+        i += len;
+        idx++;
+	} while (i < end_page);
+ 
+    if ((end - i)< 0) {
+          printk("megaraid:Error in user address\n");
+    }       
+	
+	if (end - i) {
+    	pScb->sgList[idx].address = virt_to_bus((volatile void *)i);
+    	pScb->sgList[idx].length = end - i;
+		idx++; 
+	}
+	mbox->xferaddr = virt_to_bus(pScb->sgList);
+	mbox->numsgelements = idx;
+}
+
 #if DEBUG
 static void showMbox(mega_scb *pScb)
 {
@@ -1065,7 +1315,7 @@
 #if LINUX_VERSION_CODE >= 0x20100
     IO_LOCK;
 #endif
-
+    megaCfg->nInterrupts++;
     qCnt = 0xff;
     while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) 
       ;
@@ -1135,17 +1385,21 @@
           continue;
 	}
 
-        if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW) 
-        {    /* external user buffer */
-           up(&pScb->sem);
-        }
-	/* Mark command as completed */
-	mega_cmd_done(megaCfg, pScb, qStatus);
-
+	/* We don't want the ISR routine to touch IOCTL_CMD_NEW commands, so
+	 * don't mark them as complete, instead we pop their semaphore so
+	 * that the queue routine can finish them off
+	 */
+	if(pScb->SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
+		/* save the status byte for the queue routine to use */
+		pScb->SCpnt->result = qStatus;
+		up(&pScb->ioctl_sem);
+	} else {
+		/* Mark command as completed */
+		mega_cmd_done(megaCfg, pScb, qStatus);
+	}
       }
       else {
         printk("megaraid: wrong cmd id completed from firmware:id=%x\n",sIdx);
-	for(;;);
       }
     }
 
@@ -1200,19 +1454,23 @@
 	      mega_scb * pScb,
 	      int intr)
 {
-  mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
+  volatile mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
   u_char byte;
-  u32 cmdDone;
+
+#ifdef __LP64__
+  u64 phys_mbox;
+#else
   u32 phys_mbox;
+#endif
   u8 retval=-1;
 
-  mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0);   /* Set cmdid */
+  mboxData[0x1] = (pScb ? pScb->idx + 1: 0xFE);   /* Set cmdid */
   mboxData[0xF] = 1;		/* Set busy */
 
   phys_mbox = virt_to_bus (megaCfg->mbox);
 
 #if DEBUG
-  showMbox(pScb);
+  ShowMbox(pScb);
 #endif
 
   /* Wait until mailbox is free */
@@ -1237,7 +1495,7 @@
 
   /* Copy mailbox data into host structure */
   megaCfg->mbox64->xferSegment = 0;
-  memcpy (mbox, mboxData, 16);
+  memcpy ((char *)mbox, mboxData, 16);
 
   /* Kick IO */
   if (intr) {
@@ -1261,10 +1519,18 @@
     if (megaCfg->flag & BOARD_QUARTZ) {
       mbox->mraid_poll = 0;
       mbox->mraid_ack = 0;
+      mbox->numstatus = 0xFF;
+      mbox->status = 0xFF;
       WRINDOOR (megaCfg, phys_mbox | 0x1);
 
-      while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
-      WROUTDOOR (megaCfg, cmdDone);
+     while (mbox->numstatus == 0xFF);
+     while (mbox->status == 0xFF);
+     while (mbox->mraid_poll != 0x77);
+     mbox->mraid_poll = 0;
+     mbox->mraid_ack = 0x77;
+ 
+    /* while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
+      WROUTDOOR (megaCfg, cmdDone);*/
 
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
@@ -1361,9 +1627,15 @@
 {
   /* align on 16-byte boundry */
   megaCfg->mbox = &megaCfg->mailbox64.mailbox;
-  megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xfffffff0);
+#ifdef __LP64__
+  megaCfg->mbox = (mega_mailbox *) ((((u64) megaCfg->mbox) + 16) & ( (ulong)(-1) ^ 0x0F)  );
   megaCfg->mbox64 = (mega_mailbox64 *) (megaCfg->mbox - 4);
-  paddr = (paddr + 4 + 16) & 0xfffffff0;
+  paddr = (paddr + 4 + 16) & ( (u64)(-1) ^ 0x0F );
+#else
+  megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xFFFFFFF0);
+  megaCfg->mbox64 = (mega_mailbox64 *) (megaCfg->mbox - 4);
+  paddr = (paddr + 4 + 16) & 0xFFFFFFF0;
+#endif
 
   /* Register mailbox area with the firmware */
   if (!(megaCfg->flag & BOARD_QUARTZ)) {
@@ -1509,10 +1781,10 @@
 	   megaCfg->productInfo.BiosVer[2] >> 8,
 	   megaCfg->productInfo.BiosVer[2] & 0x0f);
 #else
-  memcpy (megaCfg->fwVer, megaCfg->productInfo.FwVer, 4);
+  memcpy (megaCfg->fwVer, (char *)megaCfg->productInfo.FwVer, 4);
   megaCfg->fwVer[4] = 0;
 
-  memcpy (megaCfg->biosVer, megaCfg->productInfo.BiosVer, 4);
+  memcpy (megaCfg->biosVer, (char *)megaCfg->productInfo.BiosVer, 4);
   megaCfg->biosVer[4] = 0;
 #endif
 
@@ -1537,6 +1809,7 @@
 		    int length, int host_no, int inout)
 {
   *start = buffer;
+  
   return 0;
 }
 
@@ -1544,37 +1817,83 @@
 	  u16 pciVendor, u16 pciDev,
 	  long flag)
 {
-  mega_host_config *megaCfg;
-  struct Scsi_Host *host;
+  mega_host_config *megaCfg = NULL;
+  struct Scsi_Host *host = NULL;
   u_char pciBus, pciDevFun, megaIrq;
+
+#ifdef __LP64__
+  u64 megaBase;
+#else
   u32 megaBase;
+#endif
+
   u16 pciIdx = 0;
   u16 numFound = 0;
 
 #if LINUX_VERSION_CODE < 0x20100
   while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
 #else
-  
+#if LINUX_VERSION_CODE > 0x20300
+  struct pci_dev *pdev = NULL;
+#else  
   struct pci_dev *pdev = pci_devices;
+#endif
   
   while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
+
+#ifdef DELL_MODIFICATION 
+    if (pci_enable_device(pdev))
+    	continue;
+#endif	
     pciBus = pdev->bus->number;
     pciDevFun = pdev->devfn;
 #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 */
       }
     }
+
+/* Hmmm...Should we not make this more modularized so that in future we dont add
+   for each firmware */
+	
+	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=2940\n");
+			continue;
+			}
+		}
+
     printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n",
 	    pciVendor,
 	    pciDev,
@@ -1590,21 +1909,21 @@
     pcibios_read_config_byte (pciBus, pciDevFun,
 			      PCI_INTERRUPT_LINE,
 			      &megaIrq);
-#else
+#elif LINUX_VERSION_CODE < 0x20300
     megaBase = pdev->base_address[0];
     megaIrq  = pdev->irq;
+#else
+
+    megaBase = pci_resource_start (pdev, 0);
+    megaIrq  = pdev->irq;
 #endif
-    pciIdx++;
 
-    if (flag & BOARD_QUARTZ) {
+    pciIdx++;
 
-      megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
-      megaBase = (long) ioremap (megaBase, 128);
-    }
-    else {
-      megaBase &= PCI_BASE_ADDRESS_IO_MASK;
-      megaBase += 0x10;
-    }
+    if (flag & BOARD_QUARTZ)
+       megaBase = (long) ioremap (megaBase, 128);
+    else
+       megaBase += 0x10;
 
     /* Initialize SCSI Host structure */
     host = scsi_register (pHostTmpl, sizeof (mega_host_config));
@@ -1632,6 +1951,7 @@
     megaCfg->host->n_io_port = 16;
     megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
     megaCtlrs[numCtlrs++] = megaCfg; 
+
     if (flag != BOARD_QUARTZ) {
       /* Request our IO Range */
       if (check_region (megaBase, 16)) {
@@ -1654,42 +1974,9 @@
     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=2940\n");
-	megaraid_release (host);
-#ifdef MODULE	
-	continue;
-#else
-	while(1) schedule_timeout(1 * HZ);
-#endif	
-      }
-    }
-
     /* Initialize SCBs */
     if (mega_initSCB (megaCfg)) {
-      megaraid_release (host);
+      scsi_unregister (host);
       continue;
     }
 
@@ -1703,9 +1990,13 @@
  *---------------------------------------------------------*/
 int megaraid_detect (Scsi_Host_Template * pHostTmpl)
 {
-  int count = 0;
+  int ctlridx = 0, count = 0;
 
+#if LINUX_VERSION_CODE < 0x20300
   pHostTmpl->proc_dir = &proc_scsi_megaraid;
+#else
+  pHostTmpl->proc_name = "megaraid";
+#endif
 
 #if LINUX_VERSION_CODE < 0x20100
   if (!pcibios_present ()) {
@@ -1726,9 +2017,31 @@
 
   printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
 
-  count += mega_findCard (pHostTmpl, 0x101E, 0x9010, 0);
-  count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0);
-  count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+  count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+			  PCI_DEVICE_ID_AMI_MEGARAID, 0);
+  count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+			  PCI_DEVICE_ID_AMI_MEGARAID2, 0);
+  count += mega_findCard (pHostTmpl, 0x8086,
+			  PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+  count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+			  PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+
+#ifdef CONFIG_PROC_FS
+  if (count) {
+#if LINUX_VERSION_CODE > 0x20300 
+        mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
+#else
+        mega_proc_dir_entry = create_proc_entry("megaraid", 
+						S_IFDIR | S_IRUGO | S_IXUGO,
+						&proc_root);    
+#endif
+        if (!mega_proc_dir_entry)
+        	printk("megaraid: failed to create megaraid root\n");
+        else
+  		for (ctlridx = 0; ctlridx < count ; ctlridx++) 
+			mega_create_proc_entry(ctlridx, mega_proc_dir_entry);
+  }
+#endif
 
   return count;
 }
@@ -1741,6 +2054,7 @@
   mega_host_config *megaCfg;
   mega_mailbox *mbox;
   u_char mboxData[16];
+  int i;
 
   megaCfg = (mega_host_config *) pSHost->hostdata;
   mbox = (mega_mailbox *) mboxData;
@@ -1766,6 +2080,22 @@
   mega_freeSgList(megaCfg);
   scsi_unregister (pSHost);
 
+#ifdef CONFIG_PROC_FS
+  if (megaCfg->controller_proc_dir_entry) {
+	  remove_proc_entry("stat",megaCfg->controller_proc_dir_entry);
+	  remove_proc_entry("status", megaCfg->controller_proc_dir_entry);
+	  remove_proc_entry("config", megaCfg->controller_proc_dir_entry);
+	  remove_proc_entry("mailbox", megaCfg->controller_proc_dir_entry);
+          for (i = 0; i < numCtlrs; i++) {
+                char buf[12];
+                memset(buf,0,12);
+		sprintf(buf,"%d",i);
+          	remove_proc_entry(buf,mega_proc_dir_entry);
+	 }
+         remove_proc_entry("megaraid", &proc_root);
+  }  
+#endif
+
   return 0;
 }
 
@@ -1818,6 +2148,7 @@
   DRIVER_LOCK_T
   mega_host_config *megaCfg;
   mega_scb *pScb;
+  char *user_area = NULL;
 
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
   DRIVER_LOCK(megaCfg);
@@ -1835,6 +2166,9 @@
 
   SCpnt->scsi_done = pktComp;
 
+  if (mega_driver_ioctl(megaCfg, SCpnt))
+	return 0;
+
   /* If driver in abort or reset.. cancel this command */
   if (megaCfg->flag & IN_ABORT) {
     SCpnt->result = (DID_ABORT << 16);
@@ -1886,31 +2220,31 @@
     megaCfg->qPcnt++;
 
       mega_runpendq(megaCfg);
+  if(pScb->SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
+    pScb->ioctl_sem = MUTEX_LOCKED;
+    spin_unlock_irq(&io_request_lock);
+    down(&pScb->ioctl_sem);
+    user_area = *((char **)&pScb->SCpnt->cmnd[4]);
+    if(copy_to_user(user_area,pScb->buff_ptr,pScb->iDataSize)) {
+       printk("megaraid: Error copying ioctl return value to user buffer.\n");
+       pScb->SCpnt->result = (DID_ERROR << 16);
+    }
+    spin_lock_irq(&io_request_lock);
+    DRIVER_LOCK(megaCfg);
+    kfree(pScb->buff_ptr);
+    pScb->buff_ptr = NULL;
+    mega_cmd_done(megaCfg, pScb, pScb->SCpnt->result);
+    mega_rundoneq(megaCfg);
+    mega_runpendq(megaCfg);
+    DRIVER_UNLOCK(megaCfg);
+  }
 
-#if LINUX_VERSION_CODE > 0x020024
-    if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
-    {  /* user data from external user buffer */
-          char *user_area;
-          u32  xfer_size;
-
-          pScb->sem=MUTEX_LOCKED;
-          down(&pScb->sem);
-
-          user_area = *((char **)&pScb->SCpnt->cmnd[4]);
-          xfer_size = *((u32 *)&pScb->SCpnt->cmnd[8]);
-
-          copy_to_user(user_area,pScb->kern_area,xfer_size);
-
-          kfree(pScb->kern_area);
+  megaCfg->flag &= ~IN_QUEUE;
 
-          mega_freeSCB(megaCfg, pScb);
-    }
-#endif
   }
 
-  megaCfg->flag &= ~IN_QUEUE;
-  DRIVER_UNLOCK(megaCfg);
 
+  DRIVER_UNLOCK(megaCfg);
   return 0;
 }
 
@@ -1919,7 +2253,13 @@
  *----------------------------------------------------------------------*/
 volatile static int internal_done_flag = 0;
 volatile static int internal_done_errcode = 0;
-static struct wait_queue *internal_wait = NULL;
+
+#if LINUX_VERSION_CODE < 0x20300
+	static struct wait_queue *internal_wait = NULL;
+#else
+	static DECLARE_WAIT_QUEUE_HEAD(internal_wait);
+#endif
+
 
 static void internal_done (Scsi_Cmnd * SCpnt)
 {
@@ -2079,6 +2419,221 @@
   mega_rundoneq(megaCfg);
   return rc;
 }
+
+
+#ifdef CONFIG_PROC_FS
+/* Following code handles /proc fs  */
+static int proc_printf (mega_host_config *megaCfg, const char *fmt,...)
+{
+  va_list args;
+  int i;
+  
+  if (megaCfg->procidx > PROCBUFSIZE)
+     return 0;
+
+  va_start (args, fmt);
+  i = vsprintf ((megaCfg->procbuf + megaCfg->procidx), fmt, args);
+  va_end (args);
+  
+  megaCfg->procidx += i;
+  return i;
+}
+
+
+static int proc_read_config(char *page, char **start, off_t offset,
+				int count, int *eof, void *data) 
+{
+
+   mega_host_config *megaCfg = (mega_host_config *)data; 
+  
+   *start = page;
+
+   if (megaCfg->productInfo.ProductName[0] != 0)
+  	 proc_printf(megaCfg,"%s\n",megaCfg->productInfo.ProductName);
+	
+   proc_printf(megaCfg,"Controller Type: ");
+
+   if (megaCfg->flag & BOARD_QUARTZ)
+ 	proc_printf(megaCfg,"438/466/467/471/493\n");
+   else
+	proc_printf(megaCfg,"418/428/434\n");
+
+   if (megaCfg->flag & BOARD_40LD)
+       proc_printf(megaCfg,"Controller Supports 40 Logical Drives\n");
+
+   proc_printf(megaCfg,"Base = %08x, Irq = %d, ",megaCfg->base,
+						 megaCfg->host->irq);
+
+   proc_printf(megaCfg, "Logical Drives = %d, Channels = %d\n",
+			megaCfg->numldrv, megaCfg->productInfo.SCSIChanPresent);
+
+   proc_printf(megaCfg, "Version =%s:%s, DRAM = %dMb\n",
+			megaCfg->fwVer,megaCfg->biosVer, 
+			megaCfg->productInfo.DramSize);
+
+   proc_printf(megaCfg,"Controller Queue Depth = %d, Driver Queue Depth = %d\n",
+		megaCfg->productInfo.MaxConcCmds, megaCfg->max_cmds);   
+   COPY_BACK;
+   return count;
+}
+
+
+
+static int proc_read_stat(char *page, char **start, off_t offset,
+				int count, int *eof, void *data) 
+{
+   int i;
+   mega_host_config *megaCfg = (mega_host_config *)data; 
+
+   *start = page;
+
+   proc_printf(megaCfg,"Statistical Information for this controller\n");
+   proc_printf(megaCfg,"Interrupts Collected = %d\n", megaCfg->nInterrupts);
+
+   for (i = 0; i < megaCfg->numldrv; i++) {
+	proc_printf(megaCfg,"Logical Drive %d:\n", i);
+        proc_printf(megaCfg,"\tReads Issued = %10d, Writes Issued = %10d\n",
+			megaCfg->nReads[i], megaCfg->nWrites[i]);
+        
+        proc_printf(megaCfg,"\tSectors Read = %10d, Sectors Written = %10d\n\n",				megaCfg->nReadBlocks[i],
+				megaCfg->nWriteBlocks[i]);
+   }
+
+   COPY_BACK;
+   return count;
+}
+
+        
+
+static int proc_read_status(char *page, char **start, off_t offset,
+				int count, int *eof, void *data) 
+{
+ mega_host_config *megaCfg = (mega_host_config *)data;
+ *start = page;
+
+ proc_printf(megaCfg,"TBD\n");
+ COPY_BACK;
+ return count;
+}
+
+
+static int proc_read_mbox(char *page, char **start, off_t offset,
+				int count, int *eof, void *data) 
+{
+// int i;
+// char *dta = NULL;
+ mega_host_config *megaCfg = (mega_host_config *)data;
+ volatile mega_mailbox *mbox = megaCfg->mbox;
+
+ *start = page;
+
+ proc_printf(megaCfg,"Contents of Mail Box Structure\n");
+ proc_printf(megaCfg,"  Fw Command   = 0x%02x\n", mbox->cmd);
+ proc_printf(megaCfg,"  Cmd Sequence = 0x%02x\n", mbox->cmdid);
+ proc_printf(megaCfg,"  No of Sectors= %04d\n", mbox->numsectors);
+ proc_printf(megaCfg,"  LBA          = 0x%02x\n", mbox->lba);
+ proc_printf(megaCfg,"  DTA          = 0x%08x\n", mbox->xferaddr);
+ proc_printf(megaCfg,"  Logical Drive= 0x%02x\n", mbox->logdrv);
+ proc_printf(megaCfg,"  No of SG Elmt= 0x%02x\n", mbox->numsgelements);
+ proc_printf(megaCfg,"  Busy         = %01x\n", mbox->busy); 
+ proc_printf(megaCfg,"  Status       = 0x%02x\n", mbox->status);
+
+/* proc_printf(megaCfg, "Dump of MailBox\n");
+ for (i = 0; i < 16; i++)
+	proc_printf(megaCfg, "%02x ",*(mbox + i));
+
+proc_printf(megaCfg, "\n\nNumber of Status = %02d\n",mbox->numstatus);
+
+ for (i = 0; i < 46; i++) {
+	proc_printf(megaCfg,"%02d ",*(mbox + 16 + i));
+        if (i%16)
+		proc_printf(megaCfg,"\n");
+}
+
+if (!mbox->numsgelements) { 
+	dta = phys_to_virt(mbox->xferaddr);
+	for (i = 0; i < mbox->numsgelements; i++) 
+		if (dta) {
+			proc_printf(megaCfg,"Addr = %08x\n", (ulong)*(dta + i));			proc_printf(megaCfg,"Length = %08x\n", 
+				(ulong)*(dta + i + 4));
+		}
+}*/
+ COPY_BACK;
+ return count;
+}
+
+
+#if LINUX_VERSION_CODE > 0x20300
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string, \
+					 S_IRUSR | S_IFREG,\
+					 controller_proc_dir_entry,\
+					 fxn, megaCfg)
+#else 
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string,S_IRUSR | S_IFREG, controller_proc_dir_entry, fxn, megaCfg)
+
+struct proc_dir_entry *create_proc_read_entry(const char *string,
+			int mode,
+			struct proc_dir_entry *parent,
+ 			read_proc_t *fxn, 
+			mega_host_config *megaCfg) 
+{
+	struct proc_dir_entry *temp = NULL;
+	
+        temp = kmalloc(sizeof(struct proc_dir_entry),
+			GFP_KERNEL);
+        if (!temp)
+		return NULL;
+	memset(temp, 0, sizeof(struct proc_dir_entry));
+
+        if ( (temp->name = kmalloc(strlen(string) + 1, GFP_KERNEL)) == NULL) {
+		kfree(temp);
+		return NULL;
+	}
+
+	strcpy((char *)temp->name, string);
+	temp->namelen = strlen(string);
+        temp->mode = mode ; /*S_IFREG | S_IRUSR*/;
+	temp->data = (void *)megaCfg;
+        temp->read_proc = fxn;
+	proc_register(parent, temp);
+        return temp;
+}
+#endif
+
+		
+	 
+void mega_create_proc_entry(int index, struct proc_dir_entry *parent)
+{
+    u_char string[64] = {0};
+    mega_host_config *megaCfg = megaCtlrs[index];
+    struct proc_dir_entry *controller_proc_dir_entry = NULL;
+
+    sprintf(string,"%d", index);
+
+#if LINUX_VERSION_CODE > 0x20300
+    controller_proc_dir_entry = 
+    megaCfg->controller_proc_dir_entry = 
+		proc_mkdir(string, parent);
+#else
+    controller_proc_dir_entry = 
+    megaCfg->controller_proc_dir_entry = 
+        create_proc_entry(string,S_IFDIR | S_IRUGO | S_IXUGO, parent);
+#endif    
+
+    if (!controller_proc_dir_entry)
+   	printk("\nmegaraid: proc_mkdir failed\n");
+    else 
+    { 	
+	megaCfg->proc_read = CREATE_READ_PROC("config", proc_read_config);
+    	megaCfg->proc_status = CREATE_READ_PROC("status", proc_read_status);
+    	megaCfg->proc_stat = CREATE_READ_PROC("stat", proc_read_stat);
+    	megaCfg->proc_mbox = CREATE_READ_PROC("mailbox", proc_read_mbox);
+    }
+   
+}
+#endif /* CONFIG_PROC_FS */
+ 
+	
 
 /*-------------------------------------------------------------
  * Return the disk geometry for a particular disk
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/megaraid.h linux.18p8/drivers/scsi/megaraid.h
--- linux.vanilla/drivers/scsi/megaraid.h	Fri Jun 23 00:51:16 2000
+++ linux.18p8/drivers/scsi/megaraid.h	Fri Sep 15 15:13:38 2000
@@ -20,6 +20,11 @@
 #define SCB_ABORTED  0x5
 #define SCB_RESET    0x6
 
+/* IOCTL DRIVER INFO */
+#define DRIVER_IOCTL_INTERFACE 0x82
+/* Methods */
+#define GET_DRIVER_INFO 1
+
 #define MEGA_CMD_TIMEOUT        10
 
 /* Feel free to fiddle with these.. max values are:
@@ -94,13 +99,41 @@
 #define ENABLE_INTR(base)     WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE)
 #define DISABLE_INTR(base)    WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE)
 
+/* Special Adapter Commands */
+#define FW_FIRE_WRITE 	0x2C
+#define FW_FIRE_FLASH  	0x2D
+
+#define FC_NEW_CONFIG               0xA1
+#define DCMD_FC_CMD                 0xA1
+    #define DCMD_FC_PROCEED		0x02
+    #define DCMD_DELETE_LOGDRV		0x03
+    #define DCMD_FC_READ_NVRAM_CONFIG	0x04 
+    #define DCMD_FC_READ_FINAL_CONFIG	0x05
+    #define DCMD_GET_DISK_CONFIG	0x06
+    #define DCMD_CHANGE_LDNO		0x07
+    #define DCMD_COMPACT_CONFIG		0x08
+    #define DCMD_DELETE_DRIVEGROUP	0x09
+    #define DCMD_GET_LOOPID_INFO	0x0A
+    #define DCMD_CHANGE_LOOPID		0x0B
+    #define DCMD_GET_NUM_SCSI_CHANS	0x0C
+    #define DCMD_WRITE_CONFIG		0x0D /* writes 40-ld config */
+    #define NC_SUBOP_PRODUCT_INFO       0x0E
+    #define NC_SUBOP_ENQUIRY3           0x0F
+	#define ENQ3_GET_SOLICITED_NOTIFY_ONLY  0x01
+	#define ENQ3_GET_SOLICITED_FULL         0x02
+	#define ENQ3_GET_UNSOLICITED            0x03
+
 /* Define AMI's PCI codes */
 #undef PCI_VENDOR_ID_AMI
 #undef PCI_DEVICE_ID_AMI_MEGARAID
+#undef PCI_DEVICE_ID_AMI_MEGARAID2
+#undef PCI_DEVICE_ID_AMI_MEGARAID3
 
 #ifndef PCI_VENDOR_ID_AMI
 #define PCI_VENDOR_ID_AMI          0x101E
 #define PCI_DEVICE_ID_AMI_MEGARAID 0x9010
+#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060
+#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960
 #endif
 
 #define PCI_CONF_BASE_ADDR_OFFSET  0x10
@@ -526,8 +559,8 @@
     /* 0x10 */ u8 numstatus;
     /* 0x11 */ u8 status;
     /* 0x12 */ u8 completed[46];
-    u8 mraid_poll;
-    u8 mraid_ack;
+    volatile u8 mraid_poll;
+    volatile u8 mraid_ack;
     u8 pad[16]; /* for alignment purposes */
 }__attribute__((packed));
 typedef struct _mega_mailbox mega_mailbox;
@@ -572,9 +605,9 @@
     mega_passthru  pthru;
     Scsi_Cmnd     *SCpnt;
     mega_sglist   *sgList;
-    char          *kern_area;  /* Only used for large ioctl xfers */
-    struct wait_queue  *ioctl_wait;
-    struct semaphore   sem;
+    struct semaphore  ioctl_sem;
+    void	  *buff_ptr;
+	u32			iDataSize;
     mega_scb      *next;
 };
 
@@ -582,7 +615,12 @@
 typedef struct _mega_host_config {
     u8 numldrv;
     u32 flag;
+
+#ifdef __LP64__
+    u64 base;
+#else
     u32 base;
+#endif
  
     mega_scb *qFreeH;
     mega_scb *qFreeT;
@@ -596,8 +634,10 @@
     u32 qCcnt;
 
     u32 nReads[FC_MAX_LOGICAL_DRIVES];
+    u32 nReadBlocks[FC_MAX_LOGICAL_DRIVES];
     u32 nWrites[FC_MAX_LOGICAL_DRIVES];
-
+    u32 nWriteBlocks[FC_MAX_LOGICAL_DRIVES];
+    u32 nInterrupts;
     /* Host adapter parameters */
     u8 fwVer[7];
     u8 biosVer[7];
@@ -620,9 +660,22 @@
 
     u8 max_cmds;
     mega_scb scbList[MAX_COMMANDS];
+#define PROCBUFSIZE 4096
+    char procbuf[PROCBUFSIZE];
+    int   procidx;
+    struct proc_dir_entry *controller_proc_dir_entry;
+    struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox;
 } mega_host_config;
 
+typedef struct _driver_info {
+	int size;
+	ulong version;
+} mega_driver_info;
+
+
+#if LINUX_VERSION_CODE < 0x20300
 extern struct proc_dir_entry proc_scsi_megaraid;
+#endif
 
 const char *megaraid_info(struct Scsi_Host *);
 int megaraid_detect(Scsi_Host_Template *);
@@ -635,4 +688,6 @@
 int megaraid_proc_info(char *buffer, char **start, off_t offset,
 		       int length, int hostno, int inout);
 
+void mega_build_kernel_sg(char *, ulong , mega_scb *, mega_ioctl_mbox *); 
+void mega_create_proc_entry(int index, struct proc_dir_entry *);
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ncr53c8xx.c linux.18p8/drivers/scsi/ncr53c8xx.c
--- linux.vanilla/drivers/scsi/ncr53c8xx.c	Fri Apr 21 12:46:30 2000
+++ linux.18p8/drivers/scsi/ncr53c8xx.c	Sat Sep  2 19:38:56 2000
@@ -73,8 +73,6 @@
 */
 
 /*
-**	July 20 1999, version 3.2a-2
-**
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
 **	    Wide negotiation        (depends on the NCR Chip)
@@ -83,7 +81,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 +91,8 @@
 **		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)
+**		53C897		(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.4.1-20000726"
 
 #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>
@@ -143,15 +144,19 @@
 #include <linux/version.h>
 #include <linux/blk.h>
 
+#ifdef CONFIG_ALL_PPC
+#include <asm/prom.h>
+#endif
+
 #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)
@@ -182,98 +187,23 @@
 */
 typedef u32 u_int32;
 typedef u64 u_int64;
-
+typedef	u_long		vm_offset_t;
 #include "ncr53c8xx.h"
 
-/*==========================================================
-**
-**	A la VMS/CAM-3 queue management.
-**	Implemented from linux list management.
-**
-**==========================================================
+/*
+**	Donnot compile integrity checking code for Linux-2.3.0 
+**	and above since SCSI data structures are not ready yet.
 */
+/* #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) */
+#if 0
+#define	SCSI_NCR_INTEGRITY_CHECKING
+#endif
 
-typedef struct xpt_quehead {
-	struct xpt_quehead *flink;	/* Forward  pointer */
-	struct xpt_quehead *blink;	/* Backward pointer */
-} XPT_QUEHEAD;
-
-#define xpt_que_init(ptr) do { \
-	(ptr)->flink = (ptr); (ptr)->blink = (ptr); \
-} while (0)
-
-static inline void __xpt_que_add(struct xpt_quehead * new,
-	struct xpt_quehead * blink,
-	struct xpt_quehead * flink)
-{
-	flink->blink	= new;
-	new->flink	= flink;
-	new->blink	= blink;
-	blink->flink	= new;
-}
-
-static inline void __xpt_que_del(struct xpt_quehead * blink,
-	struct xpt_quehead * flink)
-{
-	flink->blink = blink;
-	blink->flink = flink;
-}
-
-static inline int xpt_que_empty(struct xpt_quehead *head)
-{
-	return head->flink == head;
-}
-
-static inline void xpt_que_splice(struct xpt_quehead *list,
-	struct xpt_quehead *head)
-{
-	struct xpt_quehead *first = list->flink;
-
-	if (first != list) {
-		struct xpt_quehead *last = list->blink;
-		struct xpt_quehead *at   = head->flink;
-
-		first->blink = head;
-		head->flink  = first;
-
-		last->flink = at;
-		at->blink   = last;
-	}
-}
-
-#define xpt_que_entry(ptr, type, member) \
-	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-
-
-#define xpt_insque(new, pos)		__xpt_que_add(new, pos, (pos)->flink)
-
-#define xpt_remque(el)			__xpt_que_del((el)->blink, (el)->flink)
-
-#define xpt_insque_head(new, head)	__xpt_que_add(new, head, (head)->flink)
-
-static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head)
-{
-	struct xpt_quehead *elem = head->flink;
-
-	if (elem != head)
-		__xpt_que_del(head, elem->flink);
-	else
-		elem = 0;
-	return elem;
-}
-
-#define xpt_insque_tail(new, head)	__xpt_que_add(new, (head)->blink, head)
-
-static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
-{
-	struct xpt_quehead *elem = head->blink;
+#define NAME53C			"ncr53c"
+#define NAME53C8XX		"ncr53c8xx"
+#define DRIVER_SMP_LOCK		ncr53c8xx_lock
 
-	if (elem != head)
-		__xpt_que_del(elem->blink, head);
-	else
-		elem = 0;
-	return elem;
-}
+#include "sym53c8xx_comm.h"
 
 /*==========================================================
 **
@@ -313,33 +243,6 @@
 
 /*==========================================================
 **
-**	On x86 architecture, write buffers management does 
-**	not reorder writes to memory. So, using compiler 
-**	optimization barriers is enough to guarantee some 
-**	ordering when the CPU is writing data accessed by 
-**	the NCR.
-**	On Alpha architecture, explicit memory barriers have 
-**	to be used.
-**	Other architectures are defaulted to mb() macro if  
-**	defined, otherwise use compiler barrier.
-**
-**==========================================================
-*/
-
-#if defined(__i386__)
-#define MEMORY_BARRIER()	barrier()
-#elif defined(__alpha__)
-#define MEMORY_BARRIER()	mb()
-#else
-#  ifdef mb
-#  define MEMORY_BARRIER()	mb()
-#  else
-#  define MEMORY_BARRIER()	barrier()
-#  endif
-#endif
-
-/*==========================================================
-**
 **	Configuration and Debugging
 **
 **==========================================================
@@ -369,8 +272,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 +282,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,7 +332,17 @@
 #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
 
 /*
@@ -451,264 +365,11 @@
 #endif
 
 /*
-**    Io mapped or memory mapped.
-*/
-
-#if defined(SCSI_NCR_IOMAPPED)
-#define NCR_IOMAPPED
-#endif
-
-/*
 **	other
 */
 
 #define NCR_SNOOP_TIMEOUT (1000000)
 
-/*==========================================================
-**
-**	Defines for Linux.
-**
-**	Linux and Bsd kernel functions are quite different.
-**	These defines allow a minimum change of the original
-**	code.
-**
-**==========================================================
-*/
-
- /*
- **	Obvious definitions
- */
-
-#define u_char		unsigned char
-#define u_short		unsigned short
-#define u_int		unsigned int
-#define u_long		unsigned long
-
-typedef	u_long		vm_offset_t;
-typedef	int		vm_size_t;
-
-#ifndef bcopy
-#define bcopy(s, d, n)	memcpy((d), (s), (n))
-#endif
-#ifndef bzero
-#define bzero(d, n)	memset((d), 0, (n))
-#endif
- 
-#ifndef offsetof
-#define offsetof(t, m)	((size_t) (&((t *)0)->m))
-#endif
-
-/*
-**	SMP threading.
-**
-**	Assuming that SMP systems are generally high end systems and may 
-**	use several SCSI adapters, we are using one lock per controller 
-**	instead of some global one. For the moment (linux-2.1.95), driver's 
-**	entry points are called with the 'io_request_lock' lock held, so:
-**	- We are uselessly loosing a couple of micro-seconds to lock the 
-**	  controller data structure.
-**	- But the driver is not broken by design for SMP and so can be 
-**	  more resistant to bugs or bad changes in the IO sub-system code.
-**	- A small advantage could be that the interrupt code is grained as 
-**	  wished (e.g.: threaded by controller).
-*/
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
-
-#if 0	/* not yet needed */
-static spinlock_t driver_lock;
-#define	NCR_LOCK_DRIVER(flags)     spin_lock_irqsave(&driver_lock, flags)
-#define	NCR_UNLOCK_DRIVER(flags)   spin_unlock_irqrestore(&driver_lock, flags)
-#endif
-
-#define NCR_INIT_LOCK_NCB(np)      spin_lock_init(&np->smp_lock);
-#define	NCR_LOCK_NCB(np, flags)    spin_lock_irqsave(&np->smp_lock, flags)
-#define	NCR_UNLOCK_NCB(np, flags)  spin_unlock_irqrestore(&np->smp_lock, flags)
-
-#	if LINUX_VERSION_CODE < LinuxVersionCode(2,3,99)
-
-#	define	NCR_LOCK_SCSI_DONE(np, flags) \
-		spin_lock_irqsave(&io_request_lock, flags)
-#	define	NCR_UNLOCK_SCSI_DONE(np, flags) \
-		spin_unlock_irqrestore(&io_request_lock, flags)
-
-#	else
-
-#	define	NCR_LOCK_SCSI_DONE(np, flags)    do {;} while (0)
-#	define	NCR_UNLOCK_SCSI_DONE(np, flags)  do {;} while (0)
-
-#	endif
-
-#else
-
-#if 0	/* not yet needed */
-#define	NCR_LOCK_DRIVER(flags)     do {;} while (0)
-#define	NCR_UNLOCK_DRIVER(flags)   do {;} while (0)
-#endif
-
-#define	NCR_INIT_LOCK_NCB(np)      do { } while (0)
-#define	NCR_LOCK_NCB(np, flags)    do { save_flags(flags); cli(); } while (0)
-#define	NCR_UNLOCK_NCB(np, flags)  do { restore_flags(flags); } while (0)
-
-#define	NCR_LOCK_SCSI_DONE(np, flags)    do {;} while (0)
-#define	NCR_UNLOCK_SCSI_DONE(np, flags)  do {;} while (0)
-
-#endif
-
-/*
-**	Address translation
-**
-**	The driver has to provide physical memory addresses to 
-**	the script processor. Because some architectures use 
-**	different physical addresses from the PCI BUS, we must 
-**	use virt_to_bus instead of virt_to_phys.
-*/
-
-#define vtophys(p)	virt_to_bus(p)
-
-/*
-**	Memory mapped IO
-**
-**	Since linux-2.1, we must use ioremap() to map the io memory space.
-**	iounmap() to unmap it. That allows portability.
-**	Linux 1.3.X and 2.0.X allow to remap physical pages addresses greater 
-**	than the highest physical memory address to kernel virtual pages with 
-**	vremap() / vfree(). That was not portable but worked with i386 
-**	architecture.
-*/
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
-#define ioremap vremap
-#define iounmap vfree
-#endif
-
-#if defined (__sparc__)
-#include <asm/irq.h>
-#elif defined (__alpha__)
-#define bus_dvma_to_mem(p)		((p) & 0xfffffffful)
-#else
-#define bus_dvma_to_mem(p)		(p)
-#endif
-
-#if defined(__i386__) || !defined(NCR_IOMAPPED)
-__initfunc(
-static vm_offset_t remap_pci_mem(u_long base, u_long size)
-)
-{
-	u_long page_base	= ((u_long) base) & PAGE_MASK;
-	u_long page_offs	= ((u_long) base) - page_base;
-	u_long page_remapped	= (u_long) ioremap(page_base, page_offs+size);
-
-	return (vm_offset_t) (page_remapped? (page_remapped + page_offs) : 0UL);
-}
-
-__initfunc(
-static void unmap_pci_mem(vm_offset_t vaddr, u_long size)
-)
-{
-	if (vaddr)
-		iounmap((void *) (vaddr & PAGE_MASK));
-}
-#endif	/* __i386__ || !NCR_IOMAPPED */
-
-/*
-**	Insert a delay in micro-seconds and milli-seconds.
-**	-------------------------------------------------
-**	Under Linux, udelay() is restricted to delay < 1 milli-second.
-**	In fact, it generally works for up to 1 second delay.
-**	Since 2.1.105, the mdelay() function is provided for delays 
-**	in milli-seconds.
-**	Under 2.0 kernels, udelay() is an inline function that is very 
-**	inaccurate on Pentium processors.
-*/
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105)
-#define UDELAY udelay
-#define MDELAY mdelay
-#else
-static void UDELAY(long us) { udelay(us); }
-static void MDELAY(long ms) { while (ms--) UDELAY(1000); }
-#endif
-
-/*
-**	Internal data structure allocation.
-**
-**	Linux scsi memory poor pool is adjusted for the need of
-**	middle-level scsi driver.
-**	We allocate our control blocks in the kernel memory pool
-**	to avoid scsi pool shortage.
-**
-**	kmalloc() only ensures 8 bytes boundary alignment.
-**	The NCR need better alignment for cache line bursting.
-**	The global header is moved between the NCB and CCBs and needs 
-**	origin and destination addresses to have same lower four bits.
-**
-**	We use 32 boundary alignment for NCB and CCBs and offset multiple 
-**	of 32 for global header fields. That's too much but at least enough.
-*/
-
-#define ALIGN_SIZE(shift)	(1UL << shift)
-#define ALIGN_MASK(shift)	(~(ALIGN_SIZE(shift)-1))
-
-#define CACHE_LINE_SHIFT	5
-#define CACHE_LINE_SIZE		ALIGN_SIZE(CACHE_LINE_SHIFT)
-#define CACHE_LINE_MASK		ALIGN_MASK(CACHE_LINE_SHIFT)
-
-static void *m_alloc(int size, int a_shift)
-{
-	u_long addr;
-	void *ptr;
-	u_long a_size, a_mask;
-
-	if (a_shift < 3)
-		a_shift = 3;
-
-	a_size	= ALIGN_SIZE(a_shift);
-	a_mask	= ALIGN_MASK(a_shift);
-
-	ptr = (void *) kmalloc(size + a_size, GFP_ATOMIC);
-	if (ptr) {
-		addr	= (((u_long) ptr) + a_size) & a_mask;
-		*((void **) (addr - sizeof(void *))) = ptr;
-		ptr	= (void *) addr;
-	}
-
-	return ptr;
-}
-
-#ifdef MODULE
-static void m_free(void *ptr, int size)
-{
-	u_long addr;
-
-	if (ptr) {
-		addr	= (u_long) ptr;
-		ptr	= *((void **) (addr - sizeof(void *)));
-
-		kfree(ptr);
-	}
-}
-#endif
-
-/*
-**	Transfer direction
-**
-**	Low-level scsi drivers under Linux do not receive the expected 
-**	data transfer direction from upper scsi drivers.
-**	The driver will only check actual data direction for common 
-**	scsi opcodes. Other ones may cause problem, since they may 
-**	depend on device type or be vendor specific.
-**	I would prefer to never trust the device for data direction, 
-**	but that is not possible.
-**
-**	The original driver requires the expected direction to be known.
-**	The Linux version of the driver has been enhanced in order to 
-**	be able to transfer data in the direction choosen by the target. 
-*/
-
-#define XFER_IN		(1)
-#define XFER_OUT	(2)
-
 /*
 **	Head of list of NCR boards
 **
@@ -720,42 +381,8 @@
 static struct Scsi_Host		*first_host	= NULL;
 static Scsi_Host_Template	*the_template	= NULL;	
 
-
-/*
-**	/proc directory entry and proc_info function
-*/
-
-static struct proc_dir_entry proc_scsi_ncr53c8xx = {
-    PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
-};
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-static int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,
-			int length, int hostno, int func);
-#endif
-
-/*
-**	Driver setup.
-**
-**	This structure is initialized from linux config options.
-**	It can be overridden at boot-up by the boot command line.
-*/
-static struct ncr_driver_setup
-	driver_setup			= SCSI_NCR_DRIVER_SETUP;
-
-#ifdef	SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
-static struct ncr_driver_setup
-	driver_safe_setup __initdata	= SCSI_NCR_DRIVER_SAFE_SETUP;
-# ifdef	MODULE
-char *ncr53c8xx = 0;	/* command line passed by insmod */
-#  if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
-MODULE_PARM(ncr53c8xx, "s");
-#  endif
-# endif
-#endif
-
 /*
-**	Other Linux definitions
+**	Other definitions
 */
 
 #define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
@@ -769,358 +396,98 @@
 #define bootverbose (np->verbose)
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
-static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21};
+static u_char Tekram_sync[16] __initdata =
+	{25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10};
 #endif /* SCSI_NCR_NVRAM_SUPPORT */
 
-/*
-**	Structures used by ncr53c8xx_detect/ncr53c8xx_pci_init to 
-**	transmit device configuration to the ncr_attach() function.
-*/
-typedef struct {
-	int	bus;
-	u_char	device_fn;
-	u_long	base;
-	u_long	base_2;
-	u_long	io_port;
-	int	irq;
-/* port and reg fields to use INB, OUTB macros */
-	u_long	port;
-	volatile struct ncr_reg	*reg;
-} ncr_slot;
-
-typedef struct {
-	int type;
-#define	SCSI_NCR_SYMBIOS_NVRAM	(1)
-#define	SCSI_NCR_TEKRAM_NVRAM	(2)
-#ifdef	SCSI_NCR_NVRAM_SUPPORT
-	union {
-		Symbios_nvram Symbios;
-		Tekram_nvram Tekram;
-	} data;
-#endif
-} ncr_nvram;
-
-/*
-**	Structure used by ncr53c8xx_detect/ncr53c8xx_pci_init
-**	to save data on each detected board for ncr_attach().
-*/
-typedef struct {
-	ncr_slot  slot;
-	ncr_chip  chip;
-	ncr_nvram *nvram;
-	u_char	  host_id;
-	int attach_done;
-} ncr_device;
-
 /*==========================================================
 **
-**	Debugging tags
+**	Command control block states.
 **
 **==========================================================
 */
 
-#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_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 HS_IDLE		(0)
+#define HS_BUSY		(1)
+#define HS_NEGOTIATE	(2)	/* sync/wide data transfer*/
+#define HS_DISCONNECT	(3)	/* Disconnected by target */
+
+#define HS_DONEMASK	(0x80)
+#define HS_COMPLETE	(4|HS_DONEMASK)
+#define HS_SEL_TIMEOUT	(5|HS_DONEMASK)	/* Selection timeout      */
+#define HS_RESET	(6|HS_DONEMASK)	/* SCSI reset	          */
+#define HS_ABORTED	(7|HS_DONEMASK)	/* Transfer aborted       */
+#define HS_TIMEOUT	(8|HS_DONEMASK)	/* Software timeout       */
+#define HS_FAIL		(9|HS_DONEMASK)	/* SCSI or PCI bus errors */
+#define HS_UNEXPECTED	(10|HS_DONEMASK)/* Unexpected disconnect  */
 
 /*
-**    Enable/Disable debug messages.
-**    Can be changed at runtime too.
+**	Invalid host status values used by the SCRIPTS processor 
+**	when the nexus is not fully identified.
+**	Shall never appear in a CCB.
 */
 
-#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
-	#define DEBUG_FLAGS ncr_debug
-#else
-	#define DEBUG_FLAGS	SCSI_NCR_DEBUG_FLAGS
-#endif
-
+#define HS_INVALMASK	(0x40)
+#define	HS_SELECTING	(0|HS_INVALMASK)
+#define	HS_IN_RESELECT	(1|HS_INVALMASK)
+#define	HS_STARTING	(2|HS_INVALMASK)
 
+/*
+**	Flags set by the SCRIPT processor for commands 
+**	that have been skipped.
+*/
+#define HS_SKIPMASK	(0x20)
 
 /*==========================================================
 **
-**	assert ()
+**	Software Interrupt Codes
 **
 **==========================================================
+*/
+
+#define	SIR_BAD_STATUS		(1)
+#define	SIR_XXXXXXXXXX		(2)
+#define	SIR_NEGO_SYNC		(3)
+#define	SIR_NEGO_WIDE		(4)
+#define	SIR_NEGO_FAILED		(5)
+#define	SIR_NEGO_PROTO		(6)
+#define	SIR_REJECT_RECEIVED	(7)
+#define	SIR_REJECT_SENT		(8)
+#define	SIR_IGN_RESIDUE		(9)
+#define	SIR_MISSING_SAVE	(10)
+#define	SIR_RESEL_NO_MSG_IN	(11)
+#define	SIR_RESEL_NO_IDENTIFY	(12)
+#define	SIR_RESEL_BAD_LUN	(13)
+#define	SIR_RESEL_BAD_TARGET	(14)
+#define	SIR_RESEL_BAD_I_T_L	(15)
+#define	SIR_RESEL_BAD_I_T_L_Q	(16)
+#define	SIR_DONE_OVERFLOW	(17)
+#define	SIR_MAX			(17)
+
+/*==========================================================
 **
-**	modified copy from 386bsd:/usr/include/sys/assert.h
+**	Extended error codes.
+**	xerr_status field of struct ccb.
 **
-**----------------------------------------------------------
+**==========================================================
 */
 
-#define	assert(expression) { \
-	if (!(expression)) { \
-		(void)printk(KERN_ERR \
-			"assertion \"%s\" failed: file \"%s\", line %d\n", \
-			#expression, \
-			__FILE__, __LINE__); \
-	} \
-}
+#define	XE_OK		(0)
+#define	XE_EXTRA_DATA	(1)	/* unexpected data phase */
+#define	XE_BAD_PHASE	(2)	/* illegal phase (4/5)   */
 
 /*==========================================================
 **
-**	Big/Little endian support.
+**	Negotiation status.
+**	nego_status field	of struct ccb.
 **
 **==========================================================
 */
 
-/*
-**	If the NCR uses big endian addressing mode over the 
-**	PCI, actual io register addresses for byte and word 
-**	accesses must be changed according to lane routing.
-**	Btw, ncr_offb() and ncr_offw() macros only apply to 
-**	constants and so donnot generate bloated code.
-*/
-
-#if	defined(SCSI_NCR_BIG_ENDIAN)
-
-#define ncr_offb(o)	(((o)&~3)+((~((o)&3))&3))
-#define ncr_offw(o)	(((o)&~3)+((~((o)&3))&2))
-
-#else
-
-#define ncr_offb(o)	(o)
-#define ncr_offw(o)	(o)
-
-#endif
-
-/*
-**	If the CPU and the NCR use same endian-ness addressing,
-**	no byte reordering is needed for script patching.
-**	Macro cpu_to_scr() is to be used for script patching.
-**	Macro scr_to_cpu() is to be used for getting a DWORD 
-**	from the script.
-*/
-
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define cpu_to_scr(dw)	cpu_to_le32(dw)
-#define scr_to_cpu(dw)	le32_to_cpu(dw)
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define cpu_to_scr(dw)	cpu_to_be32(dw)
-#define scr_to_cpu(dw)	be32_to_cpu(dw)
-
-#else
-
-#define cpu_to_scr(dw)	(dw)
-#define scr_to_cpu(dw)	(dw)
-
-#endif
-
-/*==========================================================
-**
-**	Access to the controller chip.
-**
-**	If NCR_IOMAPPED is defined, the driver will use 
-**	normal IOs instead of the MEMORY MAPPED IO method  
-**	recommended by PCI specifications.
-**	If all PCI bridges, host brigdes and architectures 
-**	would have been correctly designed for PCI, this 
-**	option would be useless.
-**
-**==========================================================
-*/
-
-/*
-**	If the CPU and the NCR use same endian-ness addressing,
-**	no byte reordering is needed for accessing chip io 
-**	registers. Functions suffixed by '_raw' are assumed 
-**	to access the chip over the PCI without doing byte 
-**	reordering. Functions suffixed by '_l2b' are 
-**	assumed to perform little-endian to big-endian byte 
-**	reordering, those suffixed by '_b2l' blah, blah,
-**	blah, ...
-*/
-
-#if defined(NCR_IOMAPPED)
-
-/*
-**	IO mapped only input / ouput
-*/
-
-#define	INB_OFF(o)		inb (np->port + ncr_offb(o))
-#define	OUTB_OFF(o, val)	outb ((val), np->port + ncr_offb(o))
-
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define	INW_OFF(o)		inw_l2b (np->port + ncr_offw(o))
-#define	INL_OFF(o)		inl_l2b (np->port + (o))
-
-#define	OUTW_OFF(o, val)	outw_b2l ((val), np->port + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_b2l ((val), np->port + (o))
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define	INW_OFF(o)		inw_b2l (np->port + ncr_offw(o))
-#define	INL_OFF(o)		inl_b2l (np->port + (o))
-
-#define	OUTW_OFF(o, val)	outw_l2b ((val), np->port + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_l2b ((val), np->port + (o))
-
-#else
-
-#define	INW_OFF(o)		inw_raw (np->port + ncr_offw(o))
-#define	INL_OFF(o)		inl_raw (np->port + (o))
-
-#define	OUTW_OFF(o, val)	outw_raw ((val), np->port + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_raw ((val), np->port + (o))
-
-#endif	/* ENDIANs */
-
-#else	/* defined NCR_IOMAPPED */
-
-/*
-**	MEMORY mapped IO input / output
-*/
-
-#define INB_OFF(o)		readb((char *)np->reg + ncr_offb(o))
-#define OUTB_OFF(o, val)	writeb((val), (char *)np->reg + ncr_offb(o))
-
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o)		readw_l2b((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_l2b((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val)	writew_b2l((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_b2l((val), (char *)np->reg + (o))
-
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
-
-#define INW_OFF(o)		readw_b2l((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_b2l((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val)	writew_l2b((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_l2b((val), (char *)np->reg + (o))
-
-#else
-
-#define INW_OFF(o)		readw_raw((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_raw((char *)np->reg + (o))
-
-#define OUTW_OFF(o, val)	writew_raw((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_raw((val), (char *)np->reg + (o))
-
-#endif
-
-#endif	/* defined NCR_IOMAPPED */
-
-#define INB(r)		INB_OFF (offsetof(struct ncr_reg,r))
-#define INW(r)		INW_OFF (offsetof(struct ncr_reg,r))
-#define INL(r)		INL_OFF (offsetof(struct ncr_reg,r))
-
-#define OUTB(r, val)	OUTB_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTW(r, val)	OUTW_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTL(r, val)	OUTL_OFF (offsetof(struct ncr_reg,r), (val))
-
-/*
-**	Set bit field ON, OFF 
-*/
-
-#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
-#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
-#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
-#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
-#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
-#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
-
-
-/*==========================================================
-**
-**	Command control block states.
-**
-**==========================================================
-*/
-
-#define HS_IDLE		(0)
-#define HS_BUSY		(1)
-#define HS_NEGOTIATE	(2)	/* sync/wide data transfer*/
-#define HS_DISCONNECT	(3)	/* Disconnected by target */
-
-#define HS_DONEMASK	(0x80)
-#define HS_COMPLETE	(4|HS_DONEMASK)
-#define HS_SEL_TIMEOUT	(5|HS_DONEMASK)	/* Selection timeout      */
-#define HS_RESET	(6|HS_DONEMASK)	/* SCSI reset	          */
-#define HS_ABORTED	(7|HS_DONEMASK)	/* Transfer aborted       */
-#define HS_TIMEOUT	(8|HS_DONEMASK)	/* Software timeout       */
-#define HS_FAIL		(9|HS_DONEMASK)	/* SCSI or PCI bus errors */
-#define HS_UNEXPECTED	(10|HS_DONEMASK)/* Unexpected disconnect  */
-
-/*
-**	Invalid host status values used by the SCRIPTS processor 
-**	when the nexus is not fully identified.
-**	Shall never appear in a CCB.
-*/
-
-#define HS_INVALMASK	(0x40)
-#define	HS_SELECTING	(0|HS_INVALMASK)
-#define	HS_IN_RESELECT	(1|HS_INVALMASK)
-#define	HS_STARTING	(2|HS_INVALMASK)
-
-/*
-**	Flags set by the SCRIPT processor for commands 
-**	that have been skipped.
-*/
-#define HS_SKIPMASK	(0x20)
-
-/*==========================================================
-**
-**	Software Interrupt Codes
-**
-**==========================================================
-*/
-
-#define	SIR_BAD_STATUS		(1)
-#define	SIR_XXXXXXXXXX		(2)
-#define	SIR_NEGO_SYNC		(3)
-#define	SIR_NEGO_WIDE		(4)
-#define	SIR_NEGO_FAILED		(5)
-#define	SIR_NEGO_PROTO		(6)
-#define	SIR_REJECT_RECEIVED	(7)
-#define	SIR_REJECT_SENT		(8)
-#define	SIR_IGN_RESIDUE		(9)
-#define	SIR_MISSING_SAVE	(10)
-#define	SIR_RESEL_NO_MSG_IN	(11)
-#define	SIR_RESEL_NO_IDENTIFY	(12)
-#define	SIR_RESEL_BAD_LUN	(13)
-#define	SIR_RESEL_BAD_TARGET	(14)
-#define	SIR_RESEL_BAD_I_T_L	(15)
-#define	SIR_RESEL_BAD_I_T_L_Q	(16)
-#define	SIR_DONE_OVERFLOW	(17)
-#define	SIR_MAX			(17)
-
-/*==========================================================
-**
-**	Extended error codes.
-**	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)   */
-
-/*==========================================================
-**
-**	Negotiation status.
-**	nego_status field	of struct ccb.
-**
-**==========================================================
-*/
-
-#define NS_SYNC		(1)
-#define NS_WIDE		(2)
+#define NS_NOCHANGE	(0)
+#define NS_SYNC		(1)
+#define NS_WIDE		(2)
+#define NS_PPR		(4)
 
 /*==========================================================
 **
@@ -1192,50 +559,12 @@
 #define UC_SETORDER	13
 #define UC_SETWIDE	14
 #define UC_SETFLAG	15
-#define UC_CLEARPROF	16
 #define UC_SETVERBOSE	17
 
 #define	UF_TRACE	(0x01)
 #define	UF_NODISC	(0x02)
 #define	UF_NOSCAN	(0x04)
 
-/*---------------------------------------
-**
-**	Timestamps for profiling
-**
-**---------------------------------------
-*/
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-
-struct tstamp {
-	u_long start;
-	u_long end;
-	u_long command;
-	u_long status;
-	u_long disconnect;
-	u_long reselect;
-};
-
-/*
-**	profiling data (per device)
-*/
-
-struct profile {
-	u_long	num_trans;
-	u_long	num_kbytes;
-	u_long	rest_bytes;
-	u_long	num_disc;
-	u_long	num_break;
-	u_long	num_int;
-	u_long	num_fly;
-	u_long	ms_setup;
-	u_long	ms_data;
-	u_long	ms_disc;
-	u_long	ms_post;
-};
-#endif
-
 /*========================================================================
 **
 **	Declaration of structs:		target control block
@@ -1313,6 +642,13 @@
 /*2*/	u_char	widedone;
 /*3*/	u_char	wval;
 
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+	u_char 	ic_min_sync;
+	u_char 	ic_max_width;
+	u_char 	ic_maximums_set;
+	u_char 	ic_done;
+#endif
+
 	/*----------------------------------------------------------------
 	**	User settable limits and options.
 	**	These limits are read from the NVRAM if present.
@@ -1384,7 +720,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	*/
@@ -1470,14 +806,6 @@
 	*/
 	ccb_p	cp;
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*----------------------------------------------------------------
-	**	Space for some timestamps to gather profiling data.
-	**----------------------------------------------------------------
-	*/
-	struct tstamp	stamp;
-#endif
-
 	/*----------------------------------------------------------------
 	**	Status fields.
 	**----------------------------------------------------------------
@@ -1630,7 +958,8 @@
 	**----------------------------------------------------------------
 	*/
 	Scsi_Cmnd	*cmd;		/* SCSI command 		*/
-	u_long		tlimit;		/* Deadline for this job	*/
+	u_char		cdb_buf[16];	/* Copy of CDB			*/
+	u_char		sense_buf[64];
 	int		data_len;	/* Total data length		*/
 
 	/*----------------------------------------------------------------
@@ -1761,11 +1090,12 @@
 	**	General controller parameters and configuration.
 	**----------------------------------------------------------------
 	*/
+	pcidev_t	pdev;
 	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_char		bus;		/* PCI BUS number		*/
+	u_char		device_fn;	/* PCI BUS device and function	*/
+	u_long		base_io;	/* IO space base address	*/
 	u_int		irq;		/* IRQ level			*/
 	u_int		features;	/* Chip features map		*/
 	u_char		myaddr;		/* SCSI id of the adapter	*/
@@ -1803,11 +1133,6 @@
 	*/
 	struct ncr_reg	regdump;	/* Register dump		*/
 	u_long		regtime;	/* Time it has been done	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	struct profile	profile;	/* Profiling data		*/
-	u_int		disc_phys;	/* Disconnection counters 	*/
-	u_int		disc_ref;
-#endif
 
 	/*----------------------------------------------------------------
 	**	Miscellaneous buffers accessed by the scripts-processor.
@@ -1829,6 +1154,7 @@
 	u_char		order;		/* Tag order to use		*/
 	u_char		verbose;	/* Verbosity for this controller*/
 	int		ncr_cache;	/* Used for cache test at init.	*/
+	u_long		p_ncb;		/* BUS address of this NCB	*/
 
 	/*----------------------------------------------------------------
 	**	Command completion handling.
@@ -1845,6 +1171,17 @@
 	struct ccb	*ccb;		/* Global CCB			*/
 	struct usrcmd	user;		/* Command from user		*/
 	u_char		release_stage;	/* Synchronisation stage on release  */
+
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+	/*----------------------------------------------------------------
+	**	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 */
+#endif
 };
 
 #define NCB_SCRIPT_PHYS(np,lbl)	 (np->p_script  + offsetof (struct script, lbl))
@@ -1884,19 +1221,11 @@
 	ncrcmd	send_ident	[  9];
 	ncrcmd	prepare		[  6];
 	ncrcmd	prepare2	[  7];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  command		[  9];
-#else
 	ncrcmd  command		[  6];
-#endif
 	ncrcmd  dispatch	[ 32];
 	ncrcmd  clrack		[  4];
 	ncrcmd	no_data		[ 17];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  status		[ 11];
-#else
 	ncrcmd  status		[  8];
-#endif
 	ncrcmd  msg_in		[  2];
 	ncrcmd  msg_in2		[ 16];
 	ncrcmd  msg_bad		[  4];
@@ -1915,22 +1244,14 @@
 #endif
 	ncrcmd  save_dp		[  7];
 	ncrcmd  restore_dp	[  5];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  disconnect	[ 28];
-#else
 	ncrcmd  disconnect	[ 17];
-#endif
 	ncrcmd	msg_out		[  9];
 	ncrcmd	msg_out_done	[  7];
 	ncrcmd  idle		[  2];
 	ncrcmd	reselect	[  8];
 	ncrcmd	reselected	[  8];
 	ncrcmd	resel_dsa	[  6];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd	loadpos1	[  7];
-#else
 	ncrcmd	loadpos1	[  4];
-#endif
 	ncrcmd  resel_lun	[  6];
 	ncrcmd	resel_tag	[  6];
 	ncrcmd	jump_to_nexus	[  4];
@@ -2023,20 +1344,21 @@
 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);
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-static	void	ncb_profile	(ncb_p np, ccb_p cp);
+static	int	ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr);
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+static	int	ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr);
 #endif
 
 static	void	ncr_script_copy_and_bind
 				(ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
 static  void    ncr_script_fill (struct script * scr, struct scripth * scripth);
-static	int	ncr_scatter	(ccb_p cp, Scsi_Cmnd *cmd);
+static	int	ncr_scatter	(ncb_p np, 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_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);
@@ -2061,24 +1383,6 @@
 #define requeue_waiting_list(np) process_waiting_list((np), DID_OK)
 #define reset_waiting_list(np) process_waiting_list((np), DID_RESET)
 
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-static	int	ncr_get_Symbios_nvram	(ncr_slot *np, Symbios_nvram *nvram);
-static	int	ncr_get_Tekram_nvram	(ncr_slot *np, Tekram_nvram *nvram);
-#endif
-
-/*==========================================================
-**
-**
-**      Global static data.
-**
-**
-**==========================================================
-*/
-
-#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
-static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
-#endif
-
 static inline char *ncr_name (ncb_p np)
 {
 	return np->inst_name;
@@ -2107,7 +1411,9 @@
 #define	RELOC_SOFTC	0x40000000
 #define	RELOC_LABEL	0x50000000
 #define	RELOC_REGISTER	0x60000000
+#if 0
 #define	RELOC_KVAR	0x70000000
+#endif
 #define	RELOC_LABELH	0x80000000
 #define	RELOC_MASK	0xf0000000
 
@@ -2116,19 +1422,21 @@
 #define PADDRH(label)   (RELOC_LABELH | offsetof(struct scripth, label))
 #define	RADDR(label)	(RELOC_REGISTER | REG(label))
 #define	FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs)))
+#if 0
 #define	KVAR(which)	(RELOC_KVAR | (which))
+#endif
 
+#if 0
 #define	SCRIPT_KVAR_JIFFIES	(0)
-
 #define	SCRIPT_KVAR_FIRST		SCRIPT_KVAR_JIFFIES
 #define	SCRIPT_KVAR_LAST		SCRIPT_KVAR_JIFFIES
-
 /*
  * Kernel variables referenced in the scripts.
  * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
  */
 static void *script_kvars[] __initdata =
 	{ (void *)&jiffies };
+#endif
 
 static	struct script script0 __initdata = {
 /*--------------------------< START >-----------------------*/ {
@@ -2294,14 +1602,6 @@
 		PADDR (dispatch),
 
 }/*-------------------------< COMMAND >--------------------*/,{
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	... set a timestamp ...
-	*/
-	SCR_COPY (sizeof (u_long)),
-		KVAR(SCRIPT_KVAR_JIFFIES),
-		NADDR (header.stamp.command),
-#endif
 	/*
 	**	... and send the command
 	*/
@@ -2407,14 +1707,6 @@
 		PADDR (no_data),
 
 }/*-------------------------< STATUS >--------------------*/,{
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	set the timestamp.
-	*/
-	SCR_COPY (sizeof (u_long)),
-		KVAR(SCRIPT_KVAR_JIFFIES),
-		NADDR (header.stamp.status),
-#endif
 	/*
 	**	get the status
 	*/
@@ -2641,24 +1933,6 @@
 	*/
 	SCR_WAIT_DISC,
 		0,
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	Profiling:
-	**	Set a time stamp,
-	**	and count the disconnects.
-	*/
-	SCR_COPY (sizeof (u_long)),
-		KVAR(SCRIPT_KVAR_JIFFIES),
-		NADDR (header.stamp.disconnect),
-	SCR_COPY (4),
-		NADDR (disc_phys),
-		RADDR (scratcha),
-	SCR_REG_REG (scratcha, SCR_ADD, 0x01),
-		0,
-	SCR_COPY (4),
-		RADDR (scratcha),
-		NADDR (disc_phys),
-#endif
 	/*
 	**	Status is: DISCONNECTED.
 	*/
@@ -2799,14 +2073,6 @@
 }/*-------------------------< LOADPOS1 >-------------------*/,{
 		0,
 		NADDR (header),
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**      Set a time stamp for this reselection
-	*/
-	SCR_COPY (sizeof (u_long)),
-		KVAR(SCRIPT_KVAR_JIFFIES),
-		NADDR (header.stamp.reselect),
-#endif
 	/*
 	**	The DSA contains the data structure address.
 	*/
@@ -3578,9 +2844,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 +2919,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;
@@ -3700,11 +2963,15 @@
 			*/
 			relocs = 2;
 			tmp1 = src[0];
+#ifdef	RELOC_KVAR
 			if ((tmp1 & RELOC_MASK) == RELOC_KVAR)
 				tmp1 = 0;
+#endif
 			tmp2 = src[1];
+#ifdef	RELOC_KVAR
 			if ((tmp2 & RELOC_MASK) == RELOC_KVAR)
 				tmp2 = 0;
+#endif
 			if ((tmp1 ^ tmp2) & 3) {
 				printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n",
 					ncr_name(np), (int) (src-start-1));
@@ -3757,7 +3024,7 @@
 				switch (old & RELOC_MASK) {
 				case RELOC_REGISTER:
 					new = (old & ~RELOC_MASK)
-						+ bus_dvma_to_mem(np->paddr);
+						+ pcivtobus(np->paddr);
 					break;
 				case RELOC_LABEL:
 					new = (old & ~RELOC_MASK) + np->p_script;
@@ -3766,8 +3033,9 @@
 					new = (old & ~RELOC_MASK) + np->p_scripth;
 					break;
 				case RELOC_SOFTC:
-					new = (old & ~RELOC_MASK) + vtophys(np);
+					new = (old & ~RELOC_MASK) + np->p_ncb;
 					break;
+#ifdef	RELOC_KVAR
 				case RELOC_KVAR:
 					if (((old & ~RELOC_MASK) <
 					     SCRIPT_KVAR_FIRST) ||
@@ -3777,6 +3045,7 @@
 					new = vtophys(script_kvars[old &
 					    ~RELOC_MASK]);
 					break;
+#endif
 				case 0:
 					/* Don't relocate a 0 address. */
 					if (old == 0) {
@@ -3816,17 +3085,6 @@
 
 struct host_data {
      struct ncb *ncb;
-
-     char ncb_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */
-     struct ncb _ncb_data;
-
-     char ccb_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */
-     struct ccb _ccb_data;
-
-     char scr_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */
-     struct script script_data;
-
-     struct scripth scripth_data;
 };
 
 /*
@@ -3913,10 +3171,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 +3180,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 +3192,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];
@@ -3947,7 +3201,7 @@
 
 	if (tn->flags & TEKRAM_SYNC_NEGO) {
 		i = tn->sync_index & 0xf;
-		tp->usrsync = i < 12 ? Tekram_sync[i] : 255;
+		tp->usrsync = Tekram_sync[i];
 	}
 
 	tp->usrwide = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0;
@@ -3965,9 +3219,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 +3389,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:	/* 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;
-		case 2:
-			np->rv_stest2	|= 0x20;
-			break;
-		case 1:
-			np->rv_stest2	|= (np->sv_stest2 & 0x20);
-			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 +3485,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;
 		}
@@ -4248,92 +3523,6 @@
 	return 0;
 }
 
-
-#ifdef SCSI_NCR_DEBUG_NVRAM
-
-__initfunc(
-void ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram)
-)
-{
-	int i;
-
-	/* display Symbios nvram host data */
-	printk(KERN_DEBUG "%s: HOST ID=%d%s%s%s%s%s\n",
-		ncr_name(np), nvram->host_id & 0x0f,
-		(nvram->flags  & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
-		(nvram->flags  & SYMBIOS_PARITY_ENABLE)	? " PARITY"	:"",
-		(nvram->flags  & SYMBIOS_VERBOSE_MSGS)	? " VERBOSE"	:"", 
-		(nvram->flags  & SYMBIOS_CHS_MAPPING)	? " CHS_ALT"	:"", 
-		(nvram->flags1 & SYMBIOS_SCAN_HI_LO)	? " HI_LO"	:"");
-
-	/* display Symbios nvram drive data */
-	for (i = 0 ; i < 15 ; i++) {
-		struct Symbios_target *tn = &nvram->target[i];
-		printk(KERN_DEBUG "%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
-		ncr_name(np), i,
-		(tn->flags & SYMBIOS_DISCONNECT_ENABLE)	? " DISC"	: "",
-		(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)	? " SCAN_BOOT"	: "",
-		(tn->flags & SYMBIOS_SCAN_LUNS)		? " SCAN_LUNS"	: "",
-		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ"	: "",
-		tn->bus_width,
-		tn->sync_period / 4,
-		tn->timeout);
-	}
-}
-
-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)
-)
-{
-	int i, tags, boot_delay;
-	char *rem;
-
-	/* display Tekram nvram host data */
-	tags = 2 << nvram->max_tags_index;
-	boot_delay = 0;
-	if (nvram->boot_delay_index < 6)
-		boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
-	switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
-	default:
-	case 0:	rem = "";			break;
-	case 1: rem = " REMOVABLE=boot device";	break;
-	case 2: rem = " REMOVABLE=all";		break;
-	}
-
-	printk(KERN_DEBUG
-		"%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
-		ncr_name(np), nvram->host_id & 0x0f,
-		(nvram->flags1 & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
-		(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES"	:"",
-		(nvram->flags & TEKRAM_DRIVES_SUP_1GB)	? " >1GB"	:"",
-		(nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET"	:"",
-		(nvram->flags & TEKRAM_ACTIVE_NEGATION)	? " ACT_NEG"	:"",
-		(nvram->flags & TEKRAM_IMMEDIATE_SEEK)	? " IMM_SEEK"	:"",
-		(nvram->flags & TEKRAM_SCAN_LUNS)	? " SCAN_LUNS"	:"",
-		(nvram->flags1 & TEKRAM_F2_F6_ENABLED)	? " F2_F6"	:"",
-		rem, boot_delay, tags);
-
-	/* display Tekram nvram drive data */
-	for (i = 0; i <= 15; i++) {
-		int sync, j;
-		struct Tekram_target *tn = &nvram->target[i];
-		j = tn->sync_index & 0xf;
-		sync = j < 12 ? Tekram_sync[j] : 255;
-		printk(KERN_DEBUG "%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
-		ncr_name(np), i,
-		(tn->flags & TEKRAM_PARITY_CHECK)	? " PARITY"	: "",
-		(tn->flags & TEKRAM_SYNC_NEGO)		? " SYNC"	: "",
-		(tn->flags & TEKRAM_DISCONNECT_ENABLE)	? " DISC"	: "",
-		(tn->flags & TEKRAM_START_CMD)		? " START"	: "",
-		(tn->flags & TEKRAM_TAGGED_COMMANDS)	? " TCQ"	: "",
-		(tn->flags & TEKRAM_WIDE_NEGO)		? " WIDE"	: "",
-		sync);
-	}
-}
-#endif /* SCSI_NCR_DEBUG_NVRAM */
-
 /*
 **	Host attach and initialisations.
 **
@@ -4344,47 +3533,55 @@
 **	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;
+	ncb_p np = 0;
         struct Scsi_Host *instance = 0;
 	u_long flags = 0;
 	ncr_nvram *nvram = device->nvram;
 	int i;
 
+	printk(KERN_INFO "ncr53c%s-%d: rev 0x%x on pci bus %d device %d function %d "
 #ifdef __sparc__
-printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%s\n",
-	device->chip.name, unit, device->chip.revision_id, device->slot.base,
-	device->slot.io_port, __irq_itoa(device->slot.irq));
+		"irq %s\n",
 #else
-printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
-	device->chip.name, unit, device->chip.revision_id, device->slot.base,
-	device->slot.io_port, device->slot.irq);
+		"irq %d\n",
 #endif
- 
+		device->chip.name, unit, device->chip.revision_id,
+		device->slot.bus, (device->slot.device_fn & 0xf8) >> 3,
+		device->slot.device_fn & 7,
+#ifdef __sparc__
+		__irq_itoa(device->slot.irq));
+#else
+		device->slot.irq);
+#endif
+
 	/*
 	**	Allocate host_data structure
 	*/
         if (!(instance = scsi_register(tpnt, sizeof(*host_data))))
 	        goto attach_error;
-
-	/*
-	**	Initialize structure.
-	*/
 	host_data = (struct host_data *) instance->hostdata;
-	bzero (host_data, sizeof(*host_data));
 
 	/*
-	**	Align np and first ccb to 32 boundary for cache line 
-	**	bursting when copying the global header.
+	**	Allocate the host control block.
 	*/
-	np = (ncb_p) (((u_long) &host_data->_ncb_data) & CACHE_LINE_MASK);
+	np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB");
+	if (!np)
+		goto attach_error;
 	NCR_INIT_LOCK_NCB(np);
+	np->pdev  = device->pdev;
+	np->p_ncb = vtobus(np);
 	host_data->ncb = np;
-	np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CACHE_LINE_MASK);
+
+	/*
+	**	Allocate the default CCB.
+	*/
+	np->ccb = (ccb_p) m_calloc_dma(sizeof(struct ccb), "CCB");
+	if (!np->ccb)
+		goto attach_error;
 
 	/*
 	**	Store input informations in the host data structure.
@@ -4395,17 +3592,25 @@
 	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->bus		= device->slot.bus;
+	np->device_fn	= device->slot.device_fn;
 	np->features	= device->chip.features;
 	np->clock_divn	= device->chip.nr_divisor;
 	np->maxoffs	= device->chip.offset_max;
 	np->maxburst	= device->chip.burst_max;
 	np->myaddr	= device->host_id;
 
+	/*
+	**	Allocate SCRIPTS areas.
+	*/
 	np->script0  = (struct script *)
-		(((u_long) &host_data->script_data) & CACHE_LINE_MASK);
-	np->scripth0 = &host_data->scripth_data;
+			m_calloc_dma(sizeof(struct script), "SCRIPT");
+	if (!np->script0)
+		goto attach_error;
+	np->scripth0  = (struct scripth *)
+			m_calloc_dma(sizeof(struct scripth), "SCRIPTH");
+	if (!np->scripth0)
+		goto attach_error;
 
 	/*
 	**    Initialize timer structure
@@ -4423,7 +3628,7 @@
 	np->paddr	= device->slot.base;
 	np->paddr2	= (np->features & FE_RAM)? device->slot.base_2 : 0;
 
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	np->vaddr = remap_pci_mem((u_long) np->paddr, (u_long) 128);
 	if (!np->vaddr) {
 		printk(KERN_ERR
@@ -4443,27 +3648,26 @@
 
 	np->reg = (struct ncr_reg*) np->vaddr;
 
-#endif /* !defined NCR_IOMAPPED */
+#endif /* !defined SCSI_NCR_IOMAPPED */
 
 	/*
 	**	Try to map the controller chip into iospace.
 	*/
 
 	request_region(device->slot.io_port, 128, "ncr53c8xx");
-	np->port = device->slot.io_port;
-	np->myaddr = 255;
+	np->base_io = device->slot.io_port;
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 	if (nvram) {
 		switch(nvram->type) {
 		case SCSI_NCR_SYMBIOS_NVRAM:
 #ifdef SCSI_NCR_DEBUG_NVRAM
-			ncr_display_Symbios_nvram(np, &nvram->data.Symbios);
+			ncr_display_Symbios_nvram(&nvram->data.Symbios);
 #endif
 			break;
 		case SCSI_NCR_TEKRAM_NVRAM:
 #ifdef SCSI_NCR_DEBUG_NVRAM
-			ncr_display_Tekram_nvram(np, &nvram->data.Tekram);
+			ncr_display_Tekram_nvram(&nvram->data.Tekram);
 #endif
 			break;
 		default:
@@ -4493,29 +3697,47 @@
 	instance->this_id       = np->myaddr;
 	instance->max_id	= np->maxwide ? 16 : 8;
 	instance->max_lun	= SCSI_NCR_MAX_LUN;
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,29)
+	instance->base		= (unsigned long) np->reg;
+#else
 	instance->base		= (char *) np->reg;
 #endif
+#endif
 	instance->irq		= device->slot.irq;
 	instance->unique_id	= device->slot.io_port;
 	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;
 
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+	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
+#endif
 	/*
 	**	Patch script to physical addresses
 	*/
 	ncr_script_fill (&script0, &scripth0);
 
 	np->scripth	= np->scripth0;
-	np->p_scripth	= vtophys(np->scripth);
+	np->p_scripth	= vtobus(np->scripth);
 
-	np->p_script	= (np->paddr2) ? bus_dvma_to_mem(np->paddr2) : vtophys(np->script0);
+	np->p_script	= (np->paddr2) ?
+			  pcivtobus(np->paddr2) : vtobus(np->script0);
 
 	ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
 	ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
-	np->ccb->p_ccb		= vtophys (np->ccb);
+	np->ccb->p_ccb		= vtobus (np->ccb);
 
 	/*
 	**    Patch the script for LED support.
@@ -4651,19 +3873,21 @@
 attach_error:
 	if (!instance) return -1;
 	printk(KERN_INFO "%s: detaching...\n", ncr_name(np));
-#ifndef NCR_IOMAPPED
+	if (!np)
+		goto unregister;
+#ifndef SCSI_NCR_IOMAPPED
 	if (np->vaddr) {
 #ifdef DEBUG_NCR53C8XX
 		printk(KERN_DEBUG "%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
 #endif
 		unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
 	}
-#endif /* !NCR_IOMAPPED */
-	if (np->port) {
+#endif /* !SCSI_NCR_IOMAPPED */
+	if (np->base_io) {
 #ifdef DEBUG_NCR53C8XX
-		printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+		printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128);
 #endif
-		release_region(np->port, 128);
+		release_region(np->base_io, 128);
 	}
 	if (np->irq) {
 #ifdef DEBUG_NCR53C8XX
@@ -4676,6 +3900,15 @@
 #endif
 		free_irq(np->irq, np);
 	}
+	if (np->scripth0)
+		m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH");
+	if (np->script0)
+		m_free_dma(np->script0, sizeof(struct script), "SCRIPT");
+	if (np->ccb)
+		m_free_dma(np->ccb, sizeof(struct ccb), "CCB");
+	m_free_dma(np, sizeof(struct ncb), "NCB");
+
+unregister:
 	scsi_unregister(instance);
 
         return -1;
@@ -4703,6 +3936,7 @@
 */
 static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd)
 {
+	unmap_scsi_data(np, cmd);
 	cmd->host_scribble = (char *) np->done_list;
 	np->done_list = cmd;
 }
@@ -4718,6 +3952,270 @@
 	}
 }
 
+/*==========================================================
+**
+**
+**	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.
+**
+**
+**==========================================================
+*/
+
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+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;
+}
+#endif /* SCSI_NCR_INTEGRITY_CHECKING */
+
+/*==========================================================
+**
+**
+**	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;
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+				if (tp->ic_done)
+		       			 tp->usrwide &= tp->ic_max_width;
+#endif
+			} else
+				tp->widedone=1;
+
+		};
+
+		/*
+		**	negotiate synchronous transfers?
+		*/
+
+		if (!nego && !tp->period) {
+			if (tp->inq_byte7 & INQ7_SYNC) {
+				nego = NS_SYNC;
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+				if ((tp->ic_done) &&
+				 	      (tp->minsync < tp->ic_min_sync))
+		       			 tp->minsync = tp->ic_min_sync;
+#endif
+			} 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 +4234,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 +4280,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))) {
@@ -4806,63 +4305,6 @@
 	}
 #endif
 
-	/*---------------------------------------------------
-	**
-	**	timestamp
-	**
-	**----------------------------------------------------
-	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	bzero (&cp->phys.header.stamp, sizeof (struct tstamp));
-	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 +4329,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 +4337,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 +4364,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
@@ -4957,78 +4371,128 @@
 	**----------------------------------------------------
 	*/
 
-	segments = ncr_scatter (cp, cp->cmd);
-
-	if (segments < 0) {
-		ncr_free_ccb(np, cp);
-		return(DID_ERROR);
+	direction = scsi_data_direction(cmd);
+	if (direction != SCSI_DATA_NONE) {
+		segments = ncr_scatter (np, cp, cp->cmd);
+		if (segments < 0) {
+			ncr_free_ccb(np, cp);
+			return(DID_ERROR);
+		}
 	}
-
-	/*----------------------------------------------------
-	**
-	**	Guess xfer direction.
-	**	Spare some CPU by testing here frequently opcode.
-	**
-	**----------------------------------------------------
-	*/
-	if (!cp->data_len)
-		direction = 0;
 	else {
-		switch((int) cmd->cmnd[0]) {
-		case 0x08:  /*	READ(6)				08 */
-		case 0x28:  /*	READ(10)			28 */
-		case 0xA8:  /*	READ(12)			A8 */
-			direction = XFER_IN;
-			break;
-		case 0x0A:  /*	WRITE(6)			0A */
-		case 0x2A:  /*	WRITE(10)			2A */
-		case 0xAA:  /*	WRITE(12)			AA */
-			direction = XFER_OUT;
-			break;
-		default:
-			direction = (XFER_IN|XFER_OUT);
-			break;
-		}
+		cp->data_len = 0;
+		segments = 0;
 	}
 
-	/*----------------------------------------------------
+	/*---------------------------------------------------
+	**
+	**	negotiation required?
 	**
-	**	Set the SAVED_POINTER.
+	**	(nego_status is filled by ncr_prepare_nego())
 	**
-	**----------------------------------------------------
+	**---------------------------------------------------
 	*/
 
-	/*
-	**	Default to no data transfer.
-	*/
-	lastp = goalp = NCB_SCRIPT_PHYS (np, no_data);
+	cp->nego_status = 0;
 
-	/*
-	**	Compute data out pointers, if needed.
-	*/
-	if (direction & XFER_OUT) {
-		goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
-		if (segments <= MAX_SCATTERL)
-			lastp = goalp - 8 - (segments * 16);
-		else {
-			lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
-			lastp -= (segments - MAX_SCATTERL) * 16;
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+	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;
 		}
 		/*
-		**	If actual data direction is unknown, save pointers 
-		**	in header. The SCRIPTS will swap them to current 
-		**	if target decision will be data out.
-		*/
-		if (direction & XFER_IN) {
-			cp->phys.header.wgoalp	= cpu_to_scr(goalp);
-			cp->phys.header.wlastp	= cpu_to_scr(lastp);
+		 * 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);
+        }
+#else
+	if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) {
+		msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
 	}
+#endif /* SCSI_NCR_INTEGRITY_CHECKING */
+
+	/*----------------------------------------------------
+	**
+	**	Determine xfer direction.
+	**
+	**----------------------------------------------------
+	*/
+	if (!cp->data_len)
+		direction = SCSI_DATA_NONE;
 
 	/*
-	**	Compute data in pointers, if needed.
+	**	If data direction is UNKNOWN, speculate DATA_READ 
+	**	but prepare alternate pointers for WRITE in case 
+	**	of our speculation will be just wrong.
+	**	SCRIPTS will swap values if needed.
 	*/
-	if (direction & XFER_IN) {
+	switch(direction) {
+	case SCSI_DATA_UNKNOWN:
+	case SCSI_DATA_WRITE:
+		goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
+		if (segments <= MAX_SCATTERL)
+			lastp = goalp - 8 - (segments * 16);
+		else {
+			lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
+			lastp -= (segments - MAX_SCATTERL) * 16;
+		}
+		if (direction != SCSI_DATA_UNKNOWN)
+			break;
+		cp->phys.header.wgoalp	= cpu_to_scr(goalp);
+		cp->phys.header.wlastp	= cpu_to_scr(lastp);
+		/* fall through */
+	case SCSI_DATA_READ:
 		goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
 		if (segments <= MAX_SCATTERL)
 			lastp = goalp - 8 - (segments * 16);
@@ -5036,6 +4500,11 @@
 			lastp = NCB_SCRIPTH_PHYS (np, hdata_in2);
 			lastp -= (segments - MAX_SCATTERL) * 16;
 		}
+		break;
+	default:
+	case SCSI_DATA_NONE:
+		lastp = goalp = NCB_SCRIPT_PHYS (np, no_data);
+		break;
 	}
 
 	/*
@@ -5045,7 +4514,7 @@
 	cp->phys.header.lastp = cpu_to_scr(lastp);
 	cp->phys.header.goalp = cpu_to_scr(goalp);
 
-	if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT))
+	if (direction == SCSI_DATA_UNKNOWN)
 		cp->phys.header.savep = 
 			cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io));
 	else
@@ -5088,19 +4557,19 @@
 	/*
 	**	command
 	*/
-	cp->phys.cmd.addr		= cpu_to_scr(vtophys (&cmd->cmnd[0]));
+	memcpy(cp->cdb_buf, cmd->cmnd, MIN(cmd->cmd_len, sizeof(cp->cdb_buf)));
+	cp->phys.cmd.addr		= cpu_to_scr(CCB_PHYS (cp, cdb_buf[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->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 +4585,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 +4691,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, "
@@ -5258,11 +4721,13 @@
 	**	We are expecting RESET to be TRUE and other signals to be 
 	**	FALSE.
 	*/
-	term =	INB(nc_sstat0);				/* rst, sdp0 */
-	term =	((term & 2) << 7) + ((term & 1) << 16);
-	term |= ((INB(nc_sstat2) & 0x01) << 25) |	/* sdp1 */
-		(INW(nc_sbdl) << 9) |			/* d15-0 */
-		INB(nc_sbcl);	/* req, ack, bsy, sel, atn, msg, cd, io */
+
+	term =	INB(nc_sstat0);
+	term =	((term & 2) << 7) + ((term & 1) << 17);	/* rst sdp0 */
+	term |= ((INB(nc_sstat2) & 0x01) << 26) |	/* sdp1     */
+		((INW(nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */
+		((INW(nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
+		INB(nc_sbcl);	/* req ack bsy sel atn msg cd io    */
 
 	if (!(np->features & FE_WIDE))
 		term &= 0x3ffff;
@@ -5403,7 +4868,6 @@
 	**	script to abort the command.
 	*/
 
-	cp->tlimit = 0;
 	switch(cp->host_status) {
 	case HS_BUSY:
 	case HS_NEGOTIATE:
@@ -5516,17 +4980,17 @@
 	**	Release Memory mapped IO region and IO mapped region
 	*/
 
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 #ifdef DEBUG_NCR53C8XX
 	printk("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
 #endif
 	unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
-#endif /* !NCR_IOMAPPED */
+#endif /* !SCSI_NCR_IOMAPPED */
 
 #ifdef DEBUG_NCR53C8XX
-	printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+	printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->base_io, 128);
 #endif
-	release_region(np->port, 128);
+	release_region(np->base_io, 128);
 
 	/*
 	**	Free allocated ccb(s)
@@ -5541,7 +5005,7 @@
 #ifdef DEBUG_NCR53C8XX
 	printk("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
 #endif
-		m_free(cp, sizeof(*cp));
+		m_free_dma(cp, sizeof(*cp), "CCB");
 	}
 
 	/*
@@ -5557,12 +5021,20 @@
 	printk("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
 #endif
 				if (lp->jump_ccb != &lp->jump_ccb_0)
-					m_free(lp->jump_ccb, 256);
-				m_free(lp, sizeof(*lp));
+					m_free_dma(lp->jump_ccb,256,"JUMP_CCB");
+				m_free_dma(lp, sizeof(*lp), "LCB");
 			}
 		}
 	}
 
+	if (np->scripth0)
+		m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH");
+	if (np->script0)
+		m_free_dma(np->script0, sizeof(struct script), "SCRIPT");
+	if (np->ccb)
+		m_free_dma(np->ccb, sizeof(struct ccb), "CCB");
+	m_free_dma(np, sizeof(struct ncb), "NCB");
+
 	printk("%s: host resources successfully released\n", ncr_name(np));
 
 	return 1;
@@ -5593,15 +5065,11 @@
 		return;
 
 	/*
-	**	timestamp
-	**	Optional, spare some CPU time
+	**	Print minimal debug information.
 	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncb_profile (np, cp);
-#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);
 
 	/*
@@ -5716,6 +5184,7 @@
 		*/
 		if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
 		    cmd->cmnd[4] >= 7 && !cmd->use_sg) {
+			sync_scsi_data(np, cmd);	/* SYNC the data */
 			ncr_setup_lcb (np, cmd->target, cmd->lun,
 				       (char *) cmd->request_buffer);
 		}
@@ -5742,6 +5211,12 @@
 		*/
 		cmd->result = ScsiResult(DID_OK, S_CHECK_COND);
 
+		/*
+		**	Copy back sense data to caller's buffer.
+		*/
+		memcpy(cmd->sense_buffer, cp->sense_buf,
+		       MIN(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf)));
+
 		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
 			u_char * p = (u_char*) & cmd->sense_buffer;
 			int i;
@@ -5750,7 +5225,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)) {
@@ -6073,13 +5554,11 @@
 	/*
 	**	DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2.
 	**	Disable overlapped arbitration.
-	**	The 896 Rev 1 is also affected by this errata.
+	**	All 896 chips are also affected by this errata.
 	*/
-	if (np->device_id == PCI_DEVICE_ID_NCR_53C875 &&
-	    np->revision_id >= 0x10 && np->revision_id <= 0x15)
+	if (np->device_id == PCI_DEVICE_ID_NCR_53C875)
 		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)
 		OUTB (nc_ccntl0, DPR);
 
 	/*
@@ -6114,16 +5593,15 @@
 	/*
 	**    Start script processor.
 	*/
-	MEMORY_BARRIER();
 	if (np->paddr2) {
 		if (bootverbose)
 			printk ("%s: Downloading SCSI SCRIPTS.\n",
 				ncr_name(np));
-		OUTL (nc_scratcha, vtophys(np->script0));
-		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, start_ram));
+		OUTL (nc_scratcha, vtobus(np->script0));
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, start_ram));
 	}
 	else
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, start));
 }
 
 /*==========================================================
@@ -6593,12 +6071,6 @@
 			tp->usrflag = np->user.data;
 		};
 		break;
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	case UC_CLEARPROF:
-		bzero(&np->profile, sizeof(np->profile));
-		break;
-#endif
 	}
 	np->user.cmd=0;
 }
@@ -6620,7 +6092,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 +6105,7 @@
 		return;
 	}
 
-	np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
+	np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
 	add_timer(&np->timer);
 
 	/*
@@ -6661,15 +6133,6 @@
 		**	block ncr interrupts
 		*/
 		np->lasttime = thistime;
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-		/*
-		**	Reset profile data to avoid ugly overflow
-		**	(Limited to 1024 GB for 32 bit architecture)
-		*/
-		if (np->profile.num_kbytes > (~0UL >> 2))
-			bzero(&np->profile, sizeof(np->profile));
-#endif
 	}
 
 #ifdef SCSI_NCR_BROKEN_INTR
@@ -6813,19 +6276,12 @@
 		OUTB (nc_istat, (istat & SIGP) | INTF);
 		istat = INB (nc_istat);
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-		np->profile.num_fly++;
-#endif
 		ncr_wakeup_done (np);
 	};
 
 	if (!(istat & (SIP|DIP)))
 		return;
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	np->profile.num_int++;
-#endif
-
 	if (istat & CABRT)
 		OUTB (nc_istat, CABRT);
 
@@ -6880,7 +6336,7 @@
 				ncr_name(np), istat, dstat, sist);
 			return;
 		}
-		OUTONB (nc_dcntl, (STD|NOCOM));
+		OUTONB_STD ();
 		return;
 	};
 
@@ -6927,8 +6383,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;
@@ -6956,7 +6413,7 @@
 	if (sist & UDC) {
 		printk ("%s: unexpected disconnect\n", ncr_name(np));
 		OUTB (HS_PRT, HS_UNEXPECTED);
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, cleanup));
 		return;
 	};
 
@@ -7008,7 +6465,7 @@
 	**	repair start queue and jump to start point.
 	*/
 
-	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sto_restart));
+	OUTL_DSP (NCB_SCRIPTH_PHYS (np, sto_restart));
 	return;
 }
 
@@ -7044,7 +6501,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;
 	}
@@ -7103,6 +6560,14 @@
 	else
 		msg = M_ID_ERROR;
 
+#ifdef SCSI_NCR_INTEGRITY_CHECKING
+	/*
+	**      Save error message. For integrity check use only.
+	*/
+	if (np->check_integrity)
+		np->check_integ_par = msg;
+#endif
+
 	/*
 	 *	If the NCR stopped on a MOVE ^ DATA_IN, we jump to a 
 	 *	script that will ignore all data in bytes until phase 
@@ -7118,7 +6583,7 @@
 	OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
 
 	np->msgout[0] = msg;
-	OUTL (nc_dsp, jmp);
+	OUTL_DSP (jmp);
 	return 1;
 
 reset_all:
@@ -7147,6 +6612,7 @@
 	u_int32	dsp;
 	u_int32	dsa;
 	u_int32	nxtdsp;
+	u_int32	newtmp;
 	u_int32	*vdsp;
 	u_int32	oadr, olen;
 	u_int32	*tblp;
@@ -7241,11 +6707,11 @@
 		nxtdsp = dsp;
 	}
 	else if (cp) {
-		if	(dsp == vtophys (&cp->patch[2])) {
+		if	(dsp == CCB_PHYS (cp, patch[2])) {
 			vdsp = &cp->patch[0];
 			nxtdsp = scr_to_cpu(vdsp[3]);
 		}
-		else if (dsp == vtophys (&cp->patch[6])) {
+		else if (dsp == CCB_PHYS (cp, patch[6])) {
 			vdsp = &cp->patch[4];
 			nxtdsp = scr_to_cpu(vdsp[3]);
 		}
@@ -7340,7 +6806,11 @@
 	*/
 
 	newcmd = cp->patch;
-	if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4;
+	newtmp = CCB_PHYS (cp, patch);
+	if (newtmp == scr_to_cpu(cp->phys.header.savep)) {
+		newcmd = &cp->patch[4];
+		newtmp = CCB_PHYS (cp, patch[4]);
+	}
 
 	/*
 	**	fillin the commands
@@ -7364,11 +6834,8 @@
 	**	fake the return address (to the patch).
 	**	and restart script processor at dispatcher.
 	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	np->profile.num_break++;
-#endif
-	OUTL (nc_temp, vtophys (newcmd));
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+	OUTL (nc_temp, newtmp);
+	OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch));
 	return;
 
 	/*
@@ -7430,7 +6897,7 @@
 	}
 
 	if (nxtdsp) {
-		OUTL (nc_dsp, nxtdsp);
+		OUTL_DSP (nxtdsp);
 		return;
 	}
 
@@ -7504,7 +6971,7 @@
 		ncr_put_start_queue(np, cp);
 		if (disc_cnt)
 			INB (nc_ctest2);		/* Clear SIGP */
-		OUTL (nc_dsp,	NCB_SCRIPT_PHYS (np, reselect));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, reselect));
 		return;
 	case S_TERMINATED:
 	case S_CHECK_COND:
@@ -7536,15 +7003,14 @@
 		*/
 		cp->sensecmd[0]		= 0x03;
 		cp->sensecmd[1]		= cmd->lun << 5;
-		cp->sensecmd[4]		= sizeof(cmd->sense_buffer);
+		cp->sensecmd[4]		= sizeof(cp->sense_buf);
 
 		/*
 		**	sense data
 		*/
-		cp->phys.sense.addr	=
-				cpu_to_scr(vtophys (&cmd->sense_buffer[0]));
-		cp->phys.sense.size	=
-				cpu_to_scr(sizeof(cmd->sense_buffer));
+		bzero(cp->sense_buf, sizeof(cp->sense_buf));
+		cp->phys.sense.addr	= cpu_to_scr(CCB_PHYS(cp,sense_buf[0]));
+		cp->phys.sense.size	= cpu_to_scr(sizeof(cp->sense_buf));
 
 		/*
 		**	requeue the command.
@@ -7573,12 +7039,12 @@
 
 		ncr_put_start_queue(np, cp);
 
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, start));
 		return;
 	}
 
 out:
-	OUTONB (nc_dcntl, (STD|NOCOM));
+	OUTONB_STD ();
 	return;
 }
 
@@ -7609,6 +7075,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)
 {
@@ -7631,7 +7107,7 @@
 		**	We just assume lun=0, 1 CCB, no tag.
 		*/
 		if (tp->lp[0]) { 
-			OUTL (nc_dsp, scr_to_cpu(tp->lp[0]->jump_ccb[0]));
+			OUTL_DSP (scr_to_cpu(tp->lp[0]->jump_ccb[0]));
 			return;
 		}
 	case SIR_RESEL_BAD_TARGET:	/* Will send a TARGET RESET message */
@@ -7853,13 +7329,13 @@
 					**	Answer wasn't acceptable.
 					*/
 					ncr_setsync (np, cp, 0, 0xe0);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+					OUTL_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));
+					OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 				};
 				return;
 
@@ -7892,7 +7368,7 @@
 		}
 
 		if (!ofs) {
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+			OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
 			return;
 		}
 		np->msgin [0] = M_NOOP;
@@ -7950,13 +7426,13 @@
 					**	Answer wasn't acceptable.
 					*/
 					ncr_setwide (np, cp, 0, 1);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+					OUTL_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));
+					OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 				};
 				return;
 
@@ -8064,7 +7540,7 @@
 	};
 
 out:
-	OUTONB (nc_dcntl, (STD|NOCOM));
+	OUTONB_STD ();
 }
 
 /*==========================================================
@@ -8164,7 +7640,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 +7688,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;
@@ -8253,7 +7729,7 @@
 
 
 #define ncr_reg_bus_addr(r) \
-	(bus_dvma_to_mem(np->paddr) + offsetof (struct ncr_reg, r))
+	(pcivtobus(np->paddr) + offsetof (struct ncr_reg, r))
 
 /*------------------------------------------------------------------------
 **	Initialize the fixed part of a CCB structure.
@@ -8267,7 +7743,7 @@
 	/*
 	**	Remember virtual and bus address of this ccb.
 	*/
-	cp->p_ccb 	   = vtophys(cp);
+	cp->p_ccb 	   = vtobus(cp);
 	cp->phys.header.cp = cp;
 
 	/*
@@ -8282,10 +7758,10 @@
 	**	JUMP @(sched_point)
 	*/
 	cp->start.setup_dsa[0]	 = cpu_to_scr(copy_4);
-	cp->start.setup_dsa[1]	 = cpu_to_scr(vtophys(&cp->start.p_phys));
+	cp->start.setup_dsa[1]	 = cpu_to_scr(CCB_PHYS(cp, start.p_phys));
 	cp->start.setup_dsa[2]	 = cpu_to_scr(ncr_reg_bus_addr(nc_dsa));
 	cp->start.schedule.l_cmd = cpu_to_scr(SCR_JUMP);
-	cp->start.p_phys	 = cpu_to_scr(vtophys(&cp->phys));
+	cp->start.p_phys	 = cpu_to_scr(CCB_PHYS(cp, phys));
 
 	bcopy(&cp->start, &cp->restart, sizeof(cp->restart));
 
@@ -8308,15 +7784,10 @@
 	/*
 	**	Allocate memory for this CCB.
 	*/
-	cp = m_alloc(sizeof(struct ccb), 5);
+	cp = m_calloc_dma(sizeof(struct ccb), "CCB");
 	if (!cp)
 		return;
 
-	if (DEBUG_FLAGS & DEBUG_ALLOC) {
-		PRINT_LUN(np, tn, ln);
-		printk ("new ccb @%p.\n", cp);
-	}
-
 	/*
 	**	Count it and initialyze it.
 	*/
@@ -8374,7 +7845,7 @@
 	**	COPY @(tp->sval), @(sxfer)
 	*/
 	tp->getscr[0] =	cpu_to_scr(copy_1);
-	tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval));
+	tp->getscr[1] = cpu_to_scr(vtobus (&tp->sval));
 	tp->getscr[2] = cpu_to_scr(ncr_reg_bus_addr(nc_sxfer));
   
 	/*
@@ -8382,7 +7853,7 @@
 	**	COPY @(tp->wval), @(scntl3)
 	*/
 	tp->getscr[3] =	cpu_to_scr(copy_1);
-	tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval));
+	tp->getscr[4] = cpu_to_scr(vtobus (&tp->wval));
 	tp->getscr[5] = cpu_to_scr(ncr_reg_bus_addr(nc_scntl3));
 
 	/*
@@ -8407,7 +7878,7 @@
 	/*
 	**	Link this target control block to the JUMP chain.
 	*/
-	np->jump_tcb[th].l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb));
+	np->jump_tcb[th].l_paddr = cpu_to_scr(vtobus (&tp->jump_tcb));
 
 	/*
 	**	These assert's should be moved at driver initialisations.
@@ -8442,17 +7913,12 @@
 	/*
 	**	Allocate the lcb.
 	*/
-	lp = m_alloc(sizeof(struct lcb), 3);
+	lp = m_calloc_dma(sizeof(struct lcb), "LCB");
 	if (!lp)
 		goto fail;
 	bzero(lp, sizeof(*lp));
 	tp->lp[ln] = lp;
 
-	if (DEBUG_FLAGS & DEBUG_ALLOC) {
-		PRINT_LUN(np, tn, ln);
-		printk ("new lcb @%p.\n", lp);
-	}
-
 	/*
 	**	Initialize the target control block if not yet.
 	*/
@@ -8473,7 +7939,7 @@
 	*/
 	lp->maxnxs	= 1;
 	lp->jump_ccb	= &lp->jump_ccb_0;
-	lp->p_jump_ccb	= cpu_to_scr(vtophys(lp->jump_ccb));
+	lp->p_jump_ccb	= cpu_to_scr(vtobus(lp->jump_ccb));
 
 	/*
 	**	Initilialyze the reselect script:
@@ -8491,7 +7957,7 @@
 	lp->jump_lcb.l_paddr = tp->jump_lcb[lh].l_paddr;
 
 	lp->load_jump_ccb[0] = cpu_to_scr(copy_4);
-	lp->load_jump_ccb[1] = cpu_to_scr(vtophys (&lp->p_jump_ccb));
+	lp->load_jump_ccb[1] = cpu_to_scr(vtobus (&lp->p_jump_ccb));
 	lp->load_jump_ccb[2] = cpu_to_scr(ncr_reg_bus_addr(nc_temp));
 
 	lp->jump_tag.l_cmd   = cpu_to_scr(SCR_JUMP);
@@ -8500,7 +7966,7 @@
 	/*
 	**	Link this lun control block to the JUMP chain.
 	*/
-	tp->jump_lcb[lh].l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb));
+	tp->jump_lcb[lh].l_paddr = cpu_to_scr(vtobus (&lp->jump_lcb));
 
 	/*
 	**	Initialize command queuing control.
@@ -8584,19 +8050,19 @@
 	*/
 	if ((inq_byte7 & INQ7_QUEUE) && lp->jump_ccb == &lp->jump_ccb_0) {
 		int i;
-		lp->jump_ccb = m_alloc(256, 8);
+		lp->jump_ccb = m_calloc_dma(256, "JUMP_CCB");
 		if (!lp->jump_ccb) {
 			lp->jump_ccb = &lp->jump_ccb_0;
 			goto fail;
 		}
-		lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb));
+		lp->p_jump_ccb = cpu_to_scr(vtobus(lp->jump_ccb));
 		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);
 	}
 
 	/*
@@ -8641,7 +8107,7 @@
 **	sizes to the data segment array.
 */
 
-static	int	ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
+static	int	ncr_scatter(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd)
 {
 	struct scr_tblmove *data;
 	int segment	= 0;
@@ -8652,8 +8118,10 @@
 
 	if (!use_sg) {
 		if (cmd->request_bufflen) {
+			u_long baddr = map_scsi_single_data(np, cmd);
+
 			data = &data[MAX_SCATTER - 1];
-			data[0].addr = cpu_to_scr(vtophys(cmd->request_buffer));
+			data[0].addr = cpu_to_scr(baddr);
 			data[0].size = cpu_to_scr(cmd->request_bufflen);
 			cp->data_len = cmd->request_bufflen;
 			segment = 1;
@@ -8662,13 +8130,16 @@
 	else if (use_sg <= MAX_SCATTER) {
 		struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
 
+		use_sg = map_scsi_sg_data(np, cmd);
 		data = &data[MAX_SCATTER - use_sg];
+
 		while (segment < use_sg) {
-			data[segment].addr =
-				cpu_to_scr(vtophys(scatter[segment].address));
-			data[segment].size =
-				cpu_to_scr(scatter[segment].length);
-			cp->data_len	   += scatter[segment].length;
+			u_long baddr = scsi_sg_dma_address(&scatter[segment]);
+			unsigned int len = scsi_sg_dma_len(&scatter[segment]);
+
+			data[segment].addr = cpu_to_scr(baddr);
+			data[segment].size = cpu_to_scr(len);
+			cp->data_len	  += len;
 			++segment;
 		}
 	}
@@ -8690,10 +8161,8 @@
 **==========================================================
 */
 
-#ifndef NCR_IOMAPPED
-__initfunc(
-static int ncr_regtest (struct ncb* np)
-)
+#ifndef SCSI_NCR_IOMAPPED
+static int __init ncr_regtest (struct ncb* np)
 {
 	register volatile u_int32 data;
 	/*
@@ -8717,13 +8186,11 @@
 }
 #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;
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	if (np->reg) {
             err |= ncr_regtest (np);
             if (err) return (err);
@@ -8743,7 +8210,7 @@
 	/*
 	**	Start script (exchange values)
 	*/
-	OUTL (nc_dsp, pc);
+	OUTL_DSP (pc);
 	/*
 	**	Wait 'til done (with timeout)
 	*/
@@ -8807,73 +8274,6 @@
 /*==========================================================
 **
 **
-**	Profiling the drivers and targets performance.
-**
-**
-**==========================================================
-*/
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-
-/*
-**	Compute the difference in jiffies ticks.
-*/
-
-#define ncr_delta(from, to) \
-	( ((to) && (from))? (to) - (from) : -1 )
-
-#define PROFILE  cp->phys.header.stamp
-static	void ncb_profile (ncb_p np, ccb_p cp)
-{
-	long co, st, en, di, re, post, work, disc;
-	u_int diff;
-
-	PROFILE.end = jiffies;
-
-	st = ncr_delta (PROFILE.start,PROFILE.status);
-	if (st<0) return;	/* status  not reached  */
-
-	co = ncr_delta (PROFILE.start,PROFILE.command);
-	if (co<0) return;	/* command not executed */
-
-	en = ncr_delta (PROFILE.start,PROFILE.end),
-	di = ncr_delta (PROFILE.start,PROFILE.disconnect),
-	re = ncr_delta (PROFILE.start,PROFILE.reselect);
-	post = en - st;
-
-	/*
-	**	@PROFILE@  Disconnect time invalid if multiple disconnects
-	*/
-
-	if (di>=0) disc = re - di; else  disc = 0;
-
-	work = (st - co) - disc;
-
-	diff = (scr_to_cpu(np->disc_phys) - np->disc_ref) & 0xff;
-	np->disc_ref += diff;
-
-	np->profile.num_trans	+= 1;
-	if (cp->cmd) {
-		np->profile.num_kbytes	+= (cp->cmd->request_bufflen >> 10);
-		np->profile.rest_bytes	+= (cp->cmd->request_bufflen & (0x400-1));
-		if (np->profile.rest_bytes >= 0x400) {
-			++np->profile.num_kbytes;
-			np->profile.rest_bytes	-= 0x400;
-		}
-	}
-	np->profile.num_disc	+= diff;
-	np->profile.ms_setup	+= co;
-	np->profile.ms_data	+= work;
-	np->profile.ms_disc	+= disc;
-	np->profile.ms_post	+= post;
-}
-#undef PROFILE
-
-#endif /* SCSI_NCR_PROFILE_SUPPORT */
-
-/*==========================================================
-**
-**
 **	Device lookup.
 **
 **	@GENSCSI@ should be integrated to scsiconf.c
@@ -8982,11 +8382,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 +8410,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 +8433,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);
@@ -9071,970 +8470,36 @@
 
 		if (f1 > f2) f1 = f2;		/* trust lower result	*/
 
-		if	(f1 <	45000)		f1 =  40000;
-		else if (f1 <	55000)		f1 =  50000;
-		else				f1 =  80000;
-
-		if (f1 < 80000 && mult > 1) {
-			if (bootverbose >= 2)
-				printk ("%s: clock multiplier assumed\n", ncr_name(np));
-			np->multiplier	= mult;
-		}
-	} else {
-		if	((scntl3 & 7) == 3)	f1 =  40000;
-		else if	((scntl3 & 7) == 5)	f1 =  80000;
-		else 				f1 = 160000;
-
-		f1 /= np->multiplier;
-	}
-
-	/*
-	**	Compute controller synchronous parameters.
-	*/
-	f1		*= np->multiplier;
-	np->clock_khz	= f1;
-}
-
-/*===================== LINUX ENTRY POINTS SECTION ==========================*/
-
-#ifndef uchar
-#define uchar unsigned char
-#endif
-
-#ifndef ushort
-#define ushort unsigned short
-#endif
-
-#ifndef ulong
-#define ulong unsigned long
-#endif
-
-/* ---------------------------------------------------------------------
-**
-**	Driver setup from the boot command line
-**
-** ---------------------------------------------------------------------
-*/
-
-#ifdef MODULE
-#define	ARG_SEP	' '
-#else
-#define	ARG_SEP	','
-#endif
-
-__initfunc(
-void ncr53c8xx_setup(char *str, int *ints)
-)
-{
-#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
-	char *cur = str;
-	char *pc, *pv;
-	int val;
-	int base;
-	int c;
-	int xi = 0;
-
-	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
-		char *pe;
-
-		val = 0;
-		pv = pc;
-		c = *++pv;
-
-		if	(c == 'n')
-			val = 0;
-		else if	(c == 'y')
-			val = 1;
-		else {
-			base = 0;
-			val = (int) simple_strtoul(pv, &pe, base);
-		}
-		if	(!strncmp(cur, "tags:", 5)) {
-			int i;
-			driver_setup.default_tags = val;
-			if (pe && *pe == '/') {
-				i = 0;
-				while (*pe && *pe != ARG_SEP && 
-					i < sizeof(driver_setup.tag_ctrl)-1) {
-					driver_setup.tag_ctrl[i++] = *pe++;
-				}
-				driver_setup.tag_ctrl[i] = '\0';
-			}
-		}
-		else if	(!strncmp(cur, "mpar:", 5))
-			driver_setup.master_parity	= val;
-		else if	(!strncmp(cur, "spar:", 5))
-			driver_setup.scsi_parity	= val;
-		else if	(!strncmp(cur, "disc:", 5))
-			driver_setup.disconnection	= val;
-		else if	(!strncmp(cur, "specf:", 6))
-			driver_setup.special_features = val;
-		else if	(!strncmp(cur, "ultra:", 6))
-			driver_setup.ultra_scsi	= val;
-		else if	(!strncmp(cur, "fsn:", 4))
-			driver_setup.force_sync_nego	= val;
-		else if	(!strncmp(cur, "revprob:", 8))
-			driver_setup.reverse_probe	= val;
-		else if	(!strncmp(cur, "sync:", 5))
-			driver_setup.default_sync	= val;
-		else if	(!strncmp(cur, "verb:", 5))
-			driver_setup.verbose	= val;
-		else if	(!strncmp(cur, "debug:", 6))
-			driver_setup.debug	= val;
-		else if	(!strncmp(cur, "burst:", 6))
-			driver_setup.burst_max	= val;
-		else if	(!strncmp(cur, "led:", 4))
-			driver_setup.led_pin	= val;
-		else if	(!strncmp(cur, "wide:", 5))
-			driver_setup.max_wide	= val? 1:0;
-		else if	(!strncmp(cur, "settle:", 7))
-			driver_setup.settle_delay= val;
-		else if	(!strncmp(cur, "diff:", 5))
-			driver_setup.diff_support= val;
-		else if	(!strncmp(cur, "irqm:", 5))
-			driver_setup.irqm	= val;
-		else if	(!strncmp(cur, "pcifix:", 7))
-			driver_setup.pci_fix_up	= val;
-		else if	(!strncmp(cur, "buschk:", 7))
-			driver_setup.bus_check	= val;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-		else if	(!strncmp(cur, "nvram:", 6))
-			driver_setup.use_nvram	= val;
-#endif
-
-		else if	(!strncmp(cur, "safe:", 5) && val)
-			memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
-		else if	(!strncmp(cur, "excl:", 5)) {
-			if (xi < SCSI_NCR_MAX_EXCLUDES)
-				driver_setup.excludes[xi++] = val;
-		}
-		else if	(!strncmp(cur, "hostid:", 7))
-			driver_setup.host_id	= val;
-		else
-			printk("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
-
-		if ((cur = strchr(cur, ARG_SEP)) != NULL)
-			++cur;
-	}
-#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
-}
-
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
-	     uchar bus, uchar device_fn, ncr_device *device);
-
-/*
-**   Linux entry point for NCR53C8XX devices detection routine.
-**
-**   Called by the middle-level scsi drivers at initialization time,
-**   or at module installation.
-**
-**   Read the PCI configuration and try to attach each
-**   detected NCR board.
-**
-**   If NVRAM is present, try to attach boards according to 
-**   the used defined boot order.
-**
-**   Returns the number of boards successfully attached.
-*/
-
-__initfunc(
-static void ncr_print_driver_setup(void)
-)
-{
-#define YesNo(y)	y ? 'y' : 'n'
-	printk ("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d,"
-		"burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n",
-		YesNo(driver_setup.disconnection),
-		driver_setup.special_features,
-		driver_setup.ultra_scsi,
-		driver_setup.default_tags,
-		driver_setup.default_sync,
-		driver_setup.burst_max,
-		YesNo(driver_setup.max_wide),
-		driver_setup.diff_support,
-		YesNo(driver_setup.reverse_probe),
-		driver_setup.bus_check);
-
-	printk ("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,"
-		"led:%c,settle:%d,irqm:%d,nvram:0x%x,pcifix:0x%x\n",
-		YesNo(driver_setup.master_parity),
-		YesNo(driver_setup.scsi_parity),
-		YesNo(driver_setup.force_sync_nego),
-		driver_setup.verbose,
-		driver_setup.debug,
-		YesNo(driver_setup.led_pin),
-		driver_setup.settle_delay,
-		driver_setup.irqm,
-		driver_setup.use_nvram,
-		driver_setup.pci_fix_up);
-#undef YesNo
-}
-
-/*
-**   NCR53C8XX devices description table and chip ids list.
-*/
-
-static ncr_chip	ncr_chip_table[] __initdata	= SCSI_NCR_CHIP_TABLE;
-static ushort	ncr_chip_ids[]   __initdata	= SCSI_NCR_CHIP_IDS;
-
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-__initfunc(
-static int
-ncr_attach_using_nvram(Scsi_Host_Template *tpnt, int nvram_index, int count, ncr_device device[])
-)
-{
-	int i, j;
-	int attach_count = 0;
-	ncr_nvram  *nvram;
-	ncr_device *devp = 0;	/* to shut up gcc */
-
-	if (!nvram_index)
-		return 0;
-
-	/* find first Symbios NVRAM if there is one as we need to check it for host boot order */
-	for (i = 0, nvram_index = -1; i < count; i++) {
-		devp  = &device[i];
-		nvram = devp->nvram;
-		if (!nvram)
-			continue;
-		if (nvram->type == SCSI_NCR_SYMBIOS_NVRAM) {
-			if (nvram_index == -1)
-				nvram_index = i;
-#ifdef SCSI_NCR_DEBUG_NVRAM
-			printk("ncr53c8xx: NVRAM: Symbios format Boot Block, 53c%s, PCI bus %d, device %d, function %d\n",
-				devp->chip.name, devp->slot.bus, 
-				(int) (devp->slot.device_fn & 0xf8) >> 3, 
-				(int) devp->slot.device_fn & 7);
-			for (j = 0 ; j < 4 ; j++) {
-				Symbios_host *h = &nvram->data.Symbios.host[j];
-			printk("ncr53c8xx: BOOT[%d] device_id=%04x vendor_id=%04x device_fn=%02x io_port=%04x %s\n",
-				j,		h->device_id,	h->vendor_id,
-				h->device_fn,	h->io_port,
-				(h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) ? "SCAN AT BOOT" : "");
-			}
-		}
-		else if (nvram->type == SCSI_NCR_TEKRAM_NVRAM) {
-			/* display Tekram nvram data */
-			printk("ncr53c8xx: NVRAM: Tekram format data, 53c%s, PCI bus %d, device %d, function %d\n",
-				devp->chip.name, devp->slot.bus, 
-				(int) (devp->slot.device_fn & 0xf8) >> 3, 
-				(int) devp->slot.device_fn & 7);
-#endif
-		}
-	}
-
-	if (nvram_index >= 0 && nvram_index < count)
-		nvram = device[nvram_index].nvram;
-	else
-		nvram = 0;
-
-	if (!nvram)
-		goto out;
-
-	/* 
-	** check devices in the boot record against devices detected. 
-	** attach devices if we find a match. boot table records that 
-	** do not match any detected devices will be ignored. 
-	** devices that do not match any boot table will not be attached
-	** here but will attempt to be attached during the device table 
-	** rescan.
-	*/
-     	for (i = 0; i < 4; i++) {
-		Symbios_host *h = &nvram->data.Symbios.host[i];
-		for (j = 0 ; j < count ; j++) {
-			devp = &device[j];
-			if (h->device_fn == devp->slot.device_fn &&
-#if 0	/* bus number location in nvram ? */
-			    h->bus	 == devp->slot.bus	 &&
-#endif
-			    h->device_id == devp->chip.device_id)
-				break;
-		}
-		if (j < count && !devp->attach_done) {
-			if (!ncr_attach (tpnt, attach_count, devp))
-				attach_count++;
-			devp->attach_done = 1;
-		}
-	}
-
-out:
-	return attach_count;
-}
-#endif /* SCSI_NCR_NVRAM_SUPPORT */
-
-__initfunc(
-int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
-)
-{
-	int i, j;
-	int chips;
-	int count = 0;
-	uchar bus, device_fn;
-	short index;
-	int attach_count = 0;
-	ncr_device device[8];
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-	ncr_nvram  nvram[4];
-	int k, nvrams;
-#endif
-	int hosts;
-
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-	int nvram_index = 0;
-#endif
-
-#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
-	ncr_debug = driver_setup.debug;
-#endif
-
-     tpnt->proc_dir = &proc_scsi_ncr53c8xx;
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-     tpnt->proc_info = ncr53c8xx_proc_info;
-#endif
-
-#if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
-if (ncr53c8xx)
-	ncr53c8xx_setup(ncr53c8xx, (int *) 0);
-#endif
-
-	if (initverbose >= 2)
-		ncr_print_driver_setup();
-
-	/* 
-	** Detect all 53c8xx hosts and then attach them.
-	**
-	** If we are using NVRAM, once all hosts are detected, we need to check
-	** any NVRAM for boot order in case detect and boot order differ and
-	** attach them using the order in the NVRAM.
-	**
-	** If no NVRAM is found or data appears invalid attach boards in the 
-	** the order they are detected.
-	*/
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,92)
-	if (!pci_present())
-#else
-	if (!pcibios_present())
-#endif
-		return 0;
-
-	chips	= sizeof(ncr_chip_ids)	/ sizeof(ncr_chip_ids[0]);
-	hosts	= sizeof(device)	/ sizeof(device[0]);
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-	k = 0;
-	if (driver_setup.use_nvram & 0x1)
-		nvrams	= sizeof(nvram)	/ sizeof(nvram[0]);
-	else
-		nvrams	= 0;
-#endif
-
-	for (j = 0; j < chips ; ++j) {
-		i = driver_setup.reverse_probe ? chips-1 - j : j;
-		for (index = 0; ; index++) {
-			char *msg = "";
-			if ((pcibios_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
-						index, &bus, &device_fn)) ||
-			    (count == hosts))
-				break;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-			device[count].nvram = k < nvrams ? &nvram[k] : 0;
-#else
-			device[count].nvram = 0;
-#endif
-			if (ncr53c8xx_pci_init(tpnt, bus, device_fn, &device[count])) {
-				device[count].nvram = 0;
-				continue;
-			}
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-			if (device[count].nvram) {
-				++k;
-				nvram_index |= device[count].nvram->type;
-				switch (device[count].nvram->type) {
-				case SCSI_NCR_TEKRAM_NVRAM:
-					msg = "with Tekram NVRAM";
-					break;
-				case SCSI_NCR_SYMBIOS_NVRAM:
-					msg = "with Symbios NVRAM";
-					break;
-				default:
-					msg = "";
-					device[count].nvram = 0;
-					--k;
-				}
-			}
-#endif
-			printk(KERN_INFO "ncr53c8xx: 53c%s detected %s\n",
-				device[count].chip.name, msg);
-			++count;
-		}
-	}
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-	attach_count = ncr_attach_using_nvram(tpnt, nvram_index, count, device);
-#endif
-	/* 
-	** rescan device list to make sure all boards attached.
-	** devices without boot records will not be attached yet
-	** so try to attach them here.
-	*/
-	for (i= 0; i < count; i++) {
-		if (!device[i].attach_done && 
-		    !ncr_attach (tpnt, attach_count, &device[i])) {
-			attach_count++;
-		}
-	}
-
-	return attach_count;
-}
-
-/*
-**   Generically read a base address from the PCI configuration space.
-**   Return the offset immediately after the base address that has 
-**   been read. Btw, we blindly assume that the high 32 bits of 64 bit 
-**   base addresses are set to zero on 32 bit architectures.
-**
-*/
-#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
-__initfunc(
-static int 
-pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
-)
-{
-	u_int32 tmp;
-
-	pcibios_read_config_dword(bus, device_fn, offset, &tmp);
-	*base = tmp;
-	offset += sizeof(u_int32);
-	if ((tmp & 0x7) == 0x4) {
-#if BITS_PER_LONG > 32
-		pcibios_read_config_dword(bus, device_fn, offset, &tmp);
-		*base |= (((u_long)tmp) << 32);
-#endif
-		offset += sizeof(u_int32);
-	}
-	return offset;
-}
-#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */
-__initfunc(
-static int 
-pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
-)
-{
-	*base = pdev->base_address[index++];
-	if ((*base & 0x7) == 0x4) {
-#if BITS_PER_LONG > 32
-		*base |= (((u_long)pdev->base_address[index]) << 32);
-#endif
-		++index;
-	}
-	return index;
-}
-#endif
-
-/*
-**   Read and check the PCI configuration for any detected NCR 
-**   boards and save data for attaching after all boards have 
-**   been detected.
-*/
-
-__initfunc(
-static int 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;
-	uchar revision;
-#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
-	struct pci_dev *pdev;
-	uint irq;
-#else
-	uchar irq;
-#endif
-	ulong base, base_2, io_port; 
-	int i;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-	ncr_nvram *nvram = device->nvram;
-#endif
-	ncr_chip *chip;
-
-	/*
-	**    Read info from the PCI config space.
-	**    pcibios_read_config_xxx() functions are assumed to be used for 
-	**    successfully detected PCI devices.
-	*/
-#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
-	pdev = pci_find_slot(bus, device_fn);
-	vendor_id = pdev->vendor;
-	device_id = pdev->device;
-	irq = pdev->irq;
-	i =	0;
-	i =	pci_get_base_address(pdev, i, &io_port);
-	i =	pci_get_base_address(pdev, i, &base);
-	(void)	pci_get_base_address(pdev, i, &base_2);
-#else
-	pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id);
-	pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id);
-	pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq);
-	i =	PCI_BASE_ADDRESS_0;
-	i =	pci_read_base_address(bus, device_fn, i, &io_port);
-	i =	pci_read_base_address(bus, device_fn, i, &base);
-	(void)	pci_read_base_address(bus, device_fn, i, &base_2);
-#endif
-	pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
-	pcibios_read_config_byte(bus, device_fn, PCI_CLASS_REVISION, &revision);
-	pcibios_read_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE,
-				 &cache_line_size);
-	pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER,
-				 &latency_timer);
-
-	/*
-	**	If user excludes this chip, donnot initialize it.
-	*/
-	for (i = 0 ; i < SCSI_NCR_MAX_EXCLUDES ; i++) {
-		if (driver_setup.excludes[i] ==
-				(io_port & PCI_BASE_ADDRESS_IO_MASK))
-			return -1;
-	}
-	/*
-	 *	Check if the chip is supported
-	 */
-	chip = 0;
-	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)
-			continue;
-		chip = &device->chip;
-		memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
-		chip->revision_id = revision;
-		break;
-	}
-
-#if defined(__i386__)
-	/*
-	 *	Ignore Symbios chips controlled by SISL RAID controller.
-	 */
-	if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
-		unsigned int ScriptsSize, MagicValue;
-		vm_offset_t ScriptsRAM;
-
-		if (chip->features & FE_RAM8K)
-			ScriptsSize = 8192;
-		else
-			ScriptsSize = 4096;
-
-		ScriptsRAM = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK,
-					   ScriptsSize);
-		if (ScriptsRAM) {
-			MagicValue = readl(ScriptsRAM + ScriptsSize - 16);
-			unmap_pci_mem(ScriptsRAM, ScriptsSize);
-			if (MagicValue == 0x52414944)
-				return -1;
-		}
-	}
-#endif
-
-	printk(KERN_INFO "ncr53c8xx: at PCI bus %d, device %d, function %d\n",
-		bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
-
-	if (!chip) {
-		printk("ncr53c8xx: not initializing, device not supported\n");
-		return -1;
-	}
-
-#ifdef __powerpc__
-	/*
-	 *	Several fix-up for power/pc.
-	 *	Should not be performed by the driver.
-	 */
-	if (!(command & PCI_COMMAND_MASTER)) {
-		printk("ncr53c8xx: attempting to force PCI_COMMAND_MASTER...");
-		command |= PCI_COMMAND_MASTER;
-		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
-		pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
-		if (!(command & PCI_COMMAND_MASTER)) {
-			printk("failed!\n");
-		} else {
-			printk("succeeded.\n");
-		}
-	}
-
-	if (!(command & PCI_COMMAND_IO)) {
-		printk("ncr53c8xx: attempting to force PCI_COMMAND_IO...");
-		command |= PCI_COMMAND_IO;
-		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
-		pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
-		if (!(command & PCI_COMMAND_IO)) {
-			printk("failed!\n");
-		} else {
-			printk("succeeded.\n");
-		}
-	}
-
-	if (!(command & PCI_COMMAND_MEMORY)) {
-		printk("ncr53c8xx: attempting to force PCI_COMMAND_MEMORY...");
-		command |= PCI_COMMAND_MEMORY;
-		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
-		pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
-		if (!(command & PCI_COMMAND_MEMORY)) {
-			printk("failed!\n");
-		} else {
-			printk("succeeded.\n");
-		}
-	}
-
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,140)
-	if ( is_prep ) {
-		if (io_port >= 0x10000000) {
-			printk("ncr53c8xx: reallocating io_port (Wacky IBM)");
-			io_port = (io_port & 0x00FFFFFF) | 0x01000000;
-			pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
-		}
-		if (base >= 0x10000000) {
-			printk("ncr53c8xx: reallocating base (Wacky IBM)");
-			base = (base & 0x00FFFFFF) | 0x01000000;
-			pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, base);
-		}
-		if (base_2 >= 0x10000000) {
-			printk("ncr53c8xx: reallocating base2 (Wacky IBM)");
-			base_2 = (base_2 & 0x00FFFFFF) | 0x01000000;
-			pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2, base_2);
-		}
-	}
-#endif
-#endif	/* __powerpc__ */
-
-#ifdef __sparc__
-	/*
-	 *	Severall fix-ups for sparc.
-	 *
-	 *	Should not be performed by the driver, but how can OBP know
-	 *	each and every PCI card, if they don't use Fcode?
-	 */
-
-	base = __pa(base);
-	base_2 = __pa(base_2);
-
-	if (!(command & PCI_COMMAND_MASTER)) {
-		if (initverbose >= 2)
-			printk("ncr53c8xx: setting PCI_COMMAND_MASTER bit (fixup)\n");
-		command |= PCI_COMMAND_MASTER;
-		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
-		pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
-	}
-
-	if ((chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
-		if (initverbose >= 2)
-			printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fixup)\n");
-		command |= PCI_COMMAND_INVALIDATE;
-		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
-		pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
-	}
-
-	if ((chip->features & FE_CLSE) && !cache_line_size) {
-		/* 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);
-		pcibios_write_config_byte(bus, device_fn,
-					  PCI_CACHE_LINE_SIZE, cache_line_size);
-		pcibios_read_config_byte(bus, device_fn,
-					 PCI_CACHE_LINE_SIZE, &cache_line_size);
-	}
-
-	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);
-		pcibios_write_config_byte(bus, device_fn,
-					  PCI_LATENCY_TIMER, latency_timer);
-		pcibios_read_config_byte(bus, device_fn,
-					 PCI_LATENCY_TIMER, &latency_timer);
-	}
-#endif	/* __sparc__ */
-
-	/*
-	 * 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;
-	}
-	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;
-	}
-	else
-		base = 0;
-	
-	if (!io_port && !base) {
-		printk("ncr53c8xx: not initializing, both I/O and memory mappings disabled\n");
-		return -1;
-	}
-
-	base_2 &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	if (io_port && check_region (io_port, 128)) {
-#ifdef __sparc__
-		printk("ncr53c8xx: IO region 0x%lx to 0x%lx is in use\n",
-			io_port, (io_port + 127));
-#else
-		printk("ncr53c8xx: IO region 0x%x to 0x%x is in use\n",
-			(int) io_port, (int) (io_port + 127));
-#endif
-		return -1;
-	}
-	
-	if (!(command & PCI_COMMAND_MASTER)) {
-		printk("ncr53c8xx: not initializing, BUS MASTERING was disabled\n");
-		return -1;
-	}
-
-	/*
-	 * Fix some features according to driver setup.
-	 */
-	if (!(driver_setup.special_features & 1))
-		chip->features &= ~FE_SPECIAL_SET;
-	else {
-		if (driver_setup.special_features & 2)
-			chip->features &= ~FE_WRIE;
-	}
-	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;
-
-
-#ifdef	SCSI_NCR_PCI_FIX_UP_SUPPORT
-
-	/*
-	 * Try to fix up PCI config according to wished features.
-	 */
-#if defined(__i386__) && !defined(MODULE)
-	if ((driver_setup.pci_fix_up & 1) &&
-	    (chip->features & FE_CLSE) && cache_line_size == 0) {
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
-		extern char x86;
-		switch(x86) {
-#else
-		switch(boot_cpu_data.x86) {
-#endif
-		case 4:	cache_line_size = 4; break;
-		case 6:
-		case 5:	cache_line_size = 8; break;
-		}
-		if (cache_line_size)
-			(void) pcibios_write_config_byte(bus, device_fn,
-					PCI_CACHE_LINE_SIZE, cache_line_size);
-		if (initverbose)
-			printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fix-up).\n", cache_line_size);
-	}
-
-	if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
-	    (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
-		command |= PCI_COMMAND_INVALIDATE;
-		(void) pcibios_write_config_word(bus, device_fn,
-						PCI_COMMAND, command);
-		if (initverbose)
-			printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fix-up).\n");
-	}
-#endif
-	/*
-	 * Fix up for old chips that support READ LINE but not CACHE LINE SIZE.
-	 * - If CACHE LINE SIZE is unknown, set burst max to 32 bytes = 8 dwords
-	 *   and donnot enable READ LINE.
-	 * - Otherwise set it to the CACHE LINE SIZE (power of 2 assumed). 
-	 */
-
-	if (!(chip->features & FE_CLSE)) {
-		int burst_max = chip->burst_max;
-		if (cache_line_size == 0) {
-			chip->features	&= ~FE_ERL;
-			if (burst_max > 3)
-				burst_max = 3;
-		}
-		else {
-			while (cache_line_size < (1 << burst_max))
-				--burst_max;
-		}
-		chip->burst_max = burst_max;
-	}
-
-	/*
-	 * Tune PCI LATENCY TIMER according to burst max length transfer.
-	 * (latency timer >= burst length + 6, we add 10 to be quite sure)
-	 * If current value is zero, the device has probably been configured 
-	 * for no bursting due to some broken hardware.
-	 */
-
-	if (latency_timer == 0 && chip->burst_max)
-		printk("ncr53c8xx: PCI_LATENCY_TIMER=0, bursting should'nt be allowed.\n");
-
-	if ((driver_setup.pci_fix_up & 4) && chip->burst_max) {
-		uchar lt = (1 << chip->burst_max) + 6 + 10;
-		if (latency_timer < lt) {
-			latency_timer = lt;
-			if (initverbose)
-				printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fix-up).\n", latency_timer);
-			 (void) pcibios_write_config_byte(bus, device_fn,
-					PCI_LATENCY_TIMER, latency_timer);
-		}
-	}
-
-	/*
-	 * Fix up for recent chips that support CACHE LINE SIZE.
-	 * If PCI config space is not OK, remove features that shall not be 
-	 * used by the chip. No need to trigger possible chip bugs.
-	 */
-
-	if ((chip->features & FE_CLSE) && cache_line_size == 0) {
-		chip->features &= ~FE_CACHE_SET;
-		printk("ncr53c8xx: PCI_CACHE_LINE_SIZE not set, features based on CACHE LINE SIZE not used.\n");
-	}
-
-	if ((chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
-		chip->features &= ~FE_WRIE;
-		printk("ncr53c8xx: PCI_COMMAND_INVALIDATE not set, WRITE AND INVALIDATE not used\n");
-	}
-
-#endif	/* SCSI_NCR_PCI_FIX_UP_SUPPORT */
-
- 	/* initialise ncr_device structure with items required by ncr_attach */
-	device->slot.bus	= bus;
-	device->slot.device_fn	= device_fn;
-	device->slot.base	= base;
-	device->slot.base_2	= base_2;
-	device->slot.io_port	= io_port;
-	device->slot.irq	= irq;
-	device->attach_done	= 0;
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-	if (!nvram)
-		goto out;
-
-	/*
-	** Get access to chip IO registers
-	*/
-#ifdef NCR_IOMAPPED
-	request_region(io_port, 128, "ncr53c8xx");
-	device->slot.port = io_port;
-#else
-	device->slot.reg = (struct ncr_reg *) remap_pci_mem((ulong) base, 128);
-	if (!device->slot.reg)
-		goto out;
-#endif
+		if	(f1 <	45000)		f1 =  40000;
+		else if (f1 <	55000)		f1 =  50000;
+		else				f1 =  80000;
 
-	/*
-	** Try to read SYMBIOS nvram.
-	** Data can be used to order booting of boards.
-	**
-	** Data is saved in ncr_device structure if NVRAM found. This
-	** is then used to find drive boot order for ncr_attach().
-	**
-	** NVRAM data is passed to Scsi_Host_Template later during ncr_attach()
-	** for any device set up.
-	**
-	** Try to read TEKRAM nvram if Symbios nvram not found.
-	*/
+		if (f1 < 80000 && mult > 1) {
+			if (bootverbose >= 2)
+				printk ("%s: clock multiplier assumed\n", ncr_name(np));
+			np->multiplier	= mult;
+		}
+	} else {
+		if	((scntl3 & 7) == 3)	f1 =  40000;
+		else if	((scntl3 & 7) == 5)	f1 =  80000;
+		else 				f1 = 160000;
+
+		f1 /= np->multiplier;
+	}
 
-	if	(!ncr_get_Symbios_nvram(&device->slot, &nvram->data.Symbios))
-		nvram->type = SCSI_NCR_SYMBIOS_NVRAM;
-	else if	(!ncr_get_Tekram_nvram(&device->slot, &nvram->data.Tekram))
-		nvram->type = SCSI_NCR_TEKRAM_NVRAM;
-	else
-		nvram->type = 0;
-out:
 	/*
-	** Release access to chip IO registers
+	**	Compute controller synchronous parameters.
 	*/
-#ifdef NCR_IOMAPPED
-	release_region(device->slot.port, 128);
-#else
-	unmap_pci_mem((vm_offset_t) device->slot.reg, (u_long) 128);
-#endif
-
-#endif	/* SCSI_NCR_NVRAM_SUPPORT */
-	return 0;     
+	f1		*= np->multiplier;
+	np->clock_khz	= f1;
 }
 
+/*===================== LINUX ENTRY POINTS SECTION ==========================*/
+
 /*
 **   Linux select queue depths function
 */
 
-#define DEF_DEPTH	(driver_setup.default_tags)
-#define ALL_TARGETS	-2
-#define NO_TARGET	-1
-#define ALL_LUNS	-2
-#define NO_LUN		-1
-
-static int device_queue_depth(ncb_p np, int target, int lun)
-{
-	int c, h, t, u, v;
-	char *p = driver_setup.tag_ctrl;
-	char *ep;
-
-	h = -1;
-	t = NO_TARGET;
-	u = NO_LUN;
-	while ((c = *p++) != 0) {
-		v = simple_strtoul(p, &ep, 0);
-		switch(c) {
-		case '/':
-			++h;
-			t = ALL_TARGETS;
-			u = ALL_LUNS;
-			break;
-		case 't':
-			if (t != target)
-				t = (target == v) ? v : NO_TARGET;
-			u = ALL_LUNS;
-			break;
-		case 'u':
-			if (u != lun)
-				u = (lun == v) ? v : NO_LUN;
-			break;
-		case 'q':
-			if (h == np->unit &&
-				(t == ALL_TARGETS || t == target) &&
-				(u == ALL_LUNS    || u == lun))
-				return v;
-			break;
-		case '-':
-			t = ALL_TARGETS;
-			u = ALL_LUNS;
-			break;
-		default:
-			break;
-		}
-		p = ep;
-	}
-	return DEF_DEPTH;
-}
-
 static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist)
 {
 	struct scsi_device *device;
@@ -10058,7 +8523,7 @@
 		**	Use at least 2.
 		**	Donnot use more than our maximum.
 		*/
-		numtags = device_queue_depth(np, device->id, device->lun);
+		numtags = device_queue_depth(np->unit, device->id, device->lun);
 		if (numtags > tp->usrtags)
 			numtags = tp->usrtags;
 		if (!device->tagged_supported)
@@ -10066,8 +8531,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,
@@ -10088,22 +8553,6 @@
 }
 
 /*
-**   Linux entry point for info() function
-*/
-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
-}
-
-/*
 **   Linux entry point of queuecommand() function
 */
 
@@ -10119,6 +8568,10 @@
 
      cmd->scsi_done     = done;
      cmd->host_scribble = NULL;
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+     cmd->__data_mapped = 0;
+     cmd->__data_mapping = 0;
+#endif
 
      NCR_LOCK_NCB(np, flags);
 
@@ -10135,8 +8588,10 @@
 
      NCR_UNLOCK_NCB(np, flags);
 
-     if (sts != DID_OK)
+     if (sts != DID_OK) {
+          unmap_scsi_data(np, cmd);
           done(cmd);
+     }
 
      return sts;
 }
@@ -10497,8 +8952,6 @@
 		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, "clearprof")) != 0)
-		uc->cmd = UC_CLEARPROF;
 	else
 		arg_len = 0;
 
@@ -10558,8 +9011,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 +9027,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;
@@ -10618,106 +9065,53 @@
 
 #endif	/* SCSI_NCR_USER_COMMAND_SUPPORT */
 
-#ifdef SCSI_NCR_USER_INFO_SUPPORT
-
-struct info_str
-{
-	char *buffer;
-	int length;
-	int offset;
-	int pos;
-};
-
-static void copy_mem_info(struct info_str *info, char *data, int len)
-{
-	if (info->pos + len > info->length)
-		len = info->length - info->pos;
-
-	if (info->pos + len < info->offset) {
-		info->pos += len;
-		return;
-	}
-	if (info->pos < info->offset) {
-		data += (info->offset - info->pos);
-		len  -= (info->offset - info->pos);
-	}
-
-	if (len > 0) {
-		memcpy(info->buffer + info->pos, data, len);
-		info->pos += len;
-	}
-}
-
-static int copy_info(struct info_str *info, char *fmt, ...)
-{
-	va_list args;
-	char buf[81];
-	int len;
-
-	va_start(args, fmt);
-	len = vsprintf(buf, fmt, args);
-	va_end(args);
-
-	copy_mem_info(info, buf, len);
-	return len;
-}
 
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
 /*
-**	Copy formatted profile information into the input buffer.
+**	Copy formatted information into the input buffer.
 */
 
-#define to_ms(t) ((t) * 1000 / HZ)
-
 static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
 {
 	struct info_str info;
+#ifdef CONFIG_ALL_PPC
+	struct device_node* of_node;
+#endif
 
 	info.buffer	= ptr;
 	info.length	= len;
 	info.offset	= offset;
 	info.pos	= 0;
 
-	copy_info(&info, "General information:\n");
-	copy_info(&info, "  Chip NCR53C%s, ",	np->chip_name);
-	copy_info(&info, "device id 0x%x, ",	np->device_id);
-	copy_info(&info, "revision id 0x%x\n",	np->revision_id);
-
-	copy_info(&info, "  IO port address 0x%lx, ", (u_long) np->port);
+	copy_info(&info, "  Chip NCR53C%s, device id 0x%x, "
+			 "revision id 0x%x\n",
+			 np->chip_name, np->device_id,	np->revision_id);
+	copy_info(&info, "  On PCI bus %d, device %d, function %d, "
 #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);
+		"IRQ %s\n",
 #else
-	copy_info(&info, "IRQ number %d\n", (int) np->irq);
+		"IRQ %d\n",
 #endif
-
-#ifndef NCR_IOMAPPED
-	if (np->reg)
-		copy_info(&info, "  Using memory mapped IO at virtual address 0x%lx\n",
-		                  (u_long) np->reg);
+		np->bus, (np->device_fn & 0xf8) >> 3, np->device_fn & 7,
+#ifdef __sparc__
+		__irq_itoa(np->irq));
+#else
+		(int) np->irq);
 #endif
-	copy_info(&info, "  Synchronous period factor %d, ", (int) np->minsync);
-	copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+#ifdef CONFIG_ALL_PPC
+	of_node = find_pci_device_OFnode(np->bus, np->device_fn);
+	if (of_node && of_node->full_name)
+	    copy_info(&info, "PPC OpenFirmware path : %s\n", of_node->full_name);
+#endif
+	copy_info(&info, "  Synchronous period factor %d, "
+			 "max commands per lun %d\n",
+			 (int) np->minsync, MAX_TAGS);
 
 	if (driver_setup.debug || driver_setup.verbose > 1) {
-		copy_info(&info, "  Debug flags 0x%x, ", driver_setup.debug);
-		copy_info(&info, "verbosity level %d\n", driver_setup.verbose);
+		copy_info(&info, "  Debug flags 0x%x, verbosity level %d\n",
+			  driver_setup.debug, driver_setup.verbose);
 	}
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	copy_info(&info, "Profiling information:\n");
-	copy_info(&info, "  %-12s = %lu\n", "num_trans",np->profile.num_trans);
-	copy_info(&info, "  %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes);
-	copy_info(&info, "  %-12s = %lu\n", "num_disc",	np->profile.num_disc);
-	copy_info(&info, "  %-12s = %lu\n", "num_break",np->profile.num_break);
-	copy_info(&info, "  %-12s = %lu\n", "num_int",	np->profile.num_int);
-	copy_info(&info, "  %-12s = %lu\n", "num_fly",	np->profile.num_fly);
-	copy_info(&info, "  %-12s = %lu\n", "ms_setup",	to_ms(np->profile.ms_setup));
-	copy_info(&info, "  %-12s = %lu\n", "ms_data",	to_ms(np->profile.ms_data));
-	copy_info(&info, "  %-12s = %lu\n", "ms_disc",	to_ms(np->profile.ms_disc));
-	copy_info(&info, "  %-12s = %lu\n", "ms_post",	to_ms(np->profile.ms_post));
-#endif
-	
 	return info.pos > info.offset? info.pos - info.offset : 0;
 }
 
@@ -10772,7 +9166,6 @@
 	return retv;
 }
 
-
 /*=========================================================================
 **	End of proc file system stuff
 **=========================================================================
@@ -10780,458 +9173,104 @@
 #endif
 
 
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-
-/* ---------------------------------------------------------------------
+/*==========================================================
 **
-**	Try reading Symbios format nvram
+**	/proc directory entry.
 **
-** ---------------------------------------------------------------------
+**==========================================================
+*/
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+static struct proc_dir_entry proc_scsi_ncr53c8xx = {
+    PROC_SCSI_NCR53C8XX, 9, NAME53C8XX,
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#endif
+
+/*==========================================================
 **
-** GPOI0 - data in/data out
-** GPIO1 - clock
+**	Boot command line.
 **
-**	return 0 if NVRAM data OK, 1 if NVRAM data not OK
-** ---------------------------------------------------------------------
-*/
-
-#define SET_BIT 0
-#define CLR_BIT 1
-#define SET_CLK 2
-#define CLR_CLK 3
-
-static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl);
-static void nvram_start(ncr_slot *np, u_char *gpreg);
-static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl);
-static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl);
-static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl);
-static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl);
-static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg);
-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 u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
-	u_char	gpcntl, gpreg;
-	u_char	old_gpcntl, old_gpreg;
-	u_short	csum;
-	u_char	ack_data;
-	int	retv = 1;
-
-	/* save current state of GPCNTL and GPREG */
-	old_gpreg	= INB (nc_gpreg);
-	old_gpcntl	= INB (nc_gpcntl);
-	gpcntl		= old_gpcntl & 0xfc;
-
-	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
-	OUTB (nc_gpreg,  old_gpreg);
-	OUTB (nc_gpcntl, gpcntl);
-
-	/* this is to set NVRAM into a known state with GPIO0/1 both low */
-	gpreg = old_gpreg;
-	nvram_setBit(np, 0, &gpreg, CLR_CLK);
-	nvram_setBit(np, 0, &gpreg, CLR_BIT);
-		
-	/* now set NVRAM inactive with GPIO0/1 both high */
-	nvram_stop(np, &gpreg);
-	
-	/* activate NVRAM */
-	nvram_start(np, &gpreg);
-
-	/* write device code and random address MSB */
-	nvram_write_byte(np, &ack_data,
-		0xa0 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl);
-	if (ack_data & 0x01)
-		goto out;
-
-	/* write random address LSB */
-	nvram_write_byte(np, &ack_data,
-		(SYMBIOS_NVRAM_ADDRESS & 0x7f) << 1, &gpreg, &gpcntl);
-	if (ack_data & 0x01)
-		goto out;
-
-	/* regenerate START state to set up for reading */
-	nvram_start(np, &gpreg);
-	
-	/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
-	nvram_write_byte(np, &ack_data,
-		0xa1 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl);
-	if (ack_data & 0x01)
-		goto out;
-
-	/* now set up GPIO0 for inputting data */
-	gpcntl |= 0x01;
-	OUTB (nc_gpcntl, gpcntl);
-		
-	/* input all active data - only part of total NVRAM */
-	csum = nvram_read_data(np,
-			(u_char *) nvram, sizeof(*nvram), &gpreg, &gpcntl);
-
-	/* finally put NVRAM back in inactive mode */
-	gpcntl &= 0xfe;
-	OUTB (nc_gpcntl, gpcntl);
-	nvram_stop(np, &gpreg);
-	
-#ifdef SCSI_NCR_DEBUG_NVRAM
-printk("ncr53c8xx: NvRAM type=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
-	nvram->type,
-	nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
-	nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
-	nvram->byte_count, sizeof(*nvram) - 12,
-	nvram->checksum, csum);
+**==========================================================
+*/
+#ifdef	MODULE
+char *ncr53c8xx = 0;	/* command line passed by insmod */
+# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_PARM(ncr53c8xx, "s");
+# endif
 #endif
 
-	/* check valid NVRAM signature, verify byte count and checksum */
-	if (nvram->type == 0 &&
-	    !memcmp(nvram->trailer, Symbios_trailer, 6) &&
-	    nvram->byte_count == sizeof(*nvram) - 12 &&
-	    csum == nvram->checksum)
-		retv = 0;
-out:
-	/* return GPIO0/1 to original states after having accessed NVRAM */
-	OUTB (nc_gpcntl, old_gpcntl);
-	OUTB (nc_gpreg,  old_gpreg);
-
-	return retv;
-}
-
-/*
- * 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)
-)
-{
-	int	x;
-	u_short	csum;
-
-	for (x = 0; x < len; x++) 
-		nvram_read_byte(np, &data[x], (x == (len - 1)), gpreg, gpcntl);
-
-	for (x = 6, csum = 0; x < len - 6; x++)
-		csum += data[x];
-
-	return csum;
-}
-
-/*
- * Send START condition to NVRAM to wake it up.
- */
-__initfunc(
-static void nvram_start(ncr_slot *np, u_char *gpreg)
-)
-{
-	nvram_setBit(np, 1, gpreg, SET_BIT);
-	nvram_setBit(np, 0, gpreg, SET_CLK);
-	nvram_setBit(np, 0, gpreg, CLR_BIT);
-	nvram_setBit(np, 0, gpreg, CLR_CLK);
-}
-
-/*
- * 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)
-)
-{
-	int x;
-	
-	for (x = 0; x < 8; x++)
-		nvram_doBit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
-		
-	nvram_readAck(np, ack_data, gpreg, gpcntl);
-}
-
-/*
- * 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)
-)
-{
-	int x;
-	u_char read_bit;
-
-	*read_data = 0;
-	for (x = 0; x < 8; x++) {
-		nvram_doBit(np, &read_bit, 1, gpreg);
-		*read_data |= ((read_bit & 0x01) << (7 - x));
-	}
-
-	nvram_writeAck(np, ack_data, gpreg, gpcntl);
-}
-
-/*
- * 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)
-)
-{
-	OUTB (nc_gpcntl, *gpcntl & 0xfe);
-	nvram_doBit(np, 0, write_bit, gpreg);
-	OUTB (nc_gpcntl, *gpcntl);
-}
-
-/*
- * 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)
-)
-{
-	OUTB (nc_gpcntl, *gpcntl | 0x01);
-	nvram_doBit(np, read_bit, 1, gpreg);
-	OUTB (nc_gpcntl, *gpcntl);
-}
-
-/*
- * 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)
-)
+int __init ncr53c8xx_setup(char *str)
 {
-	nvram_setBit(np, write_bit, gpreg, SET_BIT);
-	nvram_setBit(np, 0, gpreg, SET_CLK);
-	if (read_bit)
-		*read_bit = INB (nc_gpreg);
-	nvram_setBit(np, 0, gpreg, CLR_CLK);
-	nvram_setBit(np, 0, gpreg, CLR_BIT);
+	return sym53c8xx__setup(str);
 }
 
-/*
- * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
- */
-__initfunc(
-static void nvram_stop(ncr_slot *np, u_char *gpreg)
-)
-{
-	nvram_setBit(np, 0, gpreg, SET_CLK);
-	nvram_setBit(np, 1, gpreg, SET_BIT);
-}
-
-/*
- * 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)
-)
-{
-	UDELAY (5);
-	switch (bit_mode){
-	case SET_BIT:
-		*gpreg |= write_bit;
-		break;
-	case CLR_BIT:
-		*gpreg &= 0xfe;
-		break;
-	case SET_CLK:
-		*gpreg |= 0x02;
-		break;
-	case CLR_CLK:
-		*gpreg &= 0xfd;
-		break;
-
-	}
-	OUTB (nc_gpreg, *gpreg);
-	UDELAY (5);
-}
-
-#undef SET_BIT 0
-#undef CLR_BIT 1
-#undef SET_CLK 2
-#undef CLR_CLK 3
-
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("ncr53c8xx=", ncr53c8xx_setup);
+#endif
+#endif
 
-/* ---------------------------------------------------------------------
-**
-**	Try reading Tekram format nvram
-**
-** ---------------------------------------------------------------------
+/*===================================================================
 **
-** GPOI0 - data in
-** GPIO1 - data out
-** GPIO2 - clock
-** GPIO4 - chip select
+**   SYM53C8XX supported device list
 **
-**	return 0 if NVRAM data OK, 1 if NVRAM data not OK
-** ---------------------------------------------------------------------
+**===================================================================
 */
 
-static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg);
-static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg);
-static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg);
-static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg);
-static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg);
-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)
-)
-{
-	u_char gpcntl, gpreg;
-	u_char old_gpcntl, old_gpreg;
-	u_short csum;
-
-	/* save current state of GPCNTL and GPREG */
-	old_gpreg	= INB (nc_gpreg);
-	old_gpcntl	= INB (nc_gpcntl);
-
-	/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
-	   1/2/4 out */
-	gpreg = old_gpreg & 0xe9;
-	OUTB (nc_gpreg, gpreg);
-	gpcntl = (old_gpcntl & 0xe9) | 0x09;
-	OUTB (nc_gpcntl, gpcntl);
-
-	/* input all of NVRAM, 64 words */
-	csum = Tnvram_read_data(np, (u_short *) nvram,
-			sizeof(*nvram) / sizeof(short), &gpreg);
-	
-	/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
-	OUTB (nc_gpcntl, old_gpcntl);
-	OUTB (nc_gpreg,  old_gpreg);
-
-	/* check data valid */
-	if (csum != 0x1234)
-		return 1;
-
-	return 0;
-}
-
-/*
- * 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)
-)
-{
-	u_char	read_bit;
-	u_short	csum;
-	int	x;
-
-	for (x = 0, csum = 0; x < len; x++)  {
-
-		/* output read command and address */
-		Tnvram_Send_Command(np, 0x180 | x, &read_bit, gpreg);
-		if (read_bit & 0x01)
-			return 0; /* Force bad checksum */
-
-		Tnvram_Read_Word(np, &data[x], gpreg);
-		csum += data[x];
-
-		Tnvram_Stop(np, gpreg);
-	}
-
-	return csum;
-}
-
-/*
- * 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)
-)
-{
-	int x;
-
-	/* send 9 bits, start bit (1), command (2), address (6)  */
-	for (x = 0; x < 9; x++)
-		Tnvram_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
-
-	*read_bit = INB (nc_gpreg);
-}
-
-/*
- * READ a byte from the NVRAM
- */
-__initfunc(
-static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
-)
-{
-	int x;
-	u_char read_bit;
-
-	*nvram_data = 0;
-	for (x = 0; x < 16; x++) {
-		Tnvram_Read_Bit(np, &read_bit, gpreg);
-
-		if (read_bit & 0x01)
-			*nvram_data |=  (0x01 << (15 - x));
-		else
-			*nvram_data &= ~(0x01 << (15 - x));
-	}
-}
-
-/* 
- * Read bit from NVRAM
- */
-__initfunc(
-static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
-)
-{
-	UDELAY (2);
-	Tnvram_Clk(np, gpreg);
-	*read_bit = INB (nc_gpreg);
-}
+static u_short	ncr_chip_ids[]   __initdata = {
+	PCI_DEVICE_ID_NCR_53C810,
+	PCI_DEVICE_ID_NCR_53C815,
+	PCI_DEVICE_ID_NCR_53C820,
+	PCI_DEVICE_ID_NCR_53C825,
+	PCI_DEVICE_ID_NCR_53C860,
+	PCI_DEVICE_ID_NCR_53C875,
+	PCI_DEVICE_ID_NCR_53C875J,
+	PCI_DEVICE_ID_NCR_53C885,
+	PCI_DEVICE_ID_NCR_53C895,
+	PCI_DEVICE_ID_NCR_53C896,
+	PCI_DEVICE_ID_NCR_53C895A,
+	PCI_DEVICE_ID_NCR_53C1510D
+};
 
-/*
- * Write bit to GPIO0
- */
-__initfunc(
-static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
-)
+/*==========================================================
+**
+**	Chip detection entry point.
+**
+**==========================================================
+*/
+int __init ncr53c8xx_detect(Scsi_Host_Template *tpnt)
 {
-	if (write_bit & 0x01)
-		*gpreg |= 0x02;
-	else
-		*gpreg &= 0xfd;
-		
-	*gpreg |= 0x10;
-		
-	OUTB (nc_gpreg, *gpreg);
-	UDELAY (2);
-
-	Tnvram_Clk(np, gpreg);
-}
+	/*
+	**    Initialize driver general stuff.
+	*/
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+     tpnt->proc_dir  = &proc_scsi_ncr53c8xx;
+#else
+     tpnt->proc_name = NAME53C8XX;
+#endif
+     tpnt->proc_info = ncr53c8xx_proc_info;
+#endif
 
-/*
- * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
- */
-__initfunc(
-static void Tnvram_Stop(ncr_slot *np, u_char *gpreg)
-)
-{
-	*gpreg &= 0xef;
-	OUTB (nc_gpreg, *gpreg);
-	UDELAY (2);
+#if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
+if (ncr53c8xx)
+	ncr53c8xx_setup(ncr53c8xx);
+#endif
 
-	Tnvram_Clk(np, gpreg);
+	return sym53c8xx__detect(tpnt, ncr_chip_ids,
+				 sizeof(ncr_chip_ids)/sizeof(ncr_chip_ids[0]));
 }
 
-/*
- * Pulse clock bit in GPIO0
- */
-__initfunc(
-static void Tnvram_Clk(ncr_slot *np, u_char *gpreg)
-)
+/*==========================================================
+**
+**   Entry point for info() function
+**
+**==========================================================
+*/
+const char *ncr53c8xx_info (struct Scsi_Host *host)
 {
-	OUTB (nc_gpreg, *gpreg | 0x04);
-	UDELAY (2);
-	OUTB (nc_gpreg, *gpreg);
+	return SCSI_NCR_DRIVER_NAME;
 }
-
-#endif	/* SCSI_NCR_NVRAM_SUPPORT */
 
 /*
 **	Module stuff
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi.c linux.18p8/drivers/scsi/scsi.c
--- linux.vanilla/drivers/scsi/scsi.c	Sat Sep  9 18:42:41 2000
+++ linux.18p8/drivers/scsi/scsi.c	Sun Sep  3 14:00:38 2000
@@ -303,6 +303,8 @@
 {"EMULEX","MD21/S2     ESDI","*", BLIST_SINGLELUN},
 {"CANON","IPUBJD","*", BLIST_SPARSELUN},
 {"nCipher","Fastness Crypto","*", BLIST_FORCELUN},
+{"DEC","HSG80","*", BLIST_FORCELUN},
+{"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN},
 {"NEC","PD-1 ODX654P","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"MATSHITA","PD-1","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN},
@@ -312,6 +314,8 @@
 {"DGC",  "DISK",      "*", BLIST_SPARSELUN}, /* Dell PV 650F (no tgt @ LUN 0) */
 {"DELL", "PV530F",    "*", BLIST_SPARSELUN}, /* Dell PV 530F */
 {"SONY", "TSL",       "*", BLIST_FORCELUN},  /* DDS3 & DDS4 autoloaders */
+{"DELL", "PERCRAID", "*", BLIST_FORCELUN},
+{"HP", "NetRAID-4M", "*", BLIST_FORCELUN},
 /*
  * Must be at end of list...
  */
@@ -798,7 +802,8 @@
   memcpy (SDpnt->rev, scsi_result + 32, 4);
 
   SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
-  SDpnt->online = TRUE;
+  if (((scsi_result[0] >> 5) & 7) == 1)  SDpnt->online = FALSE;
+  else SDpnt->online = TRUE;
   SDpnt->lockable = SDpnt->removable;
   SDpnt->changed = 0;
   SDpnt->access_count = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sd.c linux.18p8/drivers/scsi/sd.c
--- linux.vanilla/drivers/scsi/sd.c	Sun Jun 11 21:44:17 2000
+++ linux.18p8/drivers/scsi/sd.c	Sat Sep  2 23:48:15 2000
@@ -150,36 +150,43 @@
      * This is also used to lock out further access when the partition table
      * is being re-read.
      */
-
     while (rscsi_disks[target].device->busy)
         barrier();
-    if(rscsi_disks[target].device->removable) {
+
+    /*
+     * When opening removable disks, we check media...
+     * ... unless media don't matter, due to O_NONBLOCK.
+     */
+    if ( rscsi_disks[target].device->removable
+         && !(filp->f_flags & O_NONBLOCK) )
+    {
+        /*
+         * Note disk change and/or removal.
+         * Also try to read new partition table (if any).
+         */
 	check_disk_change(inode->i_rdev);
 
-	/*
-	 * If the drive is empty, just let the open fail.
-	 */
+        /*
+         * If the drive is empty, let the open fail.
+         */
 	if ( !rscsi_disks[target].ready )
-	    return -ENXIO;
+            return -ENXIO;
 
-	/*
-	 * Similarly, if the device has the write protect tab set,
-	 * have the open fail if the user expects to be able to write
-	 * to the thing.
-	 */
-	if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) )
-	    return -EROFS;
+        /*
+         * If the device has the write protect tab set,
+         * let the open fail if the user expects to be able to write.
+         */
+        if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) )
+            return -EROFS;
     }
 
     /*
-     * It is possible that the disk changing stuff resulted in the device being taken
-     * offline.  If this is the case, report this to the user, and don't pretend that
-     * the open actually succeeded.
+     * It is possible that the disk changing stuff (or something
+     * else?) resulted in the device being taken offline.
+     * If so, let the open fail.
      */
-    if( !rscsi_disks[target].device->online )
-    {
+    if ( !rscsi_disks[target].device->online )
         return -ENXIO;
-    }
 
     /*
      * See if we are requesting a non-existent partition.  Do this
@@ -1068,7 +1075,6 @@
     int retval;
     int target;
     struct inode inode;
-    int flag = 0;
 
     target =  DEVICE_NR(full_dev);
 
@@ -1120,11 +1126,11 @@
      * presence of disk in the drive. This is kept in the Scsi_Disk
      * struct and tested at open !  Daniel Roche ( dan@lectra.fr )
      */
-
     rscsi_disks[target].ready = 1;	/* FLOPTICAL */
 
     retval = rscsi_disks[target].device->changed;
-    if(!flag) rscsi_disks[target].device->changed = 0;
+    rscsi_disks[target].device->changed = 0;
+
     return retval;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/seagate.c linux.18p8/drivers/scsi/seagate.c
--- linux.vanilla/drivers/scsi/seagate.c	Sun Jun 11 21:44:17 2000
+++ linux.18p8/drivers/scsi/seagate.c	Thu Aug 31 15:34:27 2000
@@ -1708,124 +1708,16 @@
   return SCSI_RESET_WAKEUP;
 }
 
-
-int seagate_st0x_biosparam (Disk * disk, kdev_t dev, int *ip)
-{
-  unsigned char buf[256 + sizeof (Scsi_Ioctl_Command)], 
-                cmd[6], *data, *page;
-  Scsi_Ioctl_Command *sic = (Scsi_Ioctl_Command *) buf;
-  int result, formatted_sectors, total_sectors;
-  int cylinders, heads, sectors;
-  int capacity;
-
 /*
- * Only SCSI-I CCS drives and later implement the necessary mode sense
- * pages.
+ * There used to be some biosparam() code here, but the
+ * author misunderstood the purpose of this routine and
+ * tried to determine physical reality by reading mode
+ * sense pages and the like. But that yields values like
+ * 424 sectors/track, completely unusable for partition tables.
+ * (And after the translation part we may have heads > 255,
+ * equally unusable.)
+ * So, we delete all of this stuff and rely on the defaults.
  */
-
-  if (disk->device->scsi_level < 2)
-    return -1;
-
-  data = sic->data;
-
-  cmd[0] = MODE_SENSE;
-  cmd[1] = (disk->device->lun << 5) & 0xe5;
-  cmd[2] = 0x04;                        /* Read page 4, rigid disk geometry
-                                           page current values */
-  cmd[3] = 0;
-  cmd[4] = 255;
-  cmd[5] = 0;
-
-/*
- * We are transferring 0 bytes in the out direction, and expect to get back
- * 24 bytes for each mode page.
- */
-  sic->inlen = 0;
-  sic->outlen = 256;
-
-  memcpy (data, cmd, 6);
-
-  if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND,
-                                    sic)))
-  {
-/*
- * The mode page lies beyond the MODE SENSE header, with length 4, and
- * the BLOCK DESCRIPTOR, with length header[3].
- */
-    page = data + 4 + data[3];
-    heads = (int) page[5];
-    cylinders = (page[2] << 16) | (page[3] << 8) | page[4];
-
-    cmd[2] = 0x03;                      /* Read page 3, format page current
-                                           values */
-    memcpy (data, cmd, 6);
-
-    if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND,
-                                      sic)))
-    {
-      page = data + 4 + data[3];
-      sectors = (page[10] << 8) | page[11];
-/*
- * Get the total number of formatted sectors from the block descriptor,
- * so we can tell how many are being used for alternates.
- */
-      formatted_sectors = (data[4 + 1] << 16) | (data[4 + 2] << 8) 
-                          | data[4 + 3];
-
-      total_sectors = (heads * cylinders * sectors);
-
-/*
- * Adjust the real geometry by subtracting
- * (spare sectors / (heads * tracks)) cylinders from the number of cylinders.
- *
- * It appears that the CE cylinder CAN be a partial cylinder.
- */
-
-      printk ("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %d\n",
-              hostno, heads, cylinders, sectors, total_sectors,
-              formatted_sectors);
-
-      if (!heads || !sectors || !cylinders)
-        result = -1;
-      else
-        cylinders -= ((total_sectors - formatted_sectors) / (heads * sectors));
-
-/*
- * Now, we need to do a sanity check on the geometry to see if it is
- * BIOS compatible.  The maximum BIOS geometry is 1024 cylinders *
- * 256 heads * 64 sectors.
- */
-
-      if ((cylinders > 1024) || (sectors > 64))
-      {
-        /* The Seagate's seem to have some mapping.  Multiply
-           heads*sectors*cyl to get capacity.  Then start rounding down.
-         */
-        capacity = heads * sectors * cylinders;         
-      
-        /* Old MFM Drives use this, so does the Seagate */
-        sectors = 17;
-        heads = 2;
-        capacity = capacity / sectors;
-        while (cylinders > 1024)
-        {
-          heads *= 2;                   /* For some reason, they go in
-                                           multiples */
-          cylinders = capacity / heads;
-        }
-      }
-      ip[0] = heads;
-      ip[1] = sectors;
-      ip[2] = cylinders;
-/*
- * There should be an alternate mapping for things the seagate doesn't
- * understand, but I couldn't say what it is with reasonable certainty.
- */
-    }
-  }
-
-  return result;
-}
 
 #ifdef MODULE
 /* Eventually this will go into an include file, but this will be later */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/seagate.h linux.18p8/drivers/scsi/seagate.h
--- linux.vanilla/drivers/scsi/seagate.h	Fri Apr 21 23:20:05 2000
+++ linux.18p8/drivers/scsi/seagate.h	Thu Aug 31 15:34:27 2000
@@ -29,7 +29,6 @@
 			 queuecommand:   seagate_st0x_queue_command,	\
 			 abort:          seagate_st0x_abort,		\
 			 reset:          seagate_st0x_reset,		\
-			 bios_param:     seagate_st0x_biosparam,	\
 			 can_queue:      1,				\
 			 this_id:        7,				\
 			 sg_tablesize:   SG_ALL,			\
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sr_ioctl.c linux.18p8/drivers/scsi/sr_ioctl.c
--- linux.vanilla/drivers/scsi/sr_ioctl.c	Sat Sep  9 18:42:41 2000
+++ linux.18p8/drivers/scsi/sr_ioctl.c	Fri Sep 15 12:47:12 2000
@@ -314,6 +314,8 @@
     u_char  sr_cmd[10];    
     int result, target  = MINOR(cdi->dev);
     unsigned char buffer[32];
+
+    memset(sr_cmd, 0, sizeof(sr_cmd));
     
     switch (cmd) 
     {
@@ -324,10 +326,7 @@
 	sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-	sr_cmd[6] = 0;
-	sr_cmd[7] = 0;              /* MSB of length (12) */
 	sr_cmd[8] = 12;             /* LSB of length */
-	sr_cmd[9] = 0;
 	
 	result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1);
 	
@@ -346,9 +345,7 @@
           (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
 	sr_cmd[6] = tocentry->cdte_track;
-	sr_cmd[7] = 0;             /* MSB of length (12)  */
 	sr_cmd[8] = 12;            /* LSB of length */
-	sr_cmd[9] = 0;
 	
 	result = sr_do_ioctl (target, sr_cmd, buffer, 12, 0);
 	
@@ -373,9 +370,7 @@
 		sr_cmd[0] = MODE_SENSE;
 		sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
 		sr_cmd[2] = 0xe;    /* Want mode page 0xe, CDROM audio params */
-		sr_cmd[3] = 0;
 		sr_cmd[4] = 28;
-		sr_cmd[5] = 0;
 	
 		if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL)
 			return -ENOMEM;
@@ -436,9 +431,7 @@
 		sr_cmd[0] = MODE_SENSE;
 		sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
 		sr_cmd[2] = 0xe;    /* Want mode page 0xe, CDROM audio params */
-		sr_cmd[3] = 0;
 		sr_cmd[4] = 28;
-		sr_cmd[5] = 0;
 	
 		if ((buffer = (unsigned char *) scsi_malloc(512)) == NULL)
 			return -ENOMEM;
@@ -455,6 +448,20 @@
 		volctrl->channel3 = buffer[27];
 
 		scsi_free(buffer, 512);
+		break;
+	}
+
+    case CDROMPLAYTRKIND: {
+		struct cdrom_ti* ti = (struct cdrom_ti*)arg;
+
+		sr_cmd[0] = GPCMD_PLAYAUDIO_TI;
+		sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+		sr_cmd[4] = ti->cdti_trk0;
+		sr_cmd[5] = ti->cdti_ind0;
+		sr_cmd[7] = ti->cdti_trk1;
+		sr_cmd[8] = ti->cdti_ind1;
+	
+		result = sr_do_ioctl(target, sr_cmd, NULL, 255, 0);
 		break;
 	}
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/st.c linux.18p8/drivers/scsi/st.c
--- linux.vanilla/drivers/scsi/st.c	Sat Sep  9 18:42:41 2000
+++ linux.18p8/drivers/scsi/st.c	Mon Sep 11 21:20:33 2000
@@ -11,7 +11,7 @@
   Copyright 1992 - 2000 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Sat Jun 17 17:29:35 2000 by makisara@kai.makisara.local
+  Last modified: Tue Sep  5 23:17:08 2000 by makisara@kai.makisara.local
   Some small formal changes - aeb, 950809
 */
 
@@ -1459,8 +1459,11 @@
 
 		if (SCpnt->sense_buffer[2] & 0x20) { /* ILI */
 		    if (STp->block_size == 0) {
-			if (transfer <= 0)
-			    transfer = 0;
+			if (transfer < 0) {
+			    if (STps->drv_block >= 0)
+				STps->drv_block += 1;
+			    return (-ENOMEM);
+			}
 			(STp->buffer)->buffer_bytes = bytes - transfer;
 		    }
 		    else {
@@ -2932,6 +2935,8 @@
 	   i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
 	       mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
 	       mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
+	       mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
+	       mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
 	       mtc.mt_op == MTCOMPRESSION;
        }
        i = flush_buffer(inode, file, i);
@@ -3099,6 +3104,51 @@
 }
 
 
+/* The following two functions are nearly identical to scsi_init_malloc and
+   scsi_init_free. The only difference is that the GFP_DMA flag is not set
+   by default. */
+static void * st_malloc(unsigned int size, int gfp_mask)
+{
+    void * retval;
+
+    /*
+     * For buffers used by the DMA pool, we assume page aligned 
+     * structures.
+     */
+    if ((size % PAGE_SIZE) == 0) {
+	int order, a_size;
+	for (order = 0, a_size = PAGE_SIZE;
+             a_size < size; order++, a_size <<= 1)
+            ;
+	retval = (void *) __get_free_pages(gfp_mask, order);
+    } else
+	retval = kmalloc(size, gfp_mask);
+
+    if (retval)
+	memset(retval, 0, size);
+    return retval;
+}
+
+
+static void st_free(char * ptr, unsigned int size)
+{
+    /*
+     * We need this special code here because the DMA pool assumes
+     * page aligned data.  Besides, it is wasteful to allocate
+     * page sized chunks with kmalloc.
+     */
+    if ((size % PAGE_SIZE) == 0) {
+    	int order, a_size;
+
+	for (order = 0, a_size = PAGE_SIZE;
+	     a_size < size; order++, a_size <<= 1)
+	    ;
+	free_pages((unsigned long)ptr, order);
+    } else
+	kfree(ptr);
+}
+
+
 /* Try to allocate a new tape buffer */
 	static ST_buffer *
 new_tape_buffer( int from_initialization, int need_dma )
@@ -3115,7 +3165,7 @@
     priority = GFP_KERNEL;
 
   i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist);
-  tb = (ST_buffer *)scsi_init_malloc(i, priority);
+  tb = (ST_buffer *)st_malloc(i, priority);
   if (tb) {
     tb->this_size = i;
     if (need_dma)
@@ -3128,7 +3178,7 @@
 	b_size /= 2;
     for ( ; b_size >= PAGE_SIZE; b_size /= 2) {
 	tb->sg[0].address =
-	    (unsigned char *)scsi_init_malloc(b_size, priority);
+	    (unsigned char *)st_malloc(b_size, priority);
 	if (tb->sg[0].address != NULL) {
 	    tb->sg[0].alt_address = NULL;
 	    tb->sg[0].length = b_size;
@@ -3136,7 +3186,7 @@
 	}
     }
     if (tb->sg[segs].address == NULL) {
-	scsi_init_free((char *)tb, tb->this_size);
+	st_free((char *)tb, tb->this_size);
 	tb = NULL;
     }
     else {  /* Got something, continue */
@@ -3148,7 +3198,7 @@
 	for (segs=1, got=tb->sg[0].length;
 	     got < st_buffer_size && segs < ST_FIRST_SG; ) {
 	    tb->sg[segs].address =
-		(unsigned char *)scsi_init_malloc(b_size, priority);
+		(unsigned char *)st_malloc(b_size, priority);
 	    if (tb->sg[segs].address == NULL) {
 		if (st_buffer_size - got <=
 		    (ST_FIRST_SG - segs) * b_size / 2) {
@@ -3156,8 +3206,8 @@
 		    continue;
 		}
 		for (i=0; i < segs - 1; i++)
-		    scsi_init_free(tb->sg[i].address, tb->sg[i].length);
-		scsi_init_free((char *)tb, tb->this_size);
+		    st_free(tb->sg[i].address, tb->sg[i].length);
+		st_free((char *)tb, tb->this_size);
 		tb = NULL;
 		break;
 	    }
@@ -3220,7 +3270,7 @@
   for (segs=STbuffer->sg_segs, got=STbuffer->buffer_size;
        segs < max_segs && got < new_size; ) {
       STbuffer->sg[segs].address =
-	  (unsigned char *)scsi_init_malloc(b_size, priority);
+	  (unsigned char *)st_malloc(b_size, priority);
       if (STbuffer->sg[segs].address == NULL) {
 	  if (new_size - got <= (max_segs - segs) * b_size / 2) {
 	      b_size /= 2;  /* Large enough for the rest of the buffers */
@@ -3256,7 +3306,7 @@
   int i;
 
   for (i=STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
-      scsi_init_free(STbuffer->sg[i].address, STbuffer->sg[i].length);
+      st_free(STbuffer->sg[i].address, STbuffer->sg[i].length);
       STbuffer->buffer_size -= STbuffer->sg[i].length;
   }
 #if DEBUG
@@ -3489,7 +3539,7 @@
   if (st_template.dev_max > 128 / ST_NBR_MODES)
     printk(KERN_INFO "st: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
   scsi_tapes =
-    (Scsi_Tape *) scsi_init_malloc(st_template.dev_max * sizeof(Scsi_Tape),
+    (Scsi_Tape *) st_malloc(st_template.dev_max * sizeof(Scsi_Tape),
 				   GFP_ATOMIC);
   if (scsi_tapes == NULL) {
     printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n");
@@ -3506,7 +3556,7 @@
   for (i=0; i < st_template.dev_max; ++i) {
     STp = &(scsi_tapes[i]);
     STp->capacity = 0xfffff;
-    STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget),
+    STp->mt_status = (struct mtget *) st_malloc(sizeof(struct mtget),
 						       GFP_ATOMIC);
     /* Initialize status */
     memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget));
@@ -3514,12 +3564,12 @@
 
   /* Allocate the buffers */
   st_buffers =
-    (ST_buffer **) scsi_init_malloc(st_template.dev_max * sizeof(ST_buffer *),
+    (ST_buffer **) st_malloc(st_template.dev_max * sizeof(ST_buffer *),
 				    GFP_ATOMIC);
   if (st_buffers == NULL) {
     printk(KERN_ERR "Unable to allocate tape buffer pointers.\n");
     unregister_chrdev(SCSI_TAPE_MAJOR, "st");
-    scsi_init_free((char *) scsi_tapes,
+    st_free((char *) scsi_tapes,
 		   st_template.dev_max * sizeof(Scsi_Tape));
     return 1;
   }
@@ -3532,6 +3582,8 @@
     target_nbr = ST_EXTRA_DEVS;
   if (target_nbr > st_max_buffers)
     target_nbr = st_max_buffers;
+  if (target_nbr > st_template.dev_noticed)
+    target_nbr = st_template.dev_noticed;
 
   for (i=st_nbr_buffers=0; i < target_nbr; i++) {
     if (!new_tape_buffer(TRUE, TRUE)) {
@@ -3539,9 +3591,9 @@
 #if 0
 	printk(KERN_ERR "Can't continue without at least one tape buffer.\n");
 	unregister_chrdev(SCSI_TAPE_MAJOR, "st");
-	scsi_init_free((char *) st_buffers,
+	st_free((char *) st_buffers,
 		       st_template.dev_max * sizeof(ST_buffer *));
-	scsi_init_free((char *) scsi_tapes,
+	st_free((char *) scsi_tapes,
 		       st_template.dev_max * sizeof(Scsi_Tape));
 	return 1;
 #else
@@ -3608,19 +3660,19 @@
   unregister_chrdev(SCSI_TAPE_MAJOR, "st");
   st_registered--;
   if(scsi_tapes != NULL) {
-    scsi_init_free((char *) scsi_tapes,
+    st_free((char *) scsi_tapes,
 		   st_template.dev_max * sizeof(Scsi_Tape));
 
     if (st_buffers != NULL) {
       for (i=0; i < st_nbr_buffers; i++)
 	if (st_buffers[i] != NULL) {
 	  for (j=0; j < st_buffers[i]->sg_segs; j++)
-	      scsi_init_free((char *) st_buffers[i]->sg[j].address,
+	      st_free((char *) st_buffers[i]->sg[j].address,
 			     st_buffers[i]->sg[j].length);
-	  scsi_init_free((char *) st_buffers[i], st_buffers[i]->this_size);
+	  st_free((char *) st_buffers[i], st_buffers[i]->this_size);
 	}
 
-      scsi_init_free((char *) st_buffers,
+      st_free((char *) st_buffers,
 		     st_template.dev_max * sizeof(ST_buffer *));
     }
   }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sym53c8xx.c linux.18p8/drivers/scsi/sym53c8xx.c
--- linux.vanilla/drivers/scsi/sym53c8xx.c	Sat Sep  9 18:42:41 2000
+++ linux.18p8/drivers/scsi/sym53c8xx.c	Sun Sep 10 14:49:10 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-2000  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,8 +55,6 @@
 */
 
 /*
-**	July 24 1999, sym53c8xx version 1.3g
-**
 **	Supported SCSI features:
 **	    Synchronous data transfers
 **	    Wide16 SCSI BUS
@@ -64,7 +62,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 +71,10 @@
 **		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)
+**		53C897	  (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)
+**		53C1010_66(Wide,   Fast 80 Dual, on-board rom BIOS, 33/66MHz PCI)
 **
 **	Other features:
 **		Memory mapped IO
@@ -84,11 +85,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.3g"
-
-/* #define DEBUG_896R1 */
-#define SCSI_NCR_OPTIMIZE_896
-/* #define SCSI_NCR_OPTIMIZE_896_1 */
+#define SCSI_NCR_DRIVER_NAME	"sym53c8xx-1.7.1-20000726"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -111,7 +108,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>
@@ -130,15 +129,19 @@
 #include <linux/version.h>
 #include <linux/blk.h>
 
+#ifdef CONFIG_ALL_PPC
+#include <asm/prom.h>
+#endif
+
 #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)
@@ -172,6 +175,27 @@
 
 #include "sym53c8xx.h"
 
+/*
+**	Donnot compile integrity checking code for Linux-2.3.0 
+**	and above since SCSI data structures are not ready yet.
+*/
+/* #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0) */
+#if 0
+#define	SCSI_NCR_INTEGRITY_CHECKING
+#endif
+
+#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
+#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
+
+/*
+**	Hmmm... What complex some PCI-HOST bridges actually are, 
+**	despite the fact that the PCI specifications are looking 
+**	so smart and simple! ;-)
+*/
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,47)
+#define SCSI_NCR_DYNAMIC_DMA_MAPPING
+#endif
+
 /*==========================================================
 **
 **	A la VMS/CAM-3 queue management.
@@ -264,48 +288,6 @@
 
 /*==========================================================
 **
-**	On x86 architecture, write buffers management does 
-**	not reorder writes to memory. So, using compiler 
-**	optimization barriers is enough to guarantee some 
-**	ordering when the CPU is writing data accessed by 
-**	the NCR.
-**	On Alpha architecture, explicit memory barriers have 
-**	to be used.
-**	Other architectures are defaulted to mb() macro if  
-**	defined, otherwise use compiler barrier.
-**
-**==========================================================
-*/
-
-#if defined(__i386__)
-#define MEMORY_BARRIER()	barrier()
-#elif defined(__alpha__)
-#define MEMORY_BARRIER()	mb()
-#else
-#  ifdef mb
-#  define MEMORY_BARRIER()	mb()
-#  else
-#  define MEMORY_BARRIER()	barrier()
-#  endif
-#endif
-
-/*==========================================================
-**
-**	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 +313,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,53 +384,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
 
 /*
-**    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.
+**    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.
 */
-
-#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
+#if	MAX_START > PAGE_SIZE/8
+#undef	MAX_START
+#define MAX_START (PAGE_SIZE/8)
 #endif
-#endif	/* SCSI_NCR_OPTIMIZE_896 */
 
 /*
-**    Io mapped or memory mapped.
+**    The maximum number of segments a transfer is split into.
+**    We support up to 127 segments for both read and write.
 */
 
-#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
-#define NCR_IOMAPPED
-#endif
+#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
+#define	SCR_SG_SIZE	(2)
 
 /*
 **	other
@@ -472,6 +437,133 @@
 #define offsetof(t, m)	((size_t) (&((t *)0)->m))
 #endif
 
+/*
+**	Simple Wrapper to kernel PCI bus interface.
+**
+**	This wrapper allows to get rid of old kernel PCI interface 
+**	and still allows to preserve linux-2.0 compatibilty.
+**	In fact, it is mostly an incomplete emulation of the new 
+**	PCI code for pre-2.2 kernels. When kernel-2.0 support 
+**	will be dropped, we will just have to remove most of this 
+**	code.
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0)
+
+typedef struct pci_dev *pcidev_t;
+#define PCIDEV_NULL		(0)
+#define PciBusNumber(d)		(d)->bus->number
+#define PciDeviceFn(d)		(d)->devfn
+#define PciVendorId(d)		(d)->vendor
+#define PciDeviceId(d)		(d)->device
+#define PciIrqLine(d)		(d)->irq
+
+#if 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;
+}
+#else
+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) {
+#if BITS_PER_LONG > 32
+		*base |= (((u_long)pdev->base_address[index]) << 32);
+#endif
+		++index;
+	}
+	return index;
+}
+#endif
+
+#else	/* Incomplete emulation of current PCI code for pre-2.2 kernels */
+
+typedef unsigned int pcidev_t;
+#define PCIDEV_NULL		(~0u)
+#define PciBusNumber(d)		((d)>>8)
+#define PciDeviceFn(d)		((d)&0xff)
+#define __PciDev(busn, devfn)	(((busn)<<8)+(devfn))
+
+#define pci_present pcibios_present
+
+#define pci_read_config_byte(d, w, v) \
+	pcibios_read_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_read_config_word(d, w, v) \
+	pcibios_read_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_read_config_dword(d, w, v) \
+	pcibios_read_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
+
+#define pci_write_config_byte(d, w, v) \
+	pcibios_write_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_write_config_word(d, w, v) \
+	pcibios_write_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_write_config_dword(d, w, v) \
+	pcibios_write_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
+
+static pcidev_t __init
+pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev)
+{
+	static unsigned short pci_index;
+	int retv;
+	unsigned char bus_number, device_fn;
+
+	if (prev == PCIDEV_NULL)
+		pci_index = 0;
+	else
+		++pci_index;
+	retv = pcibios_find_device (vendor, device, pci_index,
+				    &bus_number, &device_fn);
+	return retv ? PCIDEV_NULL : __PciDev(bus_number, device_fn);
+}
+
+static u_short __init PciVendorId(pcidev_t dev)
+{
+	u_short vendor_id;
+	pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id);
+	return vendor_id;
+}
+
+static u_short __init PciDeviceId(pcidev_t dev)
+{
+	u_short device_id;
+	pci_read_config_word(dev, PCI_DEVICE_ID, &device_id);
+	return device_id;
+}
+
+static u_int __init PciIrqLine(pcidev_t dev)
+{
+	u_char irq;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	return irq;
+}
+
+static int __init 
+pci_get_base_address(pcidev_t dev, int offset, u_long *base)
+{
+	u_int32 tmp;
+	
+	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
+	*base = tmp;
+	offset += sizeof(u_int32);
+	if ((tmp & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+		pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
+		*base |= (((u_long)tmp) << 32);
+#endif
+		offset += sizeof(u_int32);
+	}
+	return offset;
+}
+
+#endif	/* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */
+
 /*==========================================================
 **
 **	Debugging tags
@@ -481,17 +573,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.
@@ -522,7 +612,7 @@
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
 
-spinlock_t sym53c8xx_lock;
+spinlock_t sym53c8xx_lock = SPIN_LOCK_UNLOCKED;
 #define	NCR_LOCK_DRIVER(flags)     spin_lock_irqsave(&sym53c8xx_lock, flags)
 #define	NCR_UNLOCK_DRIVER(flags)   spin_unlock_irqrestore(&sym53c8xx_lock,flags)
 
@@ -530,20 +620,11 @@
 #define	NCR_LOCK_NCB(np, flags)    spin_lock_irqsave(&np->smp_lock, flags)
 #define	NCR_UNLOCK_NCB(np, flags)  spin_unlock_irqrestore(&np->smp_lock, flags)
 
-#	if LINUX_VERSION_CODE < LinuxVersionCode(2,3,99)
-
-#	define	NCR_LOCK_SCSI_DONE(np, flags) \
+#define	NCR_LOCK_SCSI_DONE(np, flags) \
 		spin_lock_irqsave(&io_request_lock, flags)
-#	define	NCR_UNLOCK_SCSI_DONE(np, flags) \
+#define	NCR_UNLOCK_SCSI_DONE(np, flags) \
 		spin_unlock_irqrestore(&io_request_lock, flags)
 
-#	else
-
-#	define	NCR_LOCK_SCSI_DONE(np, flags)    do {;} while (0)
-#	define	NCR_UNLOCK_SCSI_DONE(np, flags)  do {;} while (0)
-
-#	endif
-
 #else
 
 #define	NCR_LOCK_DRIVER(flags)     do { save_flags(flags); cli(); } while (0)
@@ -559,17 +640,6 @@
 #endif
 
 /*
-**	Address translation
-**
-**	The driver has to provide bus memory addresses to 
-**	the script processor. Because some architectures use 
-**	different physical addressing scheme from the PCI BUS, 
-**	we use virt_to_bus() instead of virt_to_phys().
-*/
-
-#define vtobus(p)	virt_to_bus(p)
-
-/*
 **	Memory mapped IO
 **
 **	Since linux-2.1, we must use ioremap() to map the io memory space.
@@ -587,10 +657,13 @@
 
 #ifdef __sparc__
 #  include <asm/irq.h>
-#  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))
+#  if LINUX_VERSION_CODE < LinuxVersionCode(2,3,0)
+     /* ioremap/iounmap broken in 2.2.x on Sparc. -DaveM */
+#    define ioremap(base, size)		((u_long) __va(base))
+#    define iounmap(vaddr)
+#  endif
+#  define pcivtobus(p)			bus_dvma_to_mem(p)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((void *)(a), (const void *)(b), (c))
 #elif defined(__alpha__)
 #  define pcivtobus(p)			((p) & 0xfffffffful)
 #  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
@@ -600,9 +673,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 +682,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));
@@ -649,44 +718,76 @@
 **	this allocator allows simple and fast address calculations  
 **	from the SCRIPTS code. In addition, cache line alignment 
 **	is guaranteed for power of 2 cache line size.
+**	Enhanced in linux-2.3.44 to provide a memory pool per pcidev 
+**	to support dynamic dma mapping. (I would have preferred a 
+**	real bus astraction, btw).
 */
 
-#define MEMO_SHIFT	4	/* 16 bytes minimum memory chunk */
-#define MEMO_PAGE_ORDER	0	/* 1 PAGE maximum (for now (ever?) */
-typedef unsigned long addr;	/* Enough bits to bit-hack addresses */
-
-#define MEMO_FREE_UNUSED	/* Free unused pages immediately */
-
-struct m_link {
-	struct m_link *next;	/* Simple links are enough */
-};
-
-#ifndef GFP_DMA_32BIT
-#define GFP_DMA_32BIT	0	/* Will this flag ever exist */
-#endif
-
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
-#define get_pages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order)
+#define __GetFreePages(flags, order) __get_free_pages(flags, order)
 #else
-#define get_pages(order) __get_free_pages(GFP_ATOMIC | GFP_DMA_32BIT, order, 0)
+#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0)
 #endif
 
-/*
-**	Lists of available memory chunks.
-**	Starts with 16 bytes chunks until 1 PAGE chunks.
-*/
-static struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
+#define MEMO_SHIFT	4	/* 16 bytes minimum memory chunk */
+#if PAGE_SIZE >= 8192
+#define MEMO_PAGE_ORDER	0	/* 1 PAGE  maximum */
+#else
+#define MEMO_PAGE_ORDER	1	/* 2 PAGES maximum */
+#endif
+#define MEMO_FREE_UNUSED	/* Free unused pages immediately */
+#define MEMO_WARN	1
+#define MEMO_GFP_FLAGS	GFP_ATOMIC
+#define MEMO_CLUSTER_SHIFT	(PAGE_SHIFT+MEMO_PAGE_ORDER)
+#define MEMO_CLUSTER_SIZE	(1UL << MEMO_CLUSTER_SHIFT)
+#define MEMO_CLUSTER_MASK	(MEMO_CLUSTER_SIZE-1)
+
+typedef u_long m_addr_t;	/* Enough bits to bit-hack addresses */
+typedef pcidev_t m_bush_t;	/* Something that addresses DMAable */
+
+typedef struct m_link {		/* Link between free memory chunks */
+	struct m_link *next;
+} m_link_s;
+
+#ifdef	SCSI_NCR_DYNAMIC_DMA_MAPPING
+typedef struct m_vtob {		/* Virtual to Bus address translation */
+	struct m_vtob *next;
+	m_addr_t vaddr;
+	m_addr_t baddr;
+} m_vtob_s;
+#define VTOB_HASH_SHIFT		5
+#define VTOB_HASH_SIZE		(1UL << VTOB_HASH_SHIFT)
+#define VTOB_HASH_MASK		(VTOB_HASH_SIZE-1)
+#define VTOB_HASH_CODE(m)	\
+	((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK)
+#endif
+
+typedef struct m_pool {		/* Memory pool of a given kind */
+#ifdef	SCSI_NCR_DYNAMIC_DMA_MAPPING
+	m_bush_t bush;
+	m_addr_t (*getp)(struct m_pool *);
+	void (*freep)(struct m_pool *, m_addr_t);
+#define M_GETP()		mp->getp(mp)
+#define M_FREEP(p)		mp->freep(mp, p)
+#define GetPages()		__GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
+#define FreePages(p)		free_pages(p, MEMO_PAGE_ORDER)
+	int nump;
+	m_vtob_s *(vtob[VTOB_HASH_SIZE]);
+	struct m_pool *next;
+#else
+#define M_GETP()		__GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
+#define M_FREEP(p)		free_pages(p, MEMO_PAGE_ORDER)
+#endif	/* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+	struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
+} m_pool_s;
 
-/*
-**	Allocate a memory area aligned on the lowest power of 2 
-**	greater than the requested size.
-*/
-static void *__m_alloc(int size)
+static void *___m_alloc(m_pool_s *mp, int size)
 {
 	int i = 0;
 	int s = (1 << MEMO_SHIFT);
 	int j;
-	addr a ;
+	m_addr_t a;
+	m_link_s *h = mp->h;
 
 	if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
 		return 0;
@@ -699,7 +800,7 @@
 	j = i;
 	while (!h[j].next) {
 		if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
-			h[j].next = (struct m_link *)get_pages(MEMO_PAGE_ORDER);
+			h[j].next = (m_link_s *) M_GETP();
 			if (h[j].next)
 				h[j].next->next = 0;
 			break;
@@ -707,36 +808,32 @@
 		++j;
 		s <<= 1;
 	}
-	a = (addr) h[j].next;
+	a = (m_addr_t) h[j].next;
 	if (a) {
 		h[j].next = h[j].next->next;
 		while (j > i) {
 			j -= 1;
 			s >>= 1;
-			h[j].next = (struct m_link *) (a+s);
+			h[j].next = (m_link_s *) (a+s);
 			h[j].next->next = 0;
 		}
 	}
 #ifdef DEBUG
-	printk("m_alloc(%d) = %p\n", size, (void *) a);
+	printk("___m_alloc(%d) = %p\n", size, (void *) a);
 #endif
 	return (void *) a;
 }
 
-/*
-**	Free a memory area allocated using m_alloc().
-**	Coalesce buddies.
-**	Free pages that become unused if MEMO_FREE_UNUSED is defined.
-*/
-static void __m_free(void *ptr, int size)
+static void ___m_free(m_pool_s *mp, void *ptr, int size)
 {
 	int i = 0;
 	int s = (1 << MEMO_SHIFT);
-	struct m_link *q;
-	addr a, b;
+	m_link_s *q;
+	m_addr_t a, b;
+	m_link_s *h = mp->h;
 
 #ifdef DEBUG
-	printk("m_free(%p, %d)\n", ptr, size);
+	printk("___m_free(%p, %d)\n", ptr, size);
 #endif
 
 	if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
@@ -747,23 +844,23 @@
 		++i;
 	}
 
-	a = (addr) ptr;
+	a = (m_addr_t) ptr;
 
 	while (1) {
 #ifdef MEMO_FREE_UNUSED
 		if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
-			free_pages(a, MEMO_PAGE_ORDER);
+			M_FREEP(a);
 			break;
 		}
 #endif
 		b = a ^ s;
 		q = &h[i];
-		while (q->next && q->next != (struct m_link *) b) {
+		while (q->next && q->next != (m_link_s *) b) {
 			q = q->next;
 		}
 		if (!q->next) {
-			((struct m_link *) a)->next = h[i].next;
-			h[i].next = (struct m_link *) a;
+			((m_link_s *) a)->next = h[i].next;
+			h[i].next = (m_link_s *) a;
 			break;
 		}
 		q->next = q->next->next;
@@ -773,357 +870,537 @@
 	}
 }
 
-#define MEMO_WARN	1
-
-/*
-**	The memory pool is shared by all instances.
-**	We use a global SMP LOCK to be SMP safe.
-*/
-
-static void *m_calloc(int size, char *name, int uflags)
+static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags)
 {
-	u_long flags;
 	void *p;
 
-	NCR_LOCK_DRIVER(flags);
-	p = __m_alloc(size);
-	NCR_UNLOCK_DRIVER(flags);
+	p = ___m_alloc(mp, size);
 
 	if (DEBUG_FLAGS & DEBUG_ALLOC)
 		printk ("new %-10s[%4d] @%p.\n", name, size, p);
 
 	if (p)
-		memset(p, 0, size);
+		bzero(p, size);
 	else if (uflags & MEMO_WARN)
 		printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size);
 
 	return p;
 }
 
-static void m_free(void *ptr, int size, char *name)
-{
-	u_long flags;
+#define __m_calloc(mp, s, n)	__m_calloc2(mp, s, n, MEMO_WARN)
 
+static void __m_free(m_pool_s *mp, void *ptr, int size, char *name)
+{
 	if (DEBUG_FLAGS & DEBUG_ALLOC)
 		printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
 
-	NCR_LOCK_DRIVER(flags);
-	__m_free(ptr, size);
-	NCR_UNLOCK_DRIVER(flags);
+	___m_free(mp, ptr, size);
+
 }
 
 /*
-**	Transfer direction
-**
-**	Low-level scsi drivers under Linux do not receive the expected 
-**	data transfer direction from upper scsi drivers.
-**	The driver will only check actual data direction for common 
-**	scsi opcodes. Other ones may cause problem, since they may 
-**	depend on device type or be vendor specific.
-**	I would prefer to never trust the device for data direction, 
-**	but that is not possible.
-**
-**	The original driver requires the expected direction to be known.
-**	The Linux version of the driver has been enhanced in order to 
-**	be able to transfer data in the direction choosen by the target. 
-*/
+ * With pci bus iommu support, we use a default pool of unmapped memory 
+ * for memory we donnot need to DMA from/to and one pool per pcidev for 
+ * memory accessed by the PCI chip. `mp0' is the default not DMAable pool.
+ */
 
-#define XFER_IN		(1)
-#define XFER_OUT	(2)
+#ifndef	SCSI_NCR_DYNAMIC_DMA_MAPPING
 
-/*
-**	Head of list of NCR boards
-**
-**	For kernel version < 1.3.70, host is retrieved by its irq level.
-**	For later kernels, the internal host control block address 
-**	(struct ncb) is used as device id parameter of the irq stuff.
-*/
+static m_pool_s mp0;
 
-static struct Scsi_Host	*first_host = NULL;
+#else
 
+static m_addr_t ___mp0_getp(m_pool_s *mp)
+{
+	m_addr_t m = GetPages();
+	if (m)
+		++mp->nump;
+	return m;
+}
 
-/*
-**	/proc directory entry and proc_info function
-*/
+static void ___mp0_freep(m_pool_s *mp, m_addr_t m)
+{
+	FreePages(m);
+	--mp->nump;
+}
 
-static struct proc_dir_entry proc_scsi_sym53c8xx = {
-    PROC_SCSI_SYM53C8XX, 9, NAME53C8XX,
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
-};
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset,
-			int length, int hostno, int func);
-#endif
+static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep};
 
-/*
-**	Driver setup.
-**
-**	This structure is initialized from linux config options.
-**	It can be overridden at boot-up by the boot command line.
-*/
-static struct ncr_driver_setup
-	driver_setup			= SCSI_NCR_DRIVER_SETUP;
+#endif	/* SCSI_NCR_DYNAMIC_DMA_MAPPING */
 
-#ifdef	SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
-static struct ncr_driver_setup
-	driver_safe_setup __initdata	= SCSI_NCR_DRIVER_SAFE_SETUP;
-# ifdef	MODULE
-char *sym53c8xx = 0;	/* command line passed by insmod */
-#  if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
-MODULE_PARM(sym53c8xx, "s");
-#  endif
-# endif
-#endif
+static void *m_calloc(int size, char *name)
+{
+	u_long flags;
+	void *m;
+	NCR_LOCK_DRIVER(flags);
+	m = __m_calloc(&mp0, size, name);
+	NCR_UNLOCK_DRIVER(flags);
+	return m;
+}
+
+static void m_free(void *ptr, int size, char *name)
+{
+	u_long flags;
+	NCR_LOCK_DRIVER(flags);
+	__m_free(&mp0, ptr, size, name);
+	NCR_UNLOCK_DRIVER(flags);
+}
 
 /*
-**	Other Linux definitions
-*/
-#define SetScsiResult(cmd, h_sts, s_sts) \
-	cmd->result = (((h_sts) << 16) + ((s_sts) & 0x7f))
+ * DMAable pools.
+ */
 
-static void sym53c8xx_select_queue_depths(
-	struct Scsi_Host *host, struct scsi_device *devlist);
-static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
-static void sym53c8xx_timeout(unsigned long np);
+#ifndef	SCSI_NCR_DYNAMIC_DMA_MAPPING
 
-#define initverbose (driver_setup.verbose)
-#define bootverbose (np->verbose)
+/* Without pci bus iommu support, all the memory is assumed DMAable */
 
-#ifdef SCSI_NCR_NVRAM_SUPPORT
-static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21};
-#endif /* SCSI_NCR_NVRAM_SUPPORT */
+#define __m_calloc_dma(b, s, n)		m_calloc(s, n)
+#define __m_free_dma(b, p, s, n)	m_free(p, s, n)
+#define __vtobus(b, p)			virt_to_bus(p)
+
+#else
 
 /*
-**	Structures used by sym53c8xx_detect/sym53c8xx_pci_init to 
-**	transmit device configuration to the ncr_attach() function.
-*/
-typedef struct {
-	int	bus;
-	u_char	device_fn;
-	u_long	base;
-	u_long	base_2;
-	u_long	io_port;
-	int	irq;
-/* port and reg fields to use INB, OUTB macros */
-	u_long	base_io;
-	volatile struct ncr_reg	*reg;
-} ncr_slot;
+ * With pci bus iommu support, we maintain one pool per pcidev and a 
+ * hashed reverse table for virtual to bus physical address translations.
+ */
+static m_addr_t ___dma_getp(m_pool_s *mp)
+{
+	m_addr_t vp;
+	m_vtob_s *vbp;
 
-typedef struct {
-	int type;
-#define	SCSI_NCR_SYMBIOS_NVRAM	(1)
-#define	SCSI_NCR_TEKRAM_NVRAM	(2)
-#ifdef	SCSI_NCR_NVRAM_SUPPORT
-	union {
-		Symbios_nvram Symbios;
-		Tekram_nvram Tekram;
-	} data;
-#endif
-} ncr_nvram;
+	vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB");
+	if (vbp) {
+		dma_addr_t daddr;
+		vp = (m_addr_t) pci_alloc_consistent(mp->bush,
+						PAGE_SIZE<<MEMO_PAGE_ORDER,
+						&daddr);
+		if (vp) {
+			int hc = VTOB_HASH_CODE(vp);
+			vbp->vaddr = vp;
+			vbp->baddr = daddr;
+			vbp->next = mp->vtob[hc];
+			mp->vtob[hc] = vbp;
+			++mp->nump;
+			return vp;
+		}
+		else
+			__m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+	}
+	return 0;
+}
 
-/*
-**	Structure used by sym53c8xx_detect/sym53c8xx_pci_init
-**	to save data on each detected board for ncr_attach().
-*/
-typedef struct {
-	ncr_slot  slot;
-	ncr_chip  chip;
-	ncr_nvram *nvram;
-	u_char host_id;
-#ifdef	SCSI_NCR_PQS_PDS_SUPPORT
-	u_char pqs_pds;
-#endif
-	int attach_done;
-} ncr_device;
+static void ___dma_freep(m_pool_s *mp, m_addr_t m)
+{
+	m_vtob_s **vbpp, *vbp;
+	int hc = VTOB_HASH_CODE(m);
 
-/*==========================================================
-**
-**	assert ()
-**
-**==========================================================
-**
-**	modified copy from 386bsd:/usr/include/sys/assert.h
-**
-**----------------------------------------------------------
-*/
+	vbpp = &mp->vtob[hc];
+	while (*vbpp && (*vbpp)->vaddr != m)
+		vbpp = &(*vbpp)->next;
+	if (*vbpp) {
+		vbp = *vbpp;
+		*vbpp = (*vbpp)->next;
+		pci_free_consistent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER,
+				    (void *)vbp->vaddr, (dma_addr_t)vbp->baddr);
+		__m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+		--mp->nump;
+	}
+}
 
-#define	assert(expression) { \
-	if (!(expression)) { \
-		(void)panic( \
-			"assertion \"%s\" failed: file \"%s\", line %d\n", \
-			#expression, \
-			__FILE__, __LINE__); \
-	} \
+static inline m_pool_s *___get_dma_pool(m_bush_t bush)
+{
+	m_pool_s *mp;
+	for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next);
+	return mp;
 }
 
-/*==========================================================
-**
-**	Big/Little endian support.
-**
-**==========================================================
-*/
+static m_pool_s *___cre_dma_pool(m_bush_t bush)
+{
+	m_pool_s *mp;
+	mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL");
+	if (mp) {
+		bzero(mp, sizeof(*mp));
+		mp->bush = bush;
+		mp->getp = ___dma_getp;
+		mp->freep = ___dma_freep;
+		mp->next = mp0.next;
+		mp0.next = mp;
+	}
+	return mp;
+}
 
-/*
-**	If the NCR uses big endian addressing mode over the 
-**	PCI, actual io register addresses for byte and word 
-**	accesses must be changed according to lane routing.
-**	Btw, ncr_offb() and ncr_offw() macros only apply to 
-**	constants and so donnot generate bloated code.
-*/
+static void ___del_dma_pool(m_pool_s *p)
+{
+	struct m_pool **pp = &mp0.next;
 
-#if	defined(SCSI_NCR_BIG_ENDIAN)
+	while (*pp && *pp != p)
+		pp = &(*pp)->next;
+	if (*pp) {
+		*pp = (*pp)->next;
+		__m_free(&mp0, p, sizeof(*p), "MPOOL");
+	}
+}
 
-#define ncr_offb(o)	(((o)&~3)+((~((o)&3))&3))
-#define ncr_offw(o)	(((o)&~3)+((~((o)&3))&2))
+static void *__m_calloc_dma(m_bush_t bush, int size, char *name)
+{
+	u_long flags;
+	struct m_pool *mp;
+	void *m = 0;
 
-#else
+	NCR_LOCK_DRIVER(flags);
+	mp = ___get_dma_pool(bush);
+	if (!mp)
+		mp = ___cre_dma_pool(bush);
+	if (mp)
+		m = __m_calloc(mp, size, name);
+	if (mp && !mp->nump)
+		___del_dma_pool(mp);
+	NCR_UNLOCK_DRIVER(flags);
 
-#define ncr_offb(o)	(o)
-#define ncr_offw(o)	(o)
+	return m;
+}
 
-#endif
+static void __m_free_dma(m_bush_t bush, void *m, int size, char *name)
+{
+	u_long flags;
+	struct m_pool *mp;
+
+	NCR_LOCK_DRIVER(flags);
+	mp = ___get_dma_pool(bush);
+	if (mp)
+		__m_free(mp, m, size, name);
+	if (mp && !mp->nump)
+		___del_dma_pool(mp);
+	NCR_UNLOCK_DRIVER(flags);
+}
+
+static m_addr_t __vtobus(m_bush_t bush, void *m)
+{
+	u_long flags;
+	m_pool_s *mp;
+	int hc = VTOB_HASH_CODE(m);
+	m_vtob_s *vp = 0;
+	m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK;
+
+	NCR_LOCK_DRIVER(flags);
+	mp = ___get_dma_pool(bush);
+	if (mp) {
+		vp = mp->vtob[hc];
+		while (vp && (m_addr_t) vp->vaddr != a)
+			vp = vp->next;
+	}
+	NCR_UNLOCK_DRIVER(flags);
+	return vp ? vp->baddr + (((m_addr_t) m) - a) : 0;
+}
+
+#endif	/* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+#define _m_calloc_dma(np, s, n)		__m_calloc_dma(np->pdev, s, n)
+#define _m_free_dma(np, p, s, n)	__m_free_dma(np->pdev, p, s, n)
+#define m_calloc_dma(s, n)		_m_calloc_dma(np, s, n)
+#define m_free_dma(p, s, n)		_m_free_dma(np, p, s, n)
+#define _vtobus(np, p)			__vtobus(np->pdev, p)
+#define vtobus(p)			_vtobus(np, p)
 
 /*
-**	If the CPU and the NCR use same endian-ness adressing,
-**	no byte reordering is needed for script patching.
-**	Macro cpu_to_scr() is to be used for script patching.
-**	Macro scr_to_cpu() is to be used for getting a DWORD 
-**	from the script.
-*/
+ *  Deal with DMA mapping/unmapping.
+ */
 
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
 
-#define cpu_to_scr(dw)	cpu_to_le32(dw)
-#define scr_to_cpu(dw)	le32_to_cpu(dw)
+/* Linux versions prior to pci bus iommu kernel interface */
 
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+#define __unmap_scsi_data(pdev, cmd)	do {; } while (0)
+#define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer))
+#define __map_scsi_sg_data(pdev, cmd)	((cmd)->use_sg)
+#define __sync_scsi_data(pdev, cmd)	do {; } while (0)
 
-#define cpu_to_scr(dw)	cpu_to_be32(dw)
-#define scr_to_cpu(dw)	be32_to_cpu(dw)
+#define scsi_sg_dma_address(sc)		vtobus((sc)->address)
+#define scsi_sg_dma_len(sc)		((sc)->length)
 
 #else
 
-#define cpu_to_scr(dw)	(dw)
-#define scr_to_cpu(dw)	(dw)
+/* Linux version with pci bus iommu kernel interface */
 
-#endif
+/* To keep track of the dma mapping (sg/single) that has been set */
+#define __data_mapped	SCp.phase
+#define __data_mapping	SCp.have_data_in
 
-/*==========================================================
-**
-**	Access to the controller chip.
-**
-**	If NCR_IOMAPPED is defined, the driver will use 
-**	normal IOs instead of the MEMORY MAPPED IO method  
-**	recommended by PCI specifications.
-**	If all PCI bridges, host brigdes and architectures 
-**	would have been correctly designed for PCI, this 
-**	option would be useless.
-**
-**==========================================================
-*/
+static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
-/*
-**	If the CPU and the NCR use same endian-ness adressing,
-**	no byte reordering is needed for accessing chip io 
-**	registers. Functions suffixed by '_raw' are assumed 
-**	to access the chip over the PCI without doing byte 
-**	reordering. Functions suffixed by '_l2b' are 
-**	assumed to perform little-endian to big-endian byte 
-**	reordering, those suffixed by '_b2l' blah, blah,
-**	blah, ...
-*/
+	switch(cmd->__data_mapped) {
+	case 2:
+		pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+		break;
+	case 1:
+		pci_unmap_single(pdev, cmd->__data_mapping,
+				 cmd->request_bufflen, dma_dir);
+		break;
+	}
+	cmd->__data_mapped = 0;
+}
 
-#if defined(NCR_IOMAPPED)
+static u_long __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+	dma_addr_t mapping;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
-/*
-**	IO mapped only input / ouput
-*/
+	if (cmd->request_bufflen == 0)
+		return 0;
 
-#define	INB_OFF(o)		inb (np->base_io + ncr_offb(o))
-#define	OUTB_OFF(o, val)	outb ((val), np->base_io + ncr_offb(o))
+	mapping = pci_map_single(pdev, cmd->request_buffer,
+				 cmd->request_bufflen, dma_dir);
+	cmd->__data_mapped = 1;
+	cmd->__data_mapping = mapping;
 
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+	return mapping;
+}
 
-#define	INW_OFF(o)		inw_l2b (np->base_io + ncr_offw(o))
-#define	INL_OFF(o)		inl_l2b (np->base_io + (o))
+static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+	int use_sg;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
-#define	OUTW_OFF(o, val)	outw_b2l ((val), np->base_io + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_b2l ((val), np->base_io + (o))
+	if (cmd->use_sg == 0)
+		return 0;
 
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+	cmd->__data_mapped = 2;
+	cmd->__data_mapping = use_sg;
 
-#define	INW_OFF(o)		inw_b2l (np->base_io + ncr_offw(o))
-#define	INL_OFF(o)		inl_b2l (np->base_io + (o))
+	return use_sg;
+}
 
-#define	OUTW_OFF(o, val)	outw_l2b ((val), np->base_io + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_l2b ((val), np->base_io + (o))
+static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
-#else
+	switch(cmd->__data_mapped) {
+	case 2:
+		pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+		break;
+	case 1:
+		pci_dma_sync_single(pdev, cmd->__data_mapping,
+				    cmd->request_bufflen, dma_dir);
+		break;
+	}
+}
+
+#define scsi_sg_dma_address(sc)		sg_dma_address(sc)
+#define scsi_sg_dma_len(sc)		sg_dma_len(sc)
 
-#define	INW_OFF(o)		inw_raw (np->base_io + ncr_offw(o))
-#define	INL_OFF(o)		inl_raw (np->base_io + (o))
+#endif	/* SCSI_NCR_DYNAMIC_DMA_MAPPING */
 
-#define	OUTW_OFF(o, val)	outw_raw ((val), np->base_io + ncr_offw(o))
-#define	OUTL_OFF(o, val)	outl_raw ((val), np->base_io + (o))
+#define unmap_scsi_data(np, cmd)	__unmap_scsi_data(np->pdev, cmd)
+#define map_scsi_single_data(np, cmd)	__map_scsi_single_data(np->pdev, cmd)
+#define map_scsi_sg_data(np, cmd)	__map_scsi_sg_data(np->pdev, cmd)
+#define sync_scsi_data(np, cmd)		__sync_scsi_data(np->pdev, cmd)
 
-#endif	/* ENDIANs */
 
-#else	/* defined NCR_IOMAPPED */
+/*
+ * Print out some buffer.
+ */
+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");
+}
 
 /*
-**	MEMORY mapped IO input / output
+**	Transfer direction
+**
+**	Until some linux kernel version near 2.3.40, low-level scsi 
+**	drivers were not told about data transfer direction.
+**	We check the existence of this feature that has been expected 
+**	for a _long_ time by all SCSI driver developers by just 
+**	testing against the definition of SCSI_DATA_UNKNOWN. Indeed 
+**	this is a hack, but testing against a kernel version would 
+**	have been a shame. ;-)
 */
+#ifdef	SCSI_DATA_UNKNOWN
+
+#define scsi_data_direction(cmd)	(cmd->sc_data_direction)
+
+#else
+
+#define	SCSI_DATA_UNKNOWN	0
+#define	SCSI_DATA_WRITE		1
+#define	SCSI_DATA_READ		2
+#define	SCSI_DATA_NONE		3
+
+static __inline__ int scsi_data_direction(Scsi_Cmnd *cmd)
+{
+	int direction;
 
-#define INB_OFF(o)		readb((char *)np->reg + ncr_offb(o))
-#define OUTB_OFF(o, val)	writeb((val), (char *)np->reg + ncr_offb(o))
+	switch((int) cmd->cmnd[0]) {
+	case 0x08:  /*	READ(6)				08 */
+	case 0x28:  /*	READ(10)			28 */
+	case 0xA8:  /*	READ(12)			A8 */
+		direction = SCSI_DATA_READ;
+		break;
+	case 0x0A:  /*	WRITE(6)			0A */
+	case 0x2A:  /*	WRITE(10)			2A */
+	case 0xAA:  /*	WRITE(12)			AA */
+		direction = SCSI_DATA_WRITE;
+		break;
+	default:
+		direction = SCSI_DATA_UNKNOWN;
+		break;
+	}
 
-#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+	return direction;
+}
 
-#define INW_OFF(o)		readw_l2b((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_l2b((char *)np->reg + (o))
+#endif	/* SCSI_DATA_UNKNOWN */
 
-#define OUTW_OFF(o, val)	writew_b2l((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_b2l((val), (char *)np->reg + (o))
+/*
+**	Head of list of NCR boards
+**
+**	For kernel version < 1.3.70, host is retrieved by its irq level.
+**	For later kernels, the internal host control block address 
+**	(struct ncb) is used as device id parameter of the irq stuff.
+*/
 
-#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+static struct Scsi_Host	*first_host = NULL;
 
-#define INW_OFF(o)		readw_b2l((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_b2l((char *)np->reg + (o))
 
-#define OUTW_OFF(o, val)	writew_l2b((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_l2b((val), (char *)np->reg + (o))
+/*
+**	/proc directory entry and proc_info function
+*/
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+static struct proc_dir_entry proc_scsi_sym53c8xx = {
+    PROC_SCSI_SYM53C8XX, 9, NAME53C8XX,
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#endif
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
+static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset,
+			int length, int hostno, int func);
+#endif
 
-#else
+/*
+**	Driver setup.
+**
+**	This structure is initialized from linux config options.
+**	It can be overridden at boot-up by the boot command line.
+*/
+static struct ncr_driver_setup
+	driver_setup			= SCSI_NCR_DRIVER_SETUP;
 
-#define INW_OFF(o)		readw_raw((char *)np->reg + ncr_offw(o))
-#define INL_OFF(o)		readl_raw((char *)np->reg + (o))
+#ifdef	SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+static struct ncr_driver_setup
+	driver_safe_setup __initdata	= SCSI_NCR_DRIVER_SAFE_SETUP;
+# ifdef	MODULE
+char *sym53c8xx = 0;	/* command line passed by insmod */
+#  if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+MODULE_PARM(sym53c8xx, "s");
+#  endif
+# endif
+#endif
 
-#define OUTW_OFF(o, val)	writew_raw((val), (char *)np->reg + ncr_offw(o))
-#define OUTL_OFF(o, val)	writel_raw((val), (char *)np->reg + (o))
+/*
+**	Other Linux definitions
+*/
+#define SetScsiResult(cmd, h_sts, s_sts) \
+	cmd->result = (((h_sts) << 16) + ((s_sts) & 0x7f))
 
+/* We may have to remind our amnesiac SCSI layer of the reason of the abort */
+#if 0
+#define SetScsiAbortResult(cmd)	\
+	  SetScsiResult(	\
+	    cmd, 		\
+	    (cmd)->abort_reason == DID_TIME_OUT ? DID_TIME_OUT : DID_ABORT, \
+	    0xff)
+#else
+#define SetScsiAbortResult(cmd) SetScsiResult(cmd, DID_ABORT, 0xff)
 #endif
 
-#endif	/* defined NCR_IOMAPPED */
+static void sym53c8xx_select_queue_depths(
+	struct Scsi_Host *host, struct scsi_device *devlist);
+static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void sym53c8xx_timeout(unsigned long np);
+
+#define initverbose (driver_setup.verbose)
+#define bootverbose (np->verbose)
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+static u_char Tekram_sync[16] __initdata =
+	{25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10};
+#endif /* SCSI_NCR_NVRAM_SUPPORT */
 
-#define INB(r)		INB_OFF (offsetof(struct ncr_reg,r))
-#define INW(r)		INW_OFF (offsetof(struct ncr_reg,r))
-#define INL(r)		INL_OFF (offsetof(struct ncr_reg,r))
+/*
+**	Structures used by sym53c8xx_detect/sym53c8xx_pci_init to 
+**	transmit device configuration to the ncr_attach() function.
+*/
+typedef struct {
+	int	bus;
+	u_char	device_fn;
+	u_long	base;
+	u_long	base_2;
+	u_long	io_port;
+	int	irq;
+/* port and reg fields to use INB, OUTB macros */
+	u_long	base_io;
+	volatile struct ncr_reg	*reg;
+} ncr_slot;
 
-#define OUTB(r, val)	OUTB_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTW(r, val)	OUTW_OFF (offsetof(struct ncr_reg,r), (val))
-#define OUTL(r, val)	OUTL_OFF (offsetof(struct ncr_reg,r), (val))
+typedef struct {
+	int type;
+#define	SCSI_NCR_SYMBIOS_NVRAM	(1)
+#define	SCSI_NCR_TEKRAM_NVRAM	(2)
+#ifdef	SCSI_NCR_NVRAM_SUPPORT
+	union {
+		Symbios_nvram Symbios;
+		Tekram_nvram Tekram;
+	} data;
+#endif
+} ncr_nvram;
 
 /*
-**	Set bit field ON, OFF 
+**	Structure used by sym53c8xx_detect/sym53c8xx_pci_init
+**	to save data on each detected board for ncr_attach().
 */
+typedef struct {
+	pcidev_t  pdev;
+	ncr_slot  slot;
+	ncr_chip  chip;
+	ncr_nvram *nvram;
+	u_char host_id;
+#ifdef	SCSI_NCR_PQS_PDS_SUPPORT
+	u_char pqs_pds;
+#endif
+	int attach_done;
+} ncr_device;
 
-#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
-#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
-#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
-#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
-#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
-#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
+/*==========================================================
+**
+**	assert ()
+**
+**==========================================================
+**
+**	modified copy from 386bsd:/usr/include/sys/assert.h
+**
+**----------------------------------------------------------
+*/
 
+#define	assert(expression) { \
+	if (!(expression)) { \
+		(void)panic( \
+			"assertion \"%s\" failed: file \"%s\", line %d\n", \
+			#expression, \
+			__FILE__, __LINE__); \
+	} \
+}
 
 /*==========================================================
 **
@@ -1157,36 +1434,42 @@
 
 #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_DATA_OVERRUN	(22)
+#define	SIR_BAD_PHASE		(23)
+#define	SIR_MAX			(23)
 
 /*==========================================================
 **
-**	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 */
+#define XE_SODL_UNRUN   (1<<3)
+#define XE_SWIDE_OVRUN  (1<<4)
 
 /*==========================================================
 **
@@ -1196,8 +1479,10 @@
 **==========================================================
 */
 
+#define NS_NOCHANGE	(0)
 #define NS_SYNC		(1)
 #define NS_WIDE		(2)
+#define NS_PPR		(4)
 
 /*==========================================================
 **
@@ -1209,9 +1494,6 @@
 */
 
 #define	QUIRK_AUTOSAVE	(0x01)
-#define	QUIRK_NOMSG	(0x02)
-#define QUIRK_NOSYNC	(0x10)
-#define QUIRK_NOWIDE16	(0x20)
 
 /*==========================================================
 **
@@ -1273,36 +1555,14 @@
 #define UC_SETORDER	13
 #define UC_SETWIDE	14
 #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)
 #define	UF_NOSCAN	(0x04)
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-/*
-**	profiling data (per host)
-*/
-
-struct profile {
-	u_long	num_trans;
-	u_long	num_disc;
-	u_long	num_disc0;
-	u_long	num_break;
-	u_long	num_int;
-	u_long	num_fly;
-	u_long	num_kbytes;
-#if 000
-	u_long	num_br1k;
-	u_long	num_br2k;
-	u_long	num_br4k;
-	u_long	num_br8k;
-	u_long	num_brnk;
-#endif
-};
-#endif
-
 /*========================================================================
 **
 **	Declaration of structs:		target control block
@@ -1318,6 +1578,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,23 +1591,22 @@
 	u_char		inq_byte7;	/* Contains these capabilities	*/
 
 	/*----------------------------------------------------------------
-	**	Pointer to the ccb used for negotiation.
-	**	Prevent from starting a negotiation for all queued commands 
-	**	when tagged command queuing is enabled.
+	**	Some flags.
 	**----------------------------------------------------------------
 	*/
-	ccb_p   nego_cp;
+	u_char		to_reset;	/* This target is to be reset	*/
 
 	/*----------------------------------------------------------------
-	**	statistical data
+	**	Pointer to the ccb used for negotiation.
+	**	Prevent from starting a negotiation for all queued commands 
+	**	when tagged command queuing is enabled.
 	**----------------------------------------------------------------
 	*/
-	u_long	transfers;
-	u_long	bytes;
+	ccb_p   nego_cp;
 
 	/*----------------------------------------------------------------
 	**	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 +1617,15 @@
 /*1*/	u_char	quirks;
 /*2*/	u_char	widedone;
 /*3*/	u_char	wval;
+/*0*/	u_char	uval;
+
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+	u_char ic_min_sync;
+	u_char ic_max_width;
+	u_char ic_done;
+#endif
+	u_char ic_maximums_set;
+	u_char ppr_negotiation;
 
 	/*----------------------------------------------------------------
 	**	User settable limits and options.
@@ -1365,7 +1634,7 @@
 	*/
 	u_char	usrsync;
 	u_char	usrwide;
-	u_char	usrtags;
+	u_short	usrtags;
 	u_char	usrflag;
 };
 
@@ -1403,11 +1672,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 +1684,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	*/
 };
 
 /*========================================================================
@@ -1513,7 +1783,6 @@
 	**	Status fields.
 	**----------------------------------------------------------------
 	*/
-	u_char		scr_st[4];	/* script status		*/
 	u_char		status[4];	/* host status			*/
 };
 
@@ -1532,18 +1801,10 @@
 /*
 **	The status bytes are used by the host and the script processor.
 **
-**	The last four bytes (status[4]) are copied to the scratchb register
+**	The four bytes (status[4]) are copied to the scratchb register
 **	(declared as scr0..scr3 in ncr_reg.h) just after the select/reselect,
 **	and copied back just after disconnecting.
 **	Inside the script the XX_REG are used.
-**
-**	The first four bytes (scr_st[4]) are used inside the script by 
-**	"LOAD/STORE" commands.
-**	Because source and destination must have the same alignment
-**	in a DWORD, the fields HAVE to be at the choosen offsets.
-**		xerr_st		0	(0x34)	scratcha
-**		sync_st		1	(0x05)	sxfer
-**		wide_st		3	(0x03)	scntl3
 */
 
 /*
@@ -1572,23 +1833,19 @@
 #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_DATA_ST	(1u<<5)
+#define HF_AUTO_SENSE	(1u<<4)
+#define HF_DATA_IN	(1u<<5)
 #define HF_PM_TO_C	(1u<<6)
+#define HF_EXT_ERR	(1u<<7)
 
-/*
-**	First four bytes (script)
-*/
-#define  xerr_st       header.scr_st[0]
-#define  sync_st       header.scr_st[1]
-#define  nego_st       header.scr_st[2]
-#define  wide_st       header.scr_st[3]
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define HF_HINT_IARB	(1u<<7)
+#endif
 
 /*
-**	First four bytes (host)
+**	This one is stolen from QU_REG.:)
 */
-#define  xerr_status   phys.xerr_st
-#define  nego_status   phys.nego_st
+#define HF_DATA_ST	(1u<<7)
 
 /*==========================================================
 **
@@ -1620,8 +1877,10 @@
 
 	struct scr_tblsel  select;
 	struct scr_tblmove smsg  ;
+	struct scr_tblmove smsg_ext ;
 	struct scr_tblmove cmd   ;
 	struct scr_tblmove sense ;
+	struct scr_tblmove wresid;
 	struct scr_tblmove data [MAX_SCATTER];
 
 	/*
@@ -1632,13 +1891,6 @@
 
 	struct pm_ctx pm0;
 	struct pm_ctx pm1;
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	Disconnection counter
-	*/
-	u_int32 num_disc;
-#endif
 };
 
 
@@ -1663,8 +1915,10 @@
 	**----------------------------------------------------------------
 	*/
 	Scsi_Cmnd	*cmd;		/* SCSI command 		*/
-	u_long		tlimit;		/* Deadline for this job	*/
+	u_char		cdb_buf[16];	/* Copy of CDB			*/
+	u_char		sense_buf[64];
 	int		data_len;	/* Total data length		*/
+	int		segments;	/* Number of SG segments	*/
 
 	/*----------------------------------------------------------------
 	**	Message areas.
@@ -1680,21 +1934,42 @@
 	u_char		scsi_smsg2[8];
 
 	/*----------------------------------------------------------------
+	**	Miscellaneous status'.
+	**----------------------------------------------------------------
+	*/
+	u_char		nego_status;	/* Negotiation status		*/
+	u_char		xerr_status;	/* Extended error flags		*/
+	u_int32		extra_bytes;	/* Extraneous bytes transferred	*/
+
+	/*----------------------------------------------------------------
+	**	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 +2039,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_stest1, sv_scntl4;
 
 	/*----------------------------------------------------------------
 	**	Actual initial value of IO register bits used by the 
@@ -1773,7 +2048,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 +2080,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	*/
@@ -1818,11 +2093,11 @@
 	**	General controller parameters and configuration.
 	**----------------------------------------------------------------
 	*/
+	pcidev_t	pdev;
 	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		bus;		/* PCI BUS number		*/
+	u_char		device_fn;	/* PCI BUS device and function	*/
 	u_char		myaddr;		/* SCSI id of the adapter	*/
 	u_char		maxburst;	/* log base 2 of dwords burst	*/
 	u_char		maxwide;	/* Maximum transfer width	*/
@@ -1832,6 +2107,17 @@
 	u_char		multiplier;	/* Clock multiplier (1,2,4)	*/
 	u_char		clock_divn;	/* Number of clock divisors	*/
 	u_long		clock_khz;	/* SCSI clock frequency in KHz	*/
+	u_int		features;	/* Chip features map		*/
+
+	/*----------------------------------------------------------------
+	**	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.
@@ -1839,7 +2125,8 @@
 	**	SCRIPTS processor in order to start SCSI commands.
 	**----------------------------------------------------------------
 	*/
-	u_int32		*squeue;	/* Start queue			*/
+	u_long		p_squeue;	/* Start queue BUS address	*/
+	u_int32		*squeue;	/* Start queue virtual address	*/
 	u_short		squeueput;	/* Next free slot of the queue	*/
 	u_short		actccbs;	/* Number of allocated CCBs	*/
 	u_short		queuedepth;	/* Start queue depth		*/
@@ -1866,9 +2153,6 @@
 	*/
 	struct ncr_reg	regdump;	/* Register dump		*/
 	u_long		regtime;	/* Time it has been done	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	struct profile	profile;	/* Profiling data		*/
-#endif
 
 	/*----------------------------------------------------------------
 	**	Miscellaneous buffers accessed by the scripts-processor.
@@ -1876,8 +2160,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	*/
 
@@ -1889,6 +2173,7 @@
 	u_char		order;		/* Tag order to use		*/
 	u_char		verbose;	/* Verbosity for this controller*/
 	u_int32		ncr_cache;	/* Used for cache test at init.	*/
+	u_long		p_ncb;		/* BUS address of this NCB	*/
 
 	/*----------------------------------------------------------------
 	**	CCB lists and queue.
@@ -1899,6 +2184,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.
@@ -1911,7 +2214,18 @@
 	**	We use a different scatter function for 896 rev 1.
 	**----------------------------------------------------------------
 	*/
-	int (*scatter) (ccb_p, Scsi_Cmnd *);
+	int (*scatter) (ncb_p, 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.
@@ -1919,8 +2233,20 @@
 	*/
 	struct usrcmd	user;		/* Command from user		*/
 	u_char		release_stage;	/* Synchronisation stage on release  */
+
+	/*----------------------------------------------------------------
+	**	Fields that are used (primarily) for integrity check
+	**----------------------------------------------------------------
+	*/
+	unsigned char  check_integrity; /* Enable midlayer integ. check on
+					 * bus scan. */
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+	unsigned char check_integ_par;	/* Set if par or Init. Det. error
+					 * used only during integ check */
+#endif
 };
 
+#define NCB_PHYS(np, lbl)	 (np->p_ncb + offsetof(struct ncb, lbl))
 #define NCB_SCRIPT_PHYS(np,lbl)	 (np->p_script  + offsetof (struct script, lbl))
 #define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl))
 #define NCB_SCRIPTH0_PHYS(np,lbl) (np->p_scripth0+offsetof (struct scripth,lbl))
@@ -1948,87 +2274,120 @@
 
 /*
 **	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	[ 28];
 	ncrcmd  sel_no_cmd	[ 10];
 	ncrcmd  init		[  6];
 	ncrcmd  clrack		[  4];
-	ncrcmd  databreak	[  2];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  dataphase	[  4];
+	ncrcmd  disp_status	[  4];
+	ncrcmd  datai_done	[ 26];
+	ncrcmd  datao_done	[ 12];
+	ncrcmd  ign_i_w_r_msg	[  4];
+	ncrcmd  datai_phase	[  2];
+	ncrcmd  datao_phase	[  4];
+	ncrcmd  msg_in		[  2];
+	ncrcmd  msg_in2		[ 10];
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  status		[ 14];
 #else
-	ncrcmd  dataphase	[  2];
+	ncrcmd  status		[ 10];
 #endif
-	ncrcmd  status		[  8];
-	ncrcmd  msg_in		[  2];
-	ncrcmd  msg_in2		[ 16];
-	ncrcmd  msg_bad		[  6];
 	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];
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncrcmd  disconnect	[ 32];
-#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	resel_tag	[  6];
+	ncrcmd	reselected	[ 20];
+	ncrcmd	resel_scntl4	[ 30];
+#if   MAX_TASKS*4 > 512
+	ncrcmd	resel_tag	[ 18];
+#elif MAX_TASKS*4 > 256
+	ncrcmd	resel_tag	[ 12];
+#else
+	ncrcmd	resel_tag	[  8];
+#endif
 	ncrcmd	resel_go	[  6];
-	ncrcmd	resel_notag	[  4];
+	ncrcmd	resel_notag	[  2];
 	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];
+	ncrcmd  pm0_data	[ 12];
+	ncrcmd  pm0_data_out	[  6];
+	ncrcmd  pm0_data_end	[  6];
+	ncrcmd  pm1_data	[ 12];
+	ncrcmd  pm1_data_out	[  6];
+	ncrcmd  pm1_data_end	[  6];
 };
 
 /*
 **	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	no_data		[  2];
+	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		[  4];
 	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	data_ovrun	[  2];
+	ncrcmd	data_ovrun1	[ 22];
+	ncrcmd	data_ovrun2	[  8];
 	ncrcmd	abort_resel	[ 16];
 	ncrcmd	resend_ident	[  4];
 	ncrcmd	ident_break	[  4];
@@ -2036,22 +2395,34 @@
 	ncrcmd	sdata_in	[  6];
 	ncrcmd  data_io		[  2];
 	ncrcmd  data_io_com	[  8];
-	ncrcmd  data_io_out	[ 10];
-	ncrcmd	bad_identify	[ 12];
+	ncrcmd  data_io_out	[ 12];
+	ncrcmd	resel_bad_lun	[  4];
 	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];
+
+	/* WSR handling */
+#ifdef SYM_DEBUG_PM_WITH_WSR
+	ncrcmd  pm_wsr_handle	[ 44];
+#else
+	ncrcmd  pm_wsr_handle	[ 42];
+#endif
+	ncrcmd  wsr_ma_helper	[  4];
 
 	/* 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 +2459,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,30 +2469,36 @@
 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);
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-static	void	ncb_profile	(ncb_p np, ccb_p cp);
+static	void	ncr_negotiate	(ncb_p np, tcb_p tp);
+static	int	ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr);
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+static	int	ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr);
 #endif
 static	void	ncr_script_copy_and_bind
 				(ncb_p np, ncrcmd *src, ncrcmd *dst, int len);
 static  void    ncr_script_fill (struct script * scr, struct scripth * scripth);
-static	int	ncr_scatter_896R1 (ccb_p cp, Scsi_Cmnd *cmd);
-static	int	ncr_scatter	(ccb_p cp, Scsi_Cmnd *cmd);
+static	int	ncr_scatter_896R1 (ncb_p np, ccb_p cp, Scsi_Cmnd *cmd);
+static	int	ncr_scatter	(ncb_p np, 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);
 static  int     ncr_wakeup_done (ncb_p np);
 static	void	ncr_start_next_ccb (ncb_p np, lcb_p lp, int maxn);
 static	void	ncr_put_start_queue(ncb_p np, ccb_p cp);
+static	void	ncr_chip_reset	(ncb_p np);
 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);
@@ -2139,9 +2517,10 @@
 #define reset_waiting_list(np) process_waiting_list((np), DID_RESET)
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
-static  void	ncr_get_nvram		(ncr_device *devp, ncr_nvram *nvp);
-static	int	ncr_get_Symbios_nvram	(ncr_slot *np, Symbios_nvram *nvram);
-static	int	ncr_get_Tekram_nvram	(ncr_slot *np, Tekram_nvram *nvram);
+static  void	ncr_get_nvram	       (ncr_device *devp, ncr_nvram *nvp);
+static  int	sym_read_Tekram_nvram  (ncr_slot *np, u_short device_id,
+				        Tekram_nvram *nvram);
+static  int	sym_read_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram);
 #endif
 
 /*==========================================================
@@ -2221,6 +2600,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 +2632,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 +2695,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 +2720,18 @@
 	SCR_MOVE_TBL ^ SCR_MSG_OUT,
 		offsetof (struct dsb, smsg),
 }/*-------------------------< SELECT2 >----------------------*/,{
+#ifdef SCSI_NCR_IARB_SUPPORT
 	/*
-	**      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
+	**	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.
@@ -2346,9 +2755,9 @@
 	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
 		PADDR (msg_in),
 	SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)),
-		PADDR (dataphase),
+		PADDR (datao_phase),
 	SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)),
-		PADDR (dataphase),
+		PADDR (datai_phase),
 	SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
 		PADDR (status),
 	SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
@@ -2356,23 +2765,25 @@
 	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
 		PADDRH (msg_out),
 	/*
-	**      Discard one illegal phase byte, if required.
-	*/
-	SCR_LOAD_REG (scratcha, XE_BAD_PHASE),
-		0,
-	SCR_STORE_REL (scratcha, 1),
-		offsetof (struct ccb, xerr_status),
-	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)),
-		8,
+	 *  Discard as many illegal phases as 
+	 *  required and tell the C code about.
+	 */
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)),
+		16,
 	SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
 		NADDR (scratch),
-	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)),
-		8,
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)),
+		-16,
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)),
+		16,
 	SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
 		NADDR (scratch),
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)),
+		-16,
+	SCR_INT,
+		SIR_BAD_PHASE,
 	SCR_JUMP,
 		PADDR (dispatch),
-
 }/*---------------------< SEL_NO_CMD >----------------------*/,{
 	/*
 	**	The target does not switch to command 
@@ -2422,37 +2833,137 @@
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< DATABREAK >-------------------*/,{
+}/*-------------------------< DISP_STATUS >----------------------*/,{
 	/*
-	**	Jump to dispatcher.
+	**	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 device wants us to send more data,
+	 *  we must count the extra bytes.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_IN)),
+		PADDRH (data_ovrun),
+	/*
+	**	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,
+	SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
+		PADDR (disp_status),
+	/*
+	**	The SWIDE is full.
+	**	Clear this condition.
+	*/
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	/*
+         *	We are expecting an IGNORE RESIDUE message
+         *	from the device, otherwise we are in data
+         *	overrun condition. Check against MSG_IN phase.
+	*/
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		SIR_SWIDE_OVERRUN,	
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (disp_status),
+	/*
+	 *	We are in MSG_IN phase,
+	 *	Read the first byte of the message.
+	 *	If it is not an IGNORE RESIDUE message,
+	 *	signal overrun and jump to message
+	 *	processing.
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[0]),
+	SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		SIR_SWIDE_OVERRUN,	
+	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		PADDR (msg_in2),
+
+	/*
+	 *	We got the message we expected.
+	 *	Read the 2nd byte, and jump to dispatcher.
+	 */
+	SCR_CLR (SCR_ACK),
 		0,
-#endif
-	SCR_RETURN,
- 		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[1]),
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP,
+		PADDR (disp_status),
 
-}/*-------------------------< STATUS >--------------------*/,{
+}/*-------------------------< DATAO_DONE >-------------------*/,{
 	/*
-	**	get the status
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_STATUS,
-		NADDR (scratch),
+	 *  If the device wants us to send more data,
+	 *  we must count the extra bytes.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+		PADDRH (data_ovrun),
 	/*
-	**	save status to scsi_status.
-	**	mark as complete.
+	**	If the SODL is not full jump to dispatcher.
+	**	We anticipate a MSG IN phase or a STATUS phase.
 	*/
-	SCR_TO_REG (SS_REG),
+	SCR_FROM_REG (scntl2),
 		0,
-	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+	SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
+		PADDR (disp_status),
+	/*
+	**	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),
+
+}/*-------------------------< DATAI_PHASE >------------------*/,{
+	SCR_RETURN,
+		0,
+}/*-------------------------< DATAO_PHASE >------------------*/,{
+	/*
+	**	Patch for 53c1010_66 only - to allow A0 part
+	**	to operate properly in a 33MHz PCI bus.
+	**
+	** 	SCR_REG_REG(scntl4, SCR_OR, 0x0c),
+	**		0,
+	*/
+	SCR_NO_OP,
+		0,
+	SCR_RETURN,
+		0,
 }/*-------------------------< MSG_IN >--------------------*/,{
 	/*
 	**	Get the first byte of the message.
@@ -2464,7 +2975,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 +2986,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 +3063,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 +3084,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.
@@ -2626,25 +3194,6 @@
 	*/
 	SCR_WAIT_DISC,
 		0,
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	/*
-	**	Count the disconnects.
-	**	Disconnect without DATA PHASE having been 
-	**	entered are counted in bits 8..15.
-	*/
-	SCR_LOAD_REL (scratcha, 4),
-		offsetof (struct ccb, phys.num_disc),
-	SCR_FROM_REG (HF_REG),
-		0,
-	SCR_JUMPR ^ IFTRUE (MASK (HF_DATA_ST, HF_DATA_ST)),
-		8,
-	SCR_REG_REG (scratcha1, SCR_ADD, 0x01),
-		0,
-	SCR_REG_REG (scratcha, SCR_ADD, 0x01),
-		0,
-	SCR_STORE_REL (scratcha, 4),
-		offsetof (struct ccb, phys.num_disc),
-#endif
 	/*
 	**	Status is: DISCONNECTED.
 	*/
@@ -2684,7 +3233,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,32 +3305,44 @@
 		offsetof(struct tcb, wval),
 	SCR_LOAD_REL (sxfer, 1),
 		offsetof(struct tcb, sval),
+}/*-------------------------< RESEL_SCNTL4 >------------------*/,{
 	/*
-	**	If MESSAGE IN  phase as expected,
-	**	read the data directly from the BUS DATA lines.
-	**	This helps to support very old SCSI devices that 
-	**	may reselect without sending an IDENTIFY.
+	**	Write with uval value. Patch if device
+	**	does not support Ultra3.
+	**	
+	**	SCR_LOAD_REL (scntl4, 1),
+	**		offsetof(struct tcb, uval),
 	*/
+
+	SCR_NO_OP,
+		0,
+        /*
+         *  We expect MESSAGE IN phase.
+         *  If not, get help from the C code.
+         */
 	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
 		SIR_RESEL_NO_MSG_IN,
-	SCR_FROM_REG (sbdl),
-		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
+
 	/*
-	**	If message phase but not an IDENTIFY,
-	**	get some help from the C code.
-	**	Old SCSI device may behave so.
-	*/
+	 *  If IDENTIFY LUN #0, use a faster path 
+	 *  to find the LCB structure.
+	 */
+	SCR_JUMPR ^ IFTRUE (MASK (0x80, 0xbf)),
+		56,
+	/*
+	 *  If message isn't an IDENTIFY, 
+	 *  tell the C code about.
+	 */
 	SCR_INT ^ IFFALSE (MASK (0x80, 0x80)),
 		SIR_RESEL_NO_IDENTIFY,
 	/*
-	**	It is an IDENTIFY message,
-	**	Load the LUN control block address.
-	**	Avoid nasty address calculation if LUN #0.
-	*/
+	 *  It is an IDENTIFY message,
+	 *  Load the LUN control block address.
+	 */
 	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 +3351,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,15 +3370,20 @@
 		offsetof(struct lcb, b_tasktbl),
 	SCR_RETURN,
 		0,
-
 }/*-------------------------< RESEL_TAG >-------------------*/,{
 	/*
+	**	ACK the IDENTIFY or TAG previously received
+	*/
+
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
 	**	Read IDENTIFY + SIMPLE + TAG using a single MOVE.
 	**	Agressive optimization, is'nt it?
 	**	No need to test the SIMPLE TAG message, since the 
 	**	driver only supports conformant devices for tags. ;-)
 	*/
-	SCR_MOVE_ABS (3) ^ SCR_MSG_IN,
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
 		NADDR (msgin),
 	/*
 	**	Read the TAG from the SIDL.
@@ -2807,6 +3394,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.
@@ -2820,14 +3424,9 @@
 		offsetof(struct ccb, phys.header.go.restart),
 	SCR_RETURN,
 		0,
+	/* In normal situations we branch to RESEL_DSA */
 }/*-------------------------< RESEL_NOTAG >-------------------*/,{
 	/*
-	**	No tag expected.
-	**	Read an throw away the IDENTIFY.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin),
-	/*
 	**	JUMP indirectly to the restart point of the CCB.
 	*/
 	SCR_JUMP,
@@ -2859,13 +3458,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 +3471,17 @@
 0
 }/*-------------------------< DATA_IN2 >-------------------*/,{
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (datai_done),
 	SCR_JUMP,
-		PADDRH (no_data),
+		PADDRH (data_ovrun),
 }/*-------------------------< 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,32 +3490,63 @@
 0
 }/*-------------------------< DATA_OUT2 >-------------------*/,{
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (datao_done),
 	SCR_JUMP,
-		PADDRH (no_data),
+		PADDRH (data_ovrun),
 
 }/*-------------------------< PM0_DATA >--------------------*/,{
 	/*
-	**	Keep track we are executing the PM0 DATA 
-	**	mini-script.
+	**	Read our host flags to SFBR, so we will be able 
+	**	to check against the data direction we expect.
+	*/
+	SCR_FROM_REG (HF_REG),
+		0,
+	/*
+	**	Check against actual DATA PHASE.
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDR (pm0_data_out),
+	/*
+	**	Actual phase is DATA IN.
+	**	Check against expected direction.
+	*/
+	SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDRH (data_ovrun),
+	/*
+	**	Keep track we are moving data from the 
+	**	PM0 DATA mini-script.
 	*/
 	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
 		0,
 	/*
-	**	MOVE the data according to the actual 
-	**	DATA direction.
+	**	Move the data to memory.
 	*/
-	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_JUMP,
+		PADDR (pm0_data_end),
+}/*-------------------------< PM0_DATA_OUT >----------------*/,{
+	/*
+	**	Actual phase is DATA OUT.
+	**	Check against expected direction.
+	*/
+	SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDRH (data_ovrun),
+	/*
+	**	Keep track we are moving data from the 
+	**	PM0 DATA mini-script.
+	*/
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+		0,
+	/*
+	**	Move the data from memory.
+	*/
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 		offsetof (struct ccb, phys.pm0.sg),
+}/*-------------------------< PM0_DATA_END >----------------*/,{
 	/*
-	**	Clear the flag that told we were in 
-	**	the PM0 DATA mini-script.
+	**	Clear the flag that told we were moving  
+	**	data from the PM0 DATA mini-script.
 	*/
 	SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)),
 		0,
@@ -2935,26 +3561,57 @@
 		0,
 }/*-------------------------< PM1_DATA >--------------------*/,{
 	/*
-	**	Keep track we are executing the PM1 DATA 
-	**	mini-script.
+	**	Read our host flags to SFBR, so we will be able 
+	**	to check against the data direction we expect.
+	*/
+	SCR_FROM_REG (HF_REG),
+		0,
+	/*
+	**	Check against actual DATA PHASE.
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDR (pm1_data_out),
+	/*
+	**	Actual phase is DATA IN.
+	**	Check against expected direction.
+	*/
+	SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDRH (data_ovrun),
+	/*
+	**	Keep track we are moving data from the 
+	**	PM1 DATA mini-script.
 	*/
 	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
 		0,
 	/*
-	**	MOVE the data according to the actual 
-	**	DATA direction.
+	**	Move the data to memory.
 	*/
-	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_JUMP,
+		PADDR (pm1_data_end),
+}/*-------------------------< PM1_DATA_OUT >----------------*/,{
+	/*
+	**	Actual phase is DATA OUT.
+	**	Check against expected direction.
+	*/
+	SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDRH (data_ovrun),
+	/*
+	**	Keep track we are moving data from the 
+	**	PM1 DATA mini-script.
+	*/
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+		0,
+	/*
+	**	Move the data from memory.
+	*/
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 		offsetof (struct ccb, phys.pm1.sg),
+}/*-------------------------< PM1_DATA_END >----------------*/,{
 	/*
-	**	Clear the flag that told we were in 
-	**	the PM1 DATA mini-script.
+	**	Clear the flag that told we were moving  
+	**	data from the PM1 DATA mini-script.
 	*/
 	SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)),
 		0,
@@ -2970,15 +3627,76 @@
 }/*---------------------------------------------------------*/
 };
 
+
 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),
+}/*-------------------------< NO_DATA >-------------------*/,{
+	SCR_JUMP,
+		PADDRH (data_ovrun),
+}/*-----------------------< 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 +3707,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 +3729,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_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_IGN_RESIDUE >----------*/,{
+}/*-------------------------< 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 +3853,27 @@
 	SCR_JUMP,
 		PADDRH (msg_out_done),
 
-}/*-------------------------< MSG_EXT_3 >----------------*/,{
-	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_SYNC_REQ)),
-		PADDRH (msg_sdtr),
+}/*-------------------------< SDTR_RESP >-------------*/,{
 	/*
-	**	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 +3884,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),
@@ -3199,28 +3899,6 @@
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< MSG_OUT_ABORT >-------------*/,{
-	/*
-	**	After ABORT message,
-	**
-	**	expect an immediate disconnect, ...
-	*/
-	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
-		0,
-	SCR_CLR (SCR_ACK|SCR_ATN),
-		0,
-	SCR_WAIT_DISC,
-		0,
-	SCR_INT,
-		SIR_MSG_OUT_DONE,
-	/*
-	**	... and set the status to "ABORTED"
-	*/
-	SCR_LOAD_REG (HS_REG, HS_ABORTED),
-		0,
-	SCR_JUMP,
-		PADDR (complete2),
-
 }/*-------------------------< MSG_OUT >-------------------*/,{
 	/*
 	**	The target requests a message.
@@ -3228,11 +3906,6 @@
 	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
 		NADDR (msgout),
 	/*
-	**	If it was no ABORT message ...
-	*/
-	SCR_JUMP ^ IFTRUE (DATA (M_ABORT)),
-		PADDRH (msg_out_abort),
-	/*
 	**	... wait for the next phase
 	**	if it's a message out, send it again, ...
 	*/
@@ -3250,78 +3923,67 @@
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< NO_DATA >--------------------*/,{
+}/*-------------------------< DATA_OVRUN >-----------------------*/,{
 	/*
-	**	The target wants to tranfer too much data
-	**	or in the wrong direction.
-	**      Remember that in extended error.
-	*/
-	SCR_LOAD_REG (scratcha, XE_EXTRA_DATA),
-		0,
-	SCR_STORE_REL (scratcha, 1),
-		offsetof (struct ccb, xerr_status),
+	 *  Use scratcha to count the extra bytes.
+	 */
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDRH (zero),
+}/*-------------------------< DATA_OVRUN1 >----------------------*/,{
 	/*
-	**      Discard one data byte, if required.
-	*/
+	 *  The target may want to transfer too much data.
+	 *
+	 *  If phase is DATA OUT write 1 byte and count it.
+	 */
 	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-		8,
-	SCR_MOVE_ABS (1) ^ SCR_DATA_OUT,
-		NADDR (scratch),
-	SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
-		8,
-	SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
+		16,
+	SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT,
 		NADDR (scratch),
+	SCR_JUMP,
+		PADDRH (data_ovrun2),
 	/*
-	**      .. and repeat as required.
-	*/
-	SCR_CALL,
-		PADDR (databreak),
+	 *  If WSR is set, clear this condition, and 
+	 *  count this byte.
+	 */
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+		16,
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
 	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 >------------------*/,{
+		PADDRH (data_ovrun2),
+	/*
+	 *  Finally check against DATA IN phase.
+	 *  Signal data overrun to the C code 
+	 *  and jump to dispatcher if not so.
+	 *  Read 1 byte otherwise and count it.
+	 */
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)),
+		16,
+	SCR_INT,
+		SIR_DATA_OVERRUN,
 	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 >------------------*/,{
+		PADDR (dispatch),
+	SCR_CHMOV_ABS (1) ^ SCR_DATA_IN,
+		NADDR (scratch),
+}/*-------------------------< DATA_OVRUN2 >----------------------*/,{
+	/*
+	 *  Count this byte.
+	 *  This will allow to return a negative 
+	 *  residual to user.
+	 */
+	SCR_REG_REG (scratcha,  SCR_ADD,  0x01),
+		0,
+	SCR_REG_REG (scratcha1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (scratcha2, SCR_ADDC, 0),
+		0,
+	/*
+	 *  .. and repeat as required.
+	 */
 	SCR_JUMP,
-		PADDR (data_out),
-
-#endif	/* MAX_SCATTERH */
+		PADDRH (data_ovrun1),
 
 }/*-------------------------< ABORT_RESEL >----------------*/,{
 	SCR_SET (SCR_ATN),
@@ -3366,13 +4028,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 (datai_done),
 	SCR_JUMP,
-		PADDRH (no_data),
-
+		PADDRH (data_ovrun),
 }/*-------------------------< DATA_IO >--------------------*/,{
 	/*
 	**	We jump here if the data direction was unknown at the 
@@ -3409,6 +4070,8 @@
 	/*
 	**	Direction is DATA OUT.
 	*/
+	SCR_REG_REG (HF_REG, SCR_AND, (~HF_DATA_IN)),
+		0,
 	SCR_LOAD_REL  (scratcha, 4),
 		offsetof (struct ccb, phys.header.wlastp),
 	SCR_STORE_REL (scratcha, 4),
@@ -3420,29 +4083,14 @@
 	SCR_JUMP,
 		PADDRH(data_io_com),
 
-}/*-------------------------< BAD_IDENTIFY >---------------*/,{
-	/*
-	**	If message phase but not an IDENTIFY,
-	**	get some help from the C code.
-	**	Old SCSI device may behave so.
-	*/
-	SCR_JUMPR ^ IFTRUE (MASK (0x80, 0x80)),
-		16,
-	SCR_INT,
-		SIR_RESEL_NO_IDENTIFY,
-	SCR_JUMP,
-		PADDRH (abort_resel),
+}/*-------------------------< RESEL_BAD_LUN >---------------*/,{
 	/*
 	**	Message is an IDENTIFY, but lun is unknown.
-	**	Read the message, since we got it directly 
-	**	from the SCSI BUS data lines.
 	**	Signal problem to C code for logging the event.
 	**	Send a M_ABORT to clear all pending tasks.
 	*/
 	SCR_INT,
 		SIR_RESEL_BAD_LUN,
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin),
 	SCR_JUMP,
 		PADDRH (abort_resel),
 }/*-------------------------< BAD_I_T_L >------------------*/,{
@@ -3467,17 +4115,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 +4219,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 (pm_wsr_handle),
 	/*
 	**	Save the remaining byte count, the updated 
 	**	address and the return address.
@@ -3582,16 +4238,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 (pm_wsr_handle),
 	/*
 	**	Save the remaining byte count, the updated 
 	**	address and the return address.
@@ -3600,21 +4265,136 @@
 		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),
+		PADDR (dispatch),
+}/*--------------------------< PM_WSR_HANDLE >-----------------------*/,{
+	/*
+	 *  Phase mismatch handling from SCRIPT with WSR set.
+	 *  Such a condition can occur if the chip wants to 
+	 *  execute a CHMOV(size > 1) when the WSR bit is 
+	 *  set and the target changes PHASE.
+	 */
+#ifdef	SYM_DEBUG_PM_WITH_WSR
+	/*
+	 *  Some debugging may still be needed.:)
+	 */ 
+	SCR_INT,
+		SIR_PM_WITH_WSR,
+#endif
+	/*
+	 *  We must move the residual byte to memory.
+	 *
+	 *  UA contains bit 0..31 of the address to 
+	 *  move the residual byte.
+	 *  Move it to the table indirect.
+	 */
+	SCR_STORE_REL (ua, 4),
+		offsetof (struct ccb, phys.wresid.addr),
+	/*
+	 *  Increment UA (move address to next position).
+	 */
+	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,
+	/*
+	 *  Compute SCRATCHA as:
+	 *  - size to transfer = 1 byte.
+	 *  - bit 24..31 = high address bit [32...39].
+	 */
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDRH (zero),
+	SCR_REG_REG (scratcha, SCR_OR, 1),
+		0,
+	SCR_FROM_REG (rbc3),
+		0,
+	SCR_TO_REG (scratcha3),
+		0,
+	/*
+	 *  Move this value to the table indirect.
+	 */
+	SCR_STORE_REL (scratcha, 4),
+		offsetof (struct ccb, phys.wresid.size),
+	/*
+	 *  Wait for a valid phase.
+	 *  While testing with bogus QUANTUM drives, the C1010 
+	 *  sometimes raised a spurious phase mismatch with 
+	 *  WSR and the CHMOV(1) triggered another PM.
+	 *  Waiting explicitely for the PHASE seemed to avoid 
+	 *  the nested phase mismatch. Btw, this didn't happen 
+	 *  using my IBM drives.
+	 */
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		0,
+	/*
+	 *  Perform the move of the residual byte.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct ccb, phys.wresid),
+	/*
+	 *  We can now handle the phase mismatch with UA fixed.
+	 *  RBC[0..23]=0 is a special case that does not require 
+	 *  a PM context. The C code also checks against this.
+	 */
+	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,
+	/*
+	 *  RBC[0..23]=0.
+	 *  Not only we donnot need a PM context, but this would 
+	 *  lead to a bogus CHMOV(0). This condition means that 
+	 *  the residual was the last byte to move from this CHMOV.
+	 *  So, we just have to move the current data script pointer 
+	 *  (i.e. TEMP) to the SCRIPTS address following the 
+	 *  interrupted CHMOV and jump to dispatcher.
+	 */
+	SCR_STORE_ABS (ia, 4),
+		PADDRH (scratch),
+	SCR_LOAD_ABS (temp, 4),
+		PADDRH (scratch),
+	SCR_JUMP,
+		PADDR (dispatch),
+}/*--------------------------< WSR_MA_HELPER >-----------------------*/,{
+	/*
+	 *  Helper for the C code when WSR bit is set.
+	 *  Perform the move of the residual byte.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct ccb, phys.wresid),
+	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 >--------------------*/,{
@@ -3646,7 +4426,7 @@
 
 }/*-------------------------< START_RAM64 >--------------------*/,{
 	/*
-	**	Load the RAM and start for 64 bit PCI (896).
+	**	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 
@@ -3702,57 +4482,23 @@
 **==========================================================
 */
 
-__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 +4514,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 +4605,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
@@ -3908,10 +4664,11 @@
 				new = (old & ~RELOC_MASK) + np->p_scripth;
 				break;
 			case RELOC_SOFTC:
-				new = (old & ~RELOC_MASK) + vtobus(np);
+				new = (old & ~RELOC_MASK) + np->p_ncb;
 				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 +4683,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 +4751,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 +4803,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 +4812,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 +4824,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];
@@ -4072,7 +4833,7 @@
 
 	if (tn->flags & TEKRAM_SYNC_NEGO) {
 		i = tn->sync_index & 0xf;
-		tp->usrsync = i < 12 ? Tekram_sync[i] : 255;
+		tp->usrsync = Tekram_sync[i];
 	}
 
 	tp->usrwide = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0;
@@ -4090,28 +4851,48 @@
 }
 #endif /* SCSI_NCR_NVRAM_SUPPORT */
 
-__initfunc(
-static int ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
-)
+/*
+**	Save initial settings of some IO registers.
+**	Assumed to have been set by BIOS.
+*/
+static void __init ncr_save_initial_setting(ncb_p np)
 {
-	u_char	burst_max;
-	u_long	period;
-	int i;
-
-	/*
-	**	Save assumed BIOS setting
-	*/
-
 	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_stest1	= INB(nc_stest1);
+
+ 	np->sv_scntl3   = INB(nc_scntl3) & 0x07;
+ 
+ 	if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+ 	 	(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66) ){
+ 		/*
+ 		** 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;
+         }
+}
+
+/*
+**	Prepare io register values used by ncr_init() 
+**	according to selected and supported features.
+*/
+static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
+{
+	u_char	burst_max;
+	u_long	period;
+	int i;
 
 	/*
 	**	Wide ?
@@ -4139,15 +4920,35 @@
 
 	/*
 	 * 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) ||
+		(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+
+		np->rv_scntl3 = 0; 
+	}
+	else
+	{
+		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;
+
+
+	/*
+	 * Save the ultra3 register for the C1010/C1010_66
+	 */
+
+	np->rv_scntl4 = np->sv_scntl4;
 
 	/*
 	 * Minimum synchronous period factor supported by the chip.
@@ -4161,13 +4962,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.
@@ -4177,7 +4993,7 @@
 	np->maxsync = period > 2540 ? 254 : period / 10;
 
 	/*
-	**	64 bit (53C896) ?
+	**	64 bit (53C895A or 53C896) ?
 	*/
 	if (np->features & FE_64BIT)
 #ifdef SCSI_NCR_USE_64BIT_DAC
@@ -4187,8 +5003,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 +5047,14 @@
 		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->device_id == PCI_DEVICE_ID_LSI_53C1010_66 ) )
+		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.
@@ -4242,7 +5066,7 @@
 		np->rv_dmode	|= BOF;		/* Burst Opcode Fetch */
 	if (np->features & FE_ERMP)
 		np->rv_dmode	|= ERMP;	/* Enable Read Multiple */
-#ifdef SCSI_NCR_OPTIMIZE_896
+#if 1
 	if ((np->features & FE_PFEN) && !np->base2_ba)
 #else
 	if (np->features & FE_PFEN)
@@ -4252,8 +5076,13 @@
 		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->device_id != PCI_DEVICE_ID_LSI_53C1010_66) &&
+			(np->features & FE_DFS))
 		np->rv_ctest5	|= DFS;		/* Dma Fifo Size */
+						/* C1010/C1010_66 always large fifo */
 
 	/*
 	**	Select some other
@@ -4299,28 +5128,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:	/* 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;
-		case 2:
-			np->rv_stest2	|= 0x20;
-			break;
-		case 1:
-			np->rv_stest2	|= (np->sv_stest2 & 0x20);
-			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 +5225,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 +5240,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 +5267,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 +5297,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;
@@ -4483,7 +5332,7 @@
 		int sync, j;
 		struct Tekram_target *tn = &nvram->target[i];
 		j = tn->sync_index & 0xf;
-		sync = j < 12 ? Tekram_sync[j] : 255;
+		sync = Tekram_sync[j];
 		printk(KERN_DEBUG "%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
 		ncr_name(np), i,
 		(tn->flags & TEKRAM_PARITY_CHECK)	? " PARITY"	: "",
@@ -4507,9 +5356,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;
@@ -4518,16 +5366,21 @@
 	ncr_nvram *nvram = device->nvram;
 	int i;
 
+	printk(KERN_INFO NAME53C "%s-%d: rev 0x%x on pci bus %d device %d function %d "
+#ifdef __sparc__
+		"irq %s\n",
+#else
+		"irq %d\n",
+#endif
+		device->chip.name, unit, device->chip.revision_id,
+		device->slot.bus, (device->slot.device_fn & 0xf8) >> 3,
+		device->slot.device_fn & 7,
 #ifdef __sparc__
-printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=0x%x\n",
-	device->chip.name, unit, device->chip.revision_id, device->slot.base,
-	device->slot.io_port, device->slot.irq);
-#else
-printk(KERN_INFO NAME53C "%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
-	device->chip.name, unit, device->chip.revision_id, device->slot.base,
-	device->slot.io_port, device->slot.irq);
+		__irq_itoa(device->slot.irq));
+#else
+		device->slot.irq);
 #endif
- 
+
 	/*
 	**	Allocate host_data structure
 	*/
@@ -4538,10 +5391,12 @@
 	/*
 	**	Allocate the host control block.
 	*/
-	np = m_calloc(sizeof(struct ncb), "NCB", MEMO_WARN);
+	np = __m_calloc_dma(device->pdev, sizeof(struct ncb), "NCB");
 	if (!np)
 		goto attach_error;
 	NCR_INIT_LOCK_NCB(np);
+	np->pdev  = device->pdev;
+	np->p_ncb = vtobus(np);
 	host_data->ncb = np;
 
 	/*
@@ -4553,8 +5408,8 @@
 	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->bus		= device->slot.bus;
+	np->device_fn	= device->slot.device_fn;
 	np->features	= device->chip.features;
 	np->clock_divn	= device->chip.nr_divisor;
 	np->maxoffs	= device->chip.offset_max;
@@ -4565,22 +5420,23 @@
 	**	Allocate the start queue.
 	*/
 	np->squeue = (ncrcmd *)
-		m_calloc(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE", MEMO_WARN);
+		m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "SQUEUE");
 	if (!np->squeue)
 		goto attach_error;
+	np->p_squeue = vtobus(np->squeue);
 
 	/*
 	**	Allocate the done queue.
 	*/
 	np->dqueue = (ncrcmd *)
-		m_calloc(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE", MEMO_WARN);
+		m_calloc_dma(sizeof(ncrcmd)*(MAX_START*2), "DQUEUE");
 	if (!np->dqueue)
 		goto attach_error;
 
 	/*
 	**	Allocate the target bus address array.
 	*/
-	np->targtbl = (u_int32 *) m_calloc(256, "TARGTBL", MEMO_WARN);
+	np->targtbl = (u_int32 *) m_calloc_dma(256, "TARGTBL");
 	if (!np->targtbl)
 		goto attach_error;
 
@@ -4588,11 +5444,11 @@
 	**	Allocate SCRIPTS areas
 	*/
 	np->script0	= (struct script *) 
-		m_calloc(sizeof(struct script),  "SCRIPT",  MEMO_WARN);
+		m_calloc_dma(sizeof(struct script),  "SCRIPT");
 	if (!np->script0)
 		goto attach_error;
 	np->scripth0	= (struct scripth *)
-		m_calloc(sizeof(struct scripth), "SCRIPTH", MEMO_WARN);
+		m_calloc_dma(sizeof(struct scripth), "SCRIPTH");
 	if (!np->scripth0)
 		goto attach_error;
 
@@ -4622,7 +5478,7 @@
 	np->base_ws	= (np->features & FE_IO256)? 256 : 128;
 	np->base2_ba	= (np->features & FE_RAM)? device->slot.base_2 : 0;
 
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	np->base_va = remap_pci_mem(np->base_ba, np->base_ws);
 	if (!np->base_va) {
 		printk(KERN_ERR "%s: can't map PCI MMIO region\n",ncr_name(np));
@@ -4639,7 +5495,15 @@
 
 	np->reg = (struct ncr_reg *) np->base_va;
 
-#endif /* !defined NCR_IOMAPPED */
+#endif /* !defined SCSI_NCR_IOMAPPED */
+
+	/*
+	**	If on-chip RAM is used, make sure SCRIPTS isn't too large.
+	*/
+	if (np->base2_ba && sizeof(struct script) > 4096) {
+		printk(KERN_ERR "%s: script too large.\n", ncr_name(np));
+		goto attach_error;
+	}
 
 	/*
 	**	Try to map the controller chip into iospace.
@@ -4672,14 +5536,69 @@
 	}
 #endif
 
+ 	/*
+	**	Save setting of some IO registers, so we will 
+	**	be able to probe specific implementations.
+	*/
+	ncr_save_initial_setting (np);
+
+	/*
+	**	Reset the chip now, since it has been reported 
+	**	that SCSI clock calibration may not work properly 
+	**	if the chip is currently active.
+	*/
+	ncr_chip_reset (np);
+
 	/*
 	**	Do chip dependent initialization.
 	*/
-	if (np->base2_ba && sizeof(struct script) > 4096) {
-		printk(KERN_ERR "%s: script too large.\n", ncr_name(np));
+	(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;
 	}
-	(void) ncr_prepare_setting(np, nvram);
 
 	/*
 	**	Patch script to physical addresses
@@ -4722,6 +5641,15 @@
 	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->resel_scntl4[0] = cpu_to_scr(SCR_LOAD_REL (scntl4, 1));
+		np->script0->resel_scntl4[1] = cpu_to_scr(offsetof(struct tcb, uval));
+	}
+
+
 #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));
@@ -4733,40 +5661,41 @@
 	*/
 	np->idletask.start	= cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
 	np->idletask.restart	= cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l));
-	np->p_idletask		= vtobus(&np->idletask);
+	np->p_idletask		= NCB_PHYS(np, idletask);
 
 	np->notask.start	= cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
 	np->notask.restart	= cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l));
-	np->p_notask		= vtobus(&np->notask);
+	np->p_notask		= NCB_PHYS(np, notask);
 
 	np->bad_i_t_l.start	= cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
 	np->bad_i_t_l.restart	= cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l));
-	np->p_bad_i_t_l		= vtobus(&np->bad_i_t_l);
+	np->p_bad_i_t_l		= NCB_PHYS(np, bad_i_t_l);
 
 	np->bad_i_t_l_q.start	= cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
 	np->bad_i_t_l_q.restart	= cpu_to_scr(NCB_SCRIPTH_PHYS (np,bad_i_t_l_q));
-	np->p_bad_i_t_l_q	= vtobus(&np->bad_i_t_l_q);
+	np->p_bad_i_t_l_q	= NCB_PHYS(np, bad_i_t_l_q);
 
 	/*
 	**	Allocate and prepare the bad lun table.
 	*/
-	np->badluntbl = m_calloc(256, "BADLUNTBL", MEMO_WARN);
+	np->badluntbl = m_calloc_dma(256, "BADLUNTBL");
 	if (!np->badluntbl)
 		goto attach_error;
 
 	assert (offsetof(struct lcb, resel_task) == 0);
-	np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_identify));
+	np->resel_badlun = cpu_to_scr(NCB_SCRIPTH_PHYS(np, resel_bad_lun));
 
 	for (i = 0 ; i < 64 ; i++)
-		np->badluntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun));
+		np->badluntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun));
 
 	/*
 	**	Prepare the target bus address array.
 	*/
 	np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl));
 	for (i = 0 ; i < MAX_TARGET ; i++) {
-		np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i]));
+		np->targtbl[i] = cpu_to_scr(NCB_PHYS(np, target[i]));
 		np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl));
+		np->target[i].b_lun0   = cpu_to_scr(NCB_PHYS(np, resel_badlun));
 	}
 
 	/*
@@ -4783,20 +5712,43 @@
 	}
 
 	/*
+	**	Patch the script to provide an extra clock cycle on
+	**	data out phase - 53C1010_66MHz part only.
+	*/
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66){
+		np->script0->datao_phase[0] =
+				cpu_to_scr(SCR_REG_REG(scntl4, SCR_OR, 0x0c));
+	}
+
+#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.
 	*/
 	if (np->device_id == PCI_DEVICE_ID_NCR_53C896 &&
 	    np->revision_id <= 0x1 && (np->features & FE_NOPM)) {
 		np->scatter = ncr_scatter_896R1;
-#ifndef SCSI_NCR_PROFILE_SUPPORT
-#define XXX	0
-#else
-#define XXX	3
-#endif
-		np->script0->dataphase[XXX] = cpu_to_scr(SCR_JUMP);
-		np->script0->dataphase[XXX+1] = 
+		np->script0->datai_phase[0] = cpu_to_scr(SCR_JUMP);
+		np->script0->datai_phase[1] = 
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj));
+		np->script0->datao_phase[0] = cpu_to_scr(SCR_JUMP);
+		np->script0->datao_phase[1] = 
 				cpu_to_scr(NCB_SCRIPTH_PHYS (np, tweak_pmj));
-#undef XXX
 	}
 	else
 #ifdef DEBUG_896R1
@@ -4810,10 +5762,11 @@
 	**	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);
-	OUTB (nc_istat, 0);
+	ncr_chip_reset(np);
 
 	/*
 	**	Now check the cache handling of the pci chipset.
@@ -4826,14 +5779,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);
@@ -4896,17 +5855,37 @@
 	instance->this_id	= np->myaddr;
 	instance->max_id	= np->maxwide ? 16 : 8;
 	instance->max_lun	= MAX_LUN;
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,29)
+	instance->base		= (unsigned long) np->reg;
+#else
 	instance->base		= (char *) np->reg;
 #endif
+#endif
 	instance->irq		= np->irq;
 	instance->unique_id	= np->base_io;
 	instance->io_port	= np->base_io;
 	instance->n_io_port	= np->base_ws;
 	instance->dma_channel	= 0;
-	instance->select_queue_depths = sym53c8xx_select_queue_depths;
+	instance->cmd_per_lun	= MAX_TAGS;
+	instance->can_queue	= (MAX_START-4);
 
-	NCR_UNLOCK_NCB(np, flags);
+	np->check_integrity       = 0;
+
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+	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
+#endif
+	
+	instance->select_queue_depths = sym53c8xx_select_queue_depths;
+
+	NCR_UNLOCK_NCB(np, flags);
 
 	/*
 	**	Now let the generic SCSI driver
@@ -4946,21 +5925,21 @@
 		unmap_pci_mem(np->base2_va, np->base2_ws);
 #endif
 	if (np->scripth0)
-		m_free(np->scripth0, sizeof(struct scripth), "SCRIPTH");
+		m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH");
 	if (np->script0)
-		m_free(np->script0, sizeof(struct script), "SCRIPT");
+		m_free_dma(np->script0, sizeof(struct script), "SCRIPT");
 	if (np->squeue)
-		m_free(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE");
+		m_free_dma(np->squeue, sizeof(ncrcmd)*(MAX_START*2), "SQUEUE");
 	if (np->dqueue)
-		m_free(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE");
+		m_free_dma(np->dqueue, sizeof(ncrcmd)*(MAX_START*2),"DQUEUE");
 
 	while ((cp = np->ccbc) != NULL) {
 		np->ccbc = cp->link_ccb;
-		m_free(cp, sizeof(*cp), "CCB");
+		m_free_dma(cp, sizeof(*cp), "CCB");
 	}
 
 	if (np->badluntbl)
-		m_free(np->badluntbl, 256,"BADLUNTBL");
+		m_free_dma(np->badluntbl, 256,"BADLUNTBL");
 
 	for (target = 0; target < MAX_TARGET ; target++) {
 		tp = &np->target[target];
@@ -4969,16 +5948,23 @@
 			if (!lp)
 				continue;
 			if (lp->tasktbl != &lp->tasktbl_0)
-				m_free(lp->tasktbl, 256, "TASKTBL");
-			m_free(lp, sizeof(*lp), "LCB");
+				m_free_dma(lp->tasktbl, MAX_TASKS*4, "TASKTBL");
+			if (lp->cb_tags)
+				m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS");
+			m_free_dma(lp, sizeof(*lp), "LCB");
 		}
 #if MAX_LUN > 1
 		if (tp->lmp)
 			m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP");
+		if (tp->luntbl)
+			m_free_dma(tp->luntbl, 256, "LUNTBL");
 #endif 
 	}
 
-	m_free(np, sizeof(*np), "NCB");
+	if (np->targtbl)
+		m_free_dma(np->targtbl, 256, "TARGTBL");
+
+	m_free_dma(np, sizeof(*np), "NCB");
 }
 
 
@@ -5002,6 +5988,7 @@
 */
 static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd)
 {
+	unmap_scsi_data(np, cmd);
 	cmd->host_scribble = (char *) np->done_list;
 	np->done_list = cmd;
 }
@@ -5017,6 +6004,472 @@
 	}
 }
 
+/*==========================================================
+**
+**
+**	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.
+**
+**==========================================================
+*/
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+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 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;
+			
+
+			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;
+
+			/*
+			 * Enable PPR negotiation - only if Ultra3 support
+			 * is accessible.
+			 */
+
+#if 0
+			if (tp->ic_max_width && (tp->ic_min_sync != 255 ))
+				tp->ppr_negotiation = 1;
+#endif
+			tp->ppr_negotiation = 0;
+			if (np->features & FE_ULTRA3) {
+			    if (tp->ic_max_width && (tp->ic_min_sync == 0x09))
+				tp->ppr_negotiation = 1;
+			}
+
+			if (!tp->ppr_negotiation)
+				cmd->ic_nego &= ~NS_PPR;
+		}
+
+		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;
+		}
+
+		/* 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;
+		}
+
+		/*
+		 * Always check the PPR nego. flag bit if ppr_negotiation
+		 * is set.  If the ic_nego PPR bit is clear,
+		 * there must have been a fallback. Do only
+		 * WDTR / SDTR in the future.
+		 */
+		if ((tp->ppr_negotiation) && (!(cmd->ic_nego & NS_PPR)))
+			tp->ppr_negotiation = 0;
+
+		/* 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;
+
+		case 1: /* nego. to maximum */
+			new_period  = tp->maxoffs?tp->ic_min_sync:0;
+			new_offset  = tp->maxoffs;
+			break;
+
+		case 0:	/* nego to async */
+		default:
+			new_period = 0;
+			new_offset = 0;
+			break;
+		};
+		
+
+		nego = NS_NOCHANGE;
+		if (tp->ppr_negotiation) { 
+			u_char options_byte = 0;
+
+			/*
+			** 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/1010_66 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;
+}
+#endif	/* SCSI_NCR_INTEGRITY_CHECKING */
+
+/*==========================================================
+**
+**
+**	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;
+
+	if (!np->check_integrity) {
+		/* If integrity checking disabled, enable PPR messaging
+		 * if device supports wide, sync and ultra 3
+		 */
+		if (tp->ppr_negotiation == 1) /* PPR message successful */
+			tp->ppr_negotiation = 2;
+
+		if ((tp->inq_done) && (!tp->ic_maximums_set)) {
+			tp->ic_maximums_set = 1;
+
+			/*
+			 * Issue PPR only if board is capable
+			 * and set-up for Ultra3 transfers.
+			 */
+			tp->ppr_negotiation = 0;
+			if ( (np->features & FE_ULTRA3) &&
+				(tp->usrwide) && (tp->maxoffs) &&
+				(tp->minsync == 0x09) )
+					tp->ppr_negotiation = 1;
+		}
+	}
+
+	if (tp->inq_done) {
+		/*
+		 * Get the current width, offset and period
+		 */
+		ncr_get_xfer_info( np, tp, &factor,
+						&offset, &width);
+
+		/*
+		**	negotiate wide transfers ?
+		*/
+
+		if (!tp->widedone) {
+			if (tp->inq_byte7 & INQ7_WIDE16) {
+				if (tp->ppr_negotiation)
+					nego = NS_PPR;
+				else
+					nego = NS_WIDE;
+
+				width = tp->usrwide;
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+				if (tp->ic_done)
+		       			 width &= tp->ic_max_width;
+#endif
+			} else
+				tp->widedone=1;
+
+		};
+
+		/*
+		**	negotiate synchronous transfers?
+		*/
+
+		if ((nego != NS_WIDE) && !tp->period) {
+			if (tp->inq_byte7 & INQ7_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;
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+			 	    if ((tp->ic_done) && 
+						(factor < tp->ic_min_sync))
+		       			 factor = tp->ic_min_sync;
+#endif
+				}
+
+			} 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 is ST mode, 62 if DT mode
+		*/
+		last_byte = 0;
+		if ( (factor==9) && offset) {
+			if (!width) {
+				factor = 0x0A;
+				offset &= 0x1f;
+			}
+			else 
+				last_byte = 0x02;
+		}
+		else if (factor > 0x09)
+			offset &= 0x1f;
+
+		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:
+		/*
+		** Never negotiate faster than Ultra 2 (25ns periods)
+		*/
+		if (offset && (factor < 0x0A)) {
+			factor = 0x0A;
+			tp->minsync = 0x0A;
+		}
+
+		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;
+}
 
 /*==========================================================
 **
@@ -5034,9 +6487,8 @@
 	lcb_p lp		      = ncr_lp(np, tp, cmd->lun);
 	ccb_p cp;
 
-	int	segments;
-	u_char	nego, idmsg, *msgptr;
-	u_int  msglen;
+	u_char	idmsg, *msgptr;
+	u_int   msglen;
 	int	direction;
 	u_int32	lastp, goalp;
 
@@ -5081,9 +6533,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))) {
@@ -5105,56 +6558,6 @@
 	}
 #endif
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	cp->phys.num_disc = 0;
-#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, cp->target);
-				printk ("target 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
@@ -5178,16 +6581,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 +6609,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,102 +6631,130 @@
 	**----------------------------------------------------
 	*/
 
-	segments = np->scatter (cp, cp->cmd);
-
-	if (segments < 0) {
-		ncr_free_ccb(np, cp);
-		return(DID_ERROR);
+	direction = scsi_data_direction(cmd);
+	if (direction != SCSI_DATA_NONE) {
+		cp->segments = np->scatter (np, cp, cp->cmd);
+		if (cp->segments < 0) {
+			ncr_free_ccb(np, cp);
+			return(DID_ERROR);
+		}
+	}
+	else {
+		cp->data_len = 0;
+		cp->segments = 0;
 	}
 
-	/*----------------------------------------------------
+	/*---------------------------------------------------
 	**
-	**	Determine xfer direction.
+	**	negotiation required?
 	**
-	**----------------------------------------------------
+	**	(nego_status is filled by ncr_prepare_nego())
+	**
+	**---------------------------------------------------
 	*/
-	if (!cp->data_len)
-		direction = 0;
-	else {
-		switch((int) cmd->cmnd[0]) {
-		case 0x08:  /*	READ(6)				08 */
-		case 0x28:  /*	READ(10)			28 */
-		case 0xA8:  /*	READ(12)			A8 */
-			direction = XFER_IN;
-			break;
-		case 0x0A:  /*	WRITE(6)			0A */
-		case 0x2A:  /*	WRITE(10)			2A */
-		case 0xAA:  /*	WRITE(12)			AA */
-			direction = XFER_OUT;
-			break;
-		default:
-			direction = (XFER_IN|XFER_OUT);
-			break;
+
+	cp->nego_status = 0;
+
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+	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);
+        }
+#else
+	if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) {
+		msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
 	}
+#endif	/* SCSI_NCR_INTEGRITY_CHECKING */
+
 
 	/*----------------------------------------------------
 	**
-	**	Set the DATA POINTER.
+	**	Determine xfer direction.
 	**
 	**----------------------------------------------------
 	*/
+	if (!cp->data_len)
+		direction = SCSI_DATA_NONE;
 
 	/*
-	**	Default to no data transfer.
+	**	If data direction is UNKNOWN, speculate DATA_READ 
+	**	but prepare alternate pointers for WRITE in case 
+	**	of our speculation will be just wrong.
+	**	SCRIPTS will swap values if needed.
 	*/
-	lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data);
+	switch(direction) {
+	case SCSI_DATA_UNKNOWN:
+	case SCSI_DATA_WRITE:
+		goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
+		lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4));
+		if (direction != SCSI_DATA_UNKNOWN)
+			break;
+		cp->phys.header.wgoalp	= cpu_to_scr(goalp);
+		cp->phys.header.wlastp	= cpu_to_scr(lastp);
+		/* fall through */
+	case SCSI_DATA_READ:
+		cp->host_flags |= HF_DATA_IN;
+		goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
+		lastp = goalp - 8 - (cp->segments * (SCR_SG_SIZE*4));
+		break;
+	default:
+	case SCSI_DATA_NONE:
+		lastp = goalp = NCB_SCRIPTH_PHYS (np, no_data);
+		break;
+	}
 
 	/*
-	**	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 
-		**	if target decision will be data out.
-		*/
-		if (direction & XFER_IN) {
-			cp->phys.header.wgoalp	= cpu_to_scr(goalp);
-			cp->phys.header.wlastp	= cpu_to_scr(lastp);
-		}
-	}
-
-	/*
-	**	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
-	}
-
-	/*
-	**	Set all pointers values needed by SCRIPTS.
-	**	If direction is unknown, start at data_io.
+	**	Set all pointers values needed by SCRIPTS.
+	**	If direction is unknown, start at data_io.
 	*/
 	cp->phys.header.lastp = cpu_to_scr(lastp);
 	cp->phys.header.goalp = cpu_to_scr(goalp);
 
-	if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT))
+	if (direction == SCSI_DATA_UNKNOWN)
 		cp->phys.header.savep = 
 			cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io));
 	else
@@ -5354,8 +6763,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 +6793,35 @@
 	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);
+	memcpy(cp->cdb_buf, cmd->cmnd, MIN(cmd->cmd_len, sizeof(cp->cdb_buf)));
+	cp->phys.cmd.addr	= cpu_to_scr(CCB_PHYS (cp, cdb_buf[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->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 +6834,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 +6883,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 +6922,7 @@
 	**	Wake it up.
 	*/
 	MEMORY_BARRIER();
-	OUTB (nc_istat, SIGP);
+	OUTB (nc_istat, SIGP|np->istat_sem);
 }
 
 
@@ -5506,6 +6939,13 @@
 **==========================================================
 */
 
+static void ncr_chip_reset (ncb_p np)
+{
+	OUTB (nc_istat, SRST);
+	UDELAY (10);
+	OUTB (nc_istat, 0);
+}
+
 static void ncr_soft_reset(ncb_p np)
 {
 	u_char istat;
@@ -5527,16 +6967,13 @@
 	if (!i)
 		printk("%s: unable to abort current chip operation.\n",
 			ncr_name(np));
-	OUTB (nc_istat, SRST);
-	UDELAY(10);
-	OUTB (nc_istat, 0);
+	ncr_chip_reset(np);
 }
 
 /*==========================================================
 **
 **
 **	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 +6983,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, "
@@ -5584,11 +7019,12 @@
 	**	We are expecting RESET to be TRUE and other signals to be 
 	**	FALSE.
 	*/
-	term =	INB(nc_sstat0);				/* rst, sdp0 */
-	term =	((term & 2) << 7) + ((term & 1) << 16);
-	term |= ((INB(nc_sstat2) & 0x01) << 25) |	/* sdp1 */
-		(INW(nc_sbdl) << 9) |			/* d15-0 */
-		INB(nc_sbcl);	/* req, ack, bsy, sel, atn, msg, cd, io */
+	term =	INB(nc_sstat0);
+	term =	((term & 2) << 7) + ((term & 1) << 17);	/* rst sdp0 */
+	term |= ((INB(nc_sstat2) & 0x01) << 26) |	/* sdp1     */
+		((INW(nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */
+		((INW(nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
+		INB(nc_sbcl);	/* req ack bsy sel atn msg cd io    */
 
 	if (!(np->features & FE_WIDE))
 		term &= 0x3ffff;
@@ -5690,14 +7126,12 @@
 {
 /*	Scsi_Device        *device    = cmd->device; */
 	ccb_p cp;
-	int found;
-	int retv;
 
 /*
  * First, look for the scsi command in the waiting list
  */
 	if (remove_from_waiting_list(np, cmd)) {
-		SetScsiResult(cmd, DID_ABORT, 0);
+		SetScsiAbortResult(cmd);
 		ncr_queue_done_cmd(np, cmd);
 		return SCSI_ABORT_SUCCESS;
 	}
@@ -5705,58 +7139,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->to_abort = 1;
 
-	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;
-
-	}
+	/*
+	**	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;
 }
 
 /*==========================================================
@@ -5795,9 +7212,7 @@
 */
 
 	printk("%s: resetting chip\n", ncr_name(np));
-	OUTB (nc_istat,  SRST);
-	UDELAY (100);
-	OUTB (nc_istat,  0   );
+	ncr_chip_reset(np);
 
 /*
 **	Restore bios setting for automatic clock detection.
@@ -5843,11 +7258,8 @@
 		return;
 
 	/*
-	**	Gather profiling data
+	**	Print some debugging info.
 	*/
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	ncb_profile (np, cp);
-#endif
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
 		printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp,
@@ -5871,41 +7283,56 @@
 	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->xerr_status ||
+		    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->xerr_status & XE_SODL_UNRUN) {
+			PRINT_ADDR(cmd);
+			printk ("ODD transfer in DATA OUT phase.\n");
+		}
+		if (cp->xerr_status & XE_SWIDE_OVRUN){
+			PRINT_ADDR(cmd);
+			printk ("ODD transfer in DATA IN phase.\n");
+		}
+
 		if (cp->host_status==HS_COMPLETE)
 			cp->host_status = HS_FAIL;
 	}
@@ -5914,13 +7341,22 @@
 	**	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);
 		}
 	}
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,99)
+	/*
+	**	Move residual byte count to user structure.
+	*/
+	cmd->resid = cp->resid;
+#endif
 	/*
 	**	Check the status.
 	*/
@@ -5935,13 +7371,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)
@@ -5954,13 +7383,11 @@
 		*/
 		if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) &&
 		    cmd->cmnd[4] >= 7 && !cmd->use_sg) {
+			sync_scsi_data(np, cmd);	/* SYNC the data */
 			ncr_setup_lcb (np, cp->target, cp->lun,
 				       (char *) cmd->request_buffer);
 		}
 
-		tp->bytes     += cp->data_len;
-		tp->transfers ++;
-
 		/*
 		**	If tags was reduced due to queue full,
 		**	increase tags if 1000 good status received.
@@ -5981,13 +7408,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 ||
@@ -6018,9 +7447,10 @@
 		/*
 		**   Transfer aborted
 		*/
-		SetScsiResult(cmd, DID_ABORT, cp->scsi_status);
+		SetScsiAbortResult(cmd);
 
 	} else {
+		int did_status;
 
 		/*
 		**  Other protocol messes
@@ -6029,7 +7459,11 @@
 		printk ("COMMAND FAILED (%x %x) @%p.\n",
 			cp->host_status, cp->scsi_status, cp);
 
-		SetScsiResult(cmd, DID_ERROR, cp->scsi_status);
+		did_status = DID_ERROR;
+		if (cp->xerr_status & XE_PARITY_ERR)
+			did_status = DID_PARITY;
+
+		SetScsiResult(cmd, did_status, cp->scsi_status);
 	}
 
 	/*
@@ -6037,12 +7471,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 +7482,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);
@@ -6099,6 +7528,10 @@
 /*
 **	The NCR has completed CCBs.
 **	Look at the DONE QUEUE.
+**
+**	On architectures that may reorder LOAD/STORE operations, 
+**	a memory barrier may be needed after the reading of the 
+**	so-called `flag' and prior to dealing with the data.
 */
 int ncr_wakeup_done (ncb_p np)
 {
@@ -6118,6 +7551,7 @@
 
 		cp = ncr_ccb_from_dsa(np, dsa);
 		if (cp) {
+			MEMORY_BARRIER();
 			ncr_complete (np, cp);
 			++n;
 		}
@@ -6180,7 +7614,7 @@
 	/*
 	**	Clear Start Queue
 	*/
-	phys = vtobus(np->squeue);
+	phys = np->p_squeue;
 	np->queuedepth = MAX_START - 1;	/* 1 entry needed as end marker */
 	for (i = 0; i < MAX_START*2; i += 2) {
 		np->squeue[i]   = cpu_to_scr(np->p_idletask);
@@ -6239,40 +7673,54 @@
 	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) &&
+		(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66)){
+		OUTB (nc_stest2, EXT|np->rv_stest2); 
+		/* Extended Sreq/Sack filtering, not supported in C1010/C1010_66 */
+	}
 	OUTB (nc_stest3, TE);			/* TolerANT enable */
 	OUTB (nc_stime0, 0x0c);			/* HTH disabled  STO 0.25 sec */
 
 	/*
 	**	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.
+	**	Disable overlapped arbitration for all dual-function 
+	**	devices, regardless revision id.
+	**	We may consider it is a post-chip-design feature. ;-)
+ 	**
+ 	**	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)
+	if (np->device_id == PCI_DEVICE_ID_NCR_53C875)
 		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->device_id == PCI_DEVICE_ID_LSI_53C1010_66 )
 		np->rv_ccntl0 |= DPR;
 
 	/*
-	**	If 64 bit (53C896) enable 40 bit address table 
-	**	indirect addressing for MOVE.
+	**	C1010_66MHz rev 0 part requies AIPCNTL1 bit 3 to be set.
 	*/
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)
+		OUTB(nc_aipcntl1, (1<<3));
 
+	/*
+	**	If 64 bit (895A/896/1010/1010_66) write the CCNTL1 register to 
+	**	enable 40 bit address table indirect addressing for MOVE.
+	**	Also write CCNTL0 if 64 bit chip, since this register seems 
+	**	to only be used by 64 bit cores.
+	*/
 	if (np->features & FE_64BIT) {
+		OUTB (nc_ccntl0, np->rv_ccntl0);
 		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 or 53C1010_66), set PM jump addresses. 
 	*/
 
 	if (np->features & FE_NOPM) {
 		printk(KERN_INFO "%s: handling phase mismatch from SCRIPTS.\n", 
 		       ncr_name(np));
-		OUTB (nc_ccntl0, np->rv_ccntl0);
 		OUTL (nc_pmjad1, NCB_SCRIPTH_PHYS (np, pm_handle));
 		OUTL (nc_pmjad2, NCB_SCRIPTH_PHYS (np, pm_handle));
 	}
@@ -6296,9 +7744,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 +7762,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) {
@@ -6339,7 +7791,6 @@
 	**    For platforms that may not support PCI memory mapping,
 	**    we use a simple SCRIPTS that performs MEMORY MOVEs.
 	*/
-	MEMORY_BARRIER();
 	if (np->base2_ba) {
 		if (bootverbose)
 			printk ("%s: Downloading SCSI SCRIPTS.\n",
@@ -6366,8 +7817,10 @@
 	else
 		phys = NCB_SCRIPT_PHYS (np, init);
 
-	OUTL (nc_dsa, vtobus(np));
-	OUTL (nc_dsp, phys);
+	np->istat_sem = 0;
+
+	OUTL (nc_dsa, np->p_ncb);
+	OUTL_DSP (phys);
 }
 
 /*==========================================================
@@ -6443,6 +7896,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 +7947,76 @@
 	**	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)  ||
+			(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+		*scntl3p	= (div+1) << 4;
+		*fakp		= 0;
+	}
+	else {
+		*scntl3p	= ((div+1) << 4) + (sfac < 25 ? 0x80 : 0);
+		*fakp		= fak - 4;
+	}
+}
+
+/*==========================================================
+**
+**	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) ||
+		(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66))
+		*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) || 
+	  		(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){
+		    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 +8030,20 @@
 
 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)  ||
+			(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) 
+		OUTB (nc_scntl4, tp->uval); 
 
 	/*
 	**	patch ALL ccbs of this target.
@@ -6523,6 +8055,9 @@
 			continue;
 		cp->phys.select.sel_scntl3 = tp->wval;
 		cp->phys.select.sel_sxfer  = tp->sval;
+		if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+				(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66))
+			cp->phys.select.sel_scntl4 = tp->uval;
 	};
 }
 
@@ -6533,11 +8068,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 +8083,21 @@
 
 	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) ||
+			(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+		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 +8105,42 @@
 	*/
 
 	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) ||
+			(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+			/* 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. :)
 	*/
+	if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE))
+		goto next;
 	PRINT_TARGET(np, target);
-	if (sxfer & 0x01f) {
+	if (offset) {
 		unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
 		unsigned mb10 = (f10 + tp->period/2) / tp->period;
 		char *scsi;
@@ -6580,22 +8148,26 @@
 		/*
 		**  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) &&
+			(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+				OUTOFFB (nc_stest2, EXT);
 
 		/*
 		**	Bells and whistles   ;-)
 		*/
-		if	(tp->period < 500)	scsi = "FAST-40";
+		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, sxfer & 0x1f);
+			mb10 / 10, mb10 % 10, tp->period / 10, offset);
 	} else
 		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
-
+next:
 	/*
 	**	set actual value and sync_status
 	**	patch ALL ccbs of this target.
@@ -6603,6 +8175,7 @@
 	ncr_set_sync_wide_status(np, target);
 }
 
+
 /*==========================================================
 **
 **	Switch wide mode for current job and it's target
@@ -6656,6 +8229,126 @@
 	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) ||
+			(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+		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) ||
+			(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+			/* 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;
+	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) &&
+			(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+				OUTOFFB (nc_stest2, EXT);
+
+		/*
+		**	Bells and whistles   ;-)
+		*/
+		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
+		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 +8360,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 +8454,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,33 +8474,70 @@
 		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;
+	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];
-			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;
+			switch (np->user.cmd) {
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	case UC_CLEARPROF:
-		bzero(&np->profile, sizeof(np->profile));
-		break;
-#endif
-	}
-	np->user.cmd=0;
+			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;
 }
 #endif
 
@@ -6850,7 +8557,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 +8570,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);
 
 	/*
@@ -6887,7 +8598,19 @@
 		np->lasttime = thistime;
 	}
 
-#ifdef SCSI_NCR_BROKEN_INTR
+#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_PCIQ_BROKEN_INTR
 	if (INB(nc_istat) & (INTF|SIP|DIP)) {
 
 		/*
@@ -6897,7 +8620,7 @@
 		ncr_exception (np);
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("}");
 	}
-#endif /* SCSI_NCR_BROKEN_INTR */
+#endif /* SCSI_NCR_PCIQ_BROKEN_INTR */
 }
 
 /*==========================================================
@@ -6924,7 +8647,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 +8696,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");
 }
@@ -7053,63 +8776,24 @@
 	u_short	sist;
 	int	i;
 
-#ifdef SCSI_NCR_OPTIMIZE_896_1
-	/*
-	**	This optimization when used with a 896 that handles 
-	**	phase mismatch from the SCRIPTS allows to only do 
-	**	PCI memory writes transactions from the CPU and so to 
-	**	take advantage of PCI posted writes.
-	**	Who wants his 500 MHz CPU to wait several micro-seconds 
-	**	for the PCI BUS to be granted when this can be avoided?
-	**	I don't, even for my slow 233 MHz PII. :-)
-	**
-	**	We assume we have been called for command completion.
-	**	If no completion found, go with normal handling.
-	**	Ordering is ensured by the SCRIPTS performing a read 
-	**	from main memory prior to raising INTFLY.
-	**	We have to raise SIGP since the chip may be currently 
-	**	going to a wait reselect instruction. IMO, SIGP should 
-	**	not be clearable in ISTAT since it can be polled and 
-	**	cleared by reading CTEST2. This tiny chip misdesign is a 
-	**	penalty here.
-	**
-	**	The MA interrupt and interrupt sharing may also have 
-	**	adverse effects on this optimization, so we only want 
-	**	to use it if it is enabled by user.
-	**	(BTW, this optimization seems to even have some goodness 
-	**	with my 895 that unfortunately suffers of the MA int.).
-	*/
-	if (driver_setup.optimize & 1) {
-		OUTB(nc_istat, (INTF | SIGP));
-		if (ncr_wakeup_done (np)) {
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-			++np->profile.num_fly;
-#endif
-			return;
-		}
-	}
-#endif /* SCSI_NCR_OPTIMIZE_896_1 */
-
 	/*
 	**	interrupt on the fly ?
+	**
+	**	A `dummy read' is needed to ensure that the 
+	**	clear of the INTF flag reaches the device 
+	**	before the scanning of the DONE queue.
 	*/
 	istat = INB (nc_istat);
 	if (istat & INTF) {
-		OUTB (nc_istat, (istat & SIGP) | INTF);
+		OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem);
+		istat = INB (nc_istat);		/* DUMMY READ */
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
 		(void)ncr_wakeup_done (np);
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-		++np->profile.num_fly;
-#endif
 	};
 
 	if (!(istat & (SIP|DIP)))
 		return;
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	++np->profile.num_int;
-#endif
-
 #if 0	/* We should never get this one */
 	if (istat & CABRT)
 		OUTB (nc_istat, CABRT);
@@ -7150,6 +8834,12 @@
 			(unsigned)INL(nc_dsp),
 			(unsigned)INL(nc_dbc));
 
+	/*
+	**	On paper, a memory barrier may be needed here.
+	**	And since we are paranoid ... :)
+	*/
+	MEMORY_BARRIER();
+
 	/*========================================================
 	**	First, interrupts we want to service cleanly.
 	**
@@ -7170,7 +8860,7 @@
 		if	(sist & PAR)	ncr_int_par (np, sist);
 		else if (sist & MA)	ncr_int_ma (np);
 		else if (dstat & SIR)	ncr_int_sir (np);
-		else if (dstat & SSI)	OUTONB (nc_dcntl, (STD|NOCOM));
+		else if (dstat & SSI)	OUTONB_STD ();
 		else			goto unknown_int;
 		return;
 	};
@@ -7213,8 +8903,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 +8913,28 @@
 
 	ncr_log_hard_error(np, sist, dstat);
 
+	if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+		(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+		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 +8999,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) {
@@ -7296,7 +9010,7 @@
 		OUTL (nc_dsa, DSA_INVALID);
 		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* clear dma fifo  */
 		OUTB (nc_stest3, TE|CSF);		/* clear scsi fifo */
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, start));
 	}
 	else
 		goto reset_all;
@@ -7330,7 +9044,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 +9060,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 +9109,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 +9135,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 +9152,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 +9172,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,35 +9185,44 @@
 	/*
 	**	Keep track of the parity error.
 	*/
-	OUTONB (HF_PRT, HF_PAR_ERR);
+	OUTONB (HF_PRT, HF_EXT_ERR);
+	cp->xerr_status |= XE_PARITY_ERR;
 
 	/*
 	**	Prepare the message to send to the device.
 	*/
 	np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR;
 
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+	/*
+	**	Save error message. For integrity check use only.
+	*/
+	if (np->check_integrity) 
+		np->check_integ_par = np->msgout[0];
+#endif
+
 	/*
-	**	If the old phase was DATA IN phase, we have to deal with
-	**	the 3 situations described above.
+	**	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);
+			OUTL_DSP (dsp);
 		/* Phase mismatch handled by the C code */
 		else if (sist & MA)
 			ncr_int_ma (np);
 		/* No phase mismatch occurred */
 		else {
 			OUTL (nc_temp, dsp);
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak));
+			OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch));
 		}
 	}
 	else 
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 	return;
 
 reset_all:
@@ -7524,10 +9261,6 @@
 	struct pm_ctx *pm;
 	ccb_p	cp;
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	++np->profile.num_break;
-#endif
-
 	dsp	= INL (nc_dsp);
 	dbc	= INL (nc_dbc);
 	dsa	= INL (nc_dsa);
@@ -7541,44 +9274,64 @@
 	*/
 	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) ||
+				(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) 
+			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) && 
+				(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (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) &&
+					(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && (ss2 & ORF)) 
+				rest++;
 		};
 
 		/*
@@ -7586,7 +9339,7 @@
 		*/
 		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* dma fifo  */
 		OUTB (nc_stest3, TE|CSF);		/* scsi fifo */
-	};
+	}
 
 	/*
 	**	log the information
@@ -7658,9 +9411,11 @@
 
 	/*
 	**	check cmd against assumed interrupted script command.
+	**	If dt data phase, the MOVE instruction hasn't bit 4 of 
+	**	the phase.
 	*/
 
-	if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) {
+	if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) {
 		PRINT_ADDR(cp->cmd);
 		printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
 			(unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24);
@@ -7670,9 +9425,10 @@
 
 	/*
 	**	if old phase not dataphase, leave here.
+	**	C/D line is low if data.
 	*/
 
-	if (cmd & 0x06) {
+	if (cmd & 0x02) {
 		PRINT_ADDR(cp->cmd);
 		printk ("phase change %x-%x %d@%08x resid=%d.\n",
 			cmd&7, INB(nc_sbcl)&7, (unsigned)olen,
@@ -7685,8 +9441,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 +9479,50 @@
 	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)) {
+		u32 tmp;
+
+#ifdef  SYM_DEBUG_PM_WITH_WSR
+		PRINT_ADDR(cp);
+		printf ("MA interrupt with WSR set - "
+			"pm->sg.addr=%x - pm->sg.size=%d\n",
+			pm->sg.addr, pm->sg.size);
+#endif
+		/*
+		 *  Set up the table indirect for the MOVE
+		 *  of the residual byte and adjust the data
+		 *  pointer context.
+		 */
+		tmp = scr_to_cpu(pm->sg.addr);
+		cp->phys.wresid.addr = cpu_to_scr(tmp);
+		pm->sg.addr = cpu_to_scr(tmp + 1);
+ 		tmp = scr_to_cpu(pm->sg.size);
+		cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1);
+		pm->sg.size = cpu_to_scr(tmp - 1);
+
+		/*
+		 *  If only the residual byte is to be moved,
+		 *  no PM context is needed.
+		 */
+		if ((tmp&0xffffff) == 1)
+                        newcmd = pm->ret;
+
+		/*
+		 *  Prepare the address of SCRIPTS that will
+		 *  move the residual byte to memory.
+		 */
+		nxtdsp = NCB_SCRIPTH_PHYS (np, wsr_ma_helper);
+        }
+
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		PRINT_ADDR(cp->cmd);
 		printk ("PM %x %x %x / %x %x %x.\n",
@@ -7733,12 +9533,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_DSP (nxtdsp);
 	return;
 
 	/*
@@ -7798,7 +9597,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;
@@ -7810,7 +9610,7 @@
 	}
 
 	if (nxtdsp) {
-		OUTL (nc_dsp, nxtdsp);
+		OUTL_DSP (nxtdsp);
 		return;
 	}
 
@@ -7842,6 +9642,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,75 +9658,75 @@
 	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) - np->p_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.
 	*/
-	MEMORY_BARRIER();
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+	OUTL_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 +9749,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->extra_bytes		= 0;
+		cp->host_flags		&= (HF_PM_TO_C|HF_DATA_IN);
 
 		break;
 
@@ -7957,12 +9764,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 +9787,73 @@
 		**	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.
+		*/
+
+#ifdef	SCSI_NCR_INTEGRITY_CHECKING
+		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) ||
+					(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66))
+				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]);
+		    }
+
+		}
+#else
+		ncr_negotiate(np, tp);
+		cp->nego_status = 0;
+		if ((tp->wval & EWS) || (tp->sval & 0x1f))
+			msglen +=
+			    ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]);
+#endif	/* SCSI_NCR_INTEGRITY_CHECKING */
+
+		/*
+		**	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
@@ -7986,43 +9866,34 @@
 		*/
 		cp->sensecmd[0]		= 0x03;
 		cp->sensecmd[1]		= cp->lun << 5;
-		cp->sensecmd[4]		= sizeof(cmd->sense_buffer);
+		cp->sensecmd[4]		= sizeof(cp->sense_buf);
 
 		/*
 		**	sense data
 		*/
-		cp->phys.sense.addr	=
-				cpu_to_scr(vtobus (&cmd->sense_buffer[0]));
-		cp->phys.sense.size	=
-				cpu_to_scr(sizeof(cmd->sense_buffer));
+		bzero(cp->sense_buf, sizeof(cp->sense_buf));
+		cp->phys.sense.addr	= cpu_to_scr(CCB_PHYS(cp,sense_buf[0]));
+		cp->phys.sense.size	= cpu_to_scr(sizeof(cp->sense_buf));
 
 		/*
 		**	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|HF_DATA_IN);
 
 		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,111 +9910,784 @@
 	return;
 }
 
+/*----------------------------------------------------------
+**
+**	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_clear_tasks(ncb_p np, u_char hsts, 
+			   int target, int lun, int task)
+{
+	int i = 0;
+	ccb_p cp;
+
+	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;
+}
 
 /*==========================================================
 **
+**	ncr chip handler for TASKS recovery.
 **
-**      ncr chip exception handler for programmed interrupts.
+**==========================================================
 **
+**	We cannot safely abort a command, while the SCRIPTS 
+**	processor is running, since we just would be in race 
+**	with it.
 **
-**==========================================================
+**	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 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 ...
+**
+**	On SIR_TARGET_SELECTED, we scan for the more 
+**	appropriate thing to do:
+**
+**	- 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.
+**	
+**----------------------------------------------------------
 */
-
-static int ncr_show_msg (u_char * msg)
+static void ncr_sir_task_recovery(ncb_p np, int num)
 {
-	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);
-}
-
+	ccb_p cp;
+	tcb_p tp;
+	int target=-1, lun=-1, task;
+	int i, k;
+	u_char *p;
 
-void ncr_int_sir (ncb_p np)
-{
-	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];
+	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:
 
-	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
+		/*
+		**	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;
+		}
 
-	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.
+		**	If not, look at the CCB list for any 
+		**	disconnected CCB to be aborted.
 		*/
-		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 (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;
+				}
+			}
+		}
+
 		/*
-		**	If devices reselecting without sending an IDENTIFY 
-		**	message still exist, this should help.
-		**	We just assume lun=0, 1 CCB, no tag.
+		**	If some target is to be selected, 
+		**	prepare and start the selection.
 		*/
-		if (tp->l0p) { 
-			OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0]));
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
+		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, np->p_ncb);
+			OUTL_DSP (NCB_SCRIPTH_PHYS (np, sel_for_abort));
 			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;
-	}
+		**	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) - np->p_squeue) / 4;
 
-	switch (num) {
-/*-----------------------------------------------------------------------------
-**
-**	Was Sie schon immer ueber transfermode negotiation wissen wollten ...
-**
-**	We try to negotiate sync and wide transfer only after
+			/*
+			**	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;
+				}
+
+				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);
+
+		/*
+		**	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;
+		}
+
+		/*
+		**	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;
+				}
+			}
+		}
+
+		/*
+		**	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;
+		}
+
+		/*
+		**	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 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;
+		}
+
+		/*
+		**	We have some task to abort.
+		**	Set the IDENTIFY(lun)
+		*/
+		np->abrt_msg[0] = M_IDENTIFY | cp->lun;
+
+		/*
+		**	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;
+
+	/*
+	**	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;
+
+		/*
+		**	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)
+		*/
+		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);
+		}
+
+		/*
+		**	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];
+		}
+
+		/*
+		**	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;
+
+	/*
+	**	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));
+		if (!cp)
+			break;
+		memcpy(cp->cmd->sense_buffer, cp->sense_buf,
+		       sizeof(cp->cmd->sense_buffer));
+		p  = &cp->cmd->sense_buffer[0];
+
+		if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29)
+			break;
+#if 0
+		(void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1);
+#endif
+		break;
+	}
+
+	/*
+	**	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);
+	}
+
+	/*
+	**	Let the SCRIPTS processor continue.
+	*/
+	OUTONB_STD ();
+}
+
+
+/*==========================================================
+**
+**	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.
+**
+**----------------------------------------------------------
+*/
+
+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;
+
+	/*
+	**	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  = scr_to_cpu(pm->ret);
+		dp_ofs -= scr_to_cpu(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 and vice-versa.
+	*/
+	tmp = scr_to_cpu(cp->phys.header.goalp);
+	dp_sg = MAX_SCATTER;
+	if (dp_scr != tmp)
+		dp_sg -= (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) {
+			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+			dp_ofs -= (tmp & 0xffffff);
+			++dp_sg;
+			if (dp_ofs <= 0)
+				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;
+
+	/*
+	**	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;
+	}
+
+	/*
+	**	Return data.
+	*/
+	*ofs = dp_ofs;
+	return dp_sg;
+
+out_err:
+	return -1;
+}
+
+/*==========================================================
+**
+**	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).
+**
+**----------------------------------------------------------
+*/
+
+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_int32	tmp;
+	u_char	hflags;
+	int	dp_sg;
+	struct pm_ctx *pm;
+
+	/*
+	**	Not supported for auto_sense;
+	*/
+	if (cp->host_flags & HF_AUTO_SENSE)
+		goto out_reject;
+
+	/*
+	**	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;
+
+	/*
+	**	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);
+	tmp  = scr_to_cpu(cp->phys.data[dp_sg-1].addr);
+	tmp += scr_to_cpu(cp->phys.data[dp_sg-1].size) + dp_ofs;
+	pm->sg.addr = cpu_to_scr(tmp);
+	pm->sg.size = cpu_to_scr(-dp_ofs);
+
+out_ok:
+	OUTL (nc_temp, dp_scr);
+	OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
+	return;
+
+out_reject:
+	OUTL_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, tmp;
+	int resid=0;
+	int dp_ofs = 0;
+
+	/*
+	 *	Check for some data lost or just thrown away.
+	 *	We are not required to be quite accurate in this
+	 *	situation. Btw, if we are odd for output and the
+	 *	device claims some more data, it may well happen
+	 *	than our residual be zero. :-)
+	 */
+	if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) {
+		if (cp->xerr_status & XE_EXTRA_DATA)
+			resid -= cp->extra_bytes;
+		if (cp->xerr_status & XE_SODL_UNRUN)
+			++resid;
+		if (cp->xerr_status & XE_SWIDE_OVRUN)
+			--resid;
+	}
+
+
+	/*
+	**	If SCRIPTS reaches its goal point, then 
+	**	there is no additionnal residual.
+	*/
+	if (cp->phys.header.lastp == cp->phys.header.goalp)
+		return resid;
+
+	/*
+	**	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 no data transfer occurs, or if the data
+	**	pointer is weird, return full residual.
+	*/
+	if (cp->startp == cp->phys.header.lastp ||
+	    ncr_evaluate_dp(np, cp, scr_to_cpu(cp->phys.header.lastp),
+			    &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.
 **
@@ -8152,8 +10696,8 @@
 **	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
+**	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).
@@ -8171,375 +10715,811 @@
 **
 **	If the target doesn't fetch the answer (no message out phase),
 **	we assume the negotiation has failed, and fall back to default
-**	settings.
+**	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.
 **
-**	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
+**---------------------------------------------------------------------
+*/
+
+/*==========================================================
 **
-**-----------------------------------------------------------------------------
+**	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;
 
-	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);
+	/*
+	**	Synchronous request message received.
+	*/
 
-		/* fall through */
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "sync msg in", np->msgin);
+	};
 
-	case SIR_NEGO_PROTO:
-		/*-------------------------------------------------------
-		**
-		**	Negotiation failed.
-		**	Target doesn't fetch the answer message.
-		**
-		**-------------------------------------------------------
-		*/
+	/*
+	**	get requested values.
+	*/
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("negotiation failed sir=%x status=%x.\n",
-				num, cp->nego_status);
-		};
+	chg = 0;
+	per = np->msgin[3];
+	ofs = np->msgin[4];
+	if (ofs==0) per=255;
 
-		/*
-		**	any error in negotiation:
-		**	fall back to default mode.
-		*/
-		switch (cp->nego_status) {
+	/*
+	**      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:
-			ncr_setsync (np, cp, 0, 0xe0);
-			break;
+			/*
+			**      This was an answer message
+			*/
+			if (chg) {
+				/*
+				**	Answer wasn't acceptable.
+				*/
+				ncr_setsync (np, cp, 0, 0xe0, 0);
+				OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+				if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+					(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+				  ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0);
+				else
+				  ncr_setsync (np, cp, scntl3, ofs, scntl4);
+
+				OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
+			};
+			return;
 
 		case NS_WIDE:
 			ncr_setwide (np, cp, 0, 0);
 			break;
-
 		};
-		np->msgin [0] = M_NOOP;
-		np->msgout[0] = M_NOOP;
-		cp->nego_status = 0;
-		break;
+	};
 
-	case SIR_NEGO_SYNC:
-		/*
-		**	Synchronous request message received.
-		*/
+	/*
+	**	It was a request. Set value and
+	**      prepare an answer message
+	*/
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgin: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		};
+	if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+			(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+		ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0);
+	else
+		ncr_setsync (np, cp, scntl3, ofs, scntl4);
 
-		/*
-		**	get requested values.
-		*/
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 3;
+	np->msgout[2] = M_X_SYNC_REQ;
+	np->msgout[3] = per;
+	np->msgout[4] = ofs;
 
-		chg = 0;
-		per = np->msgin[3];
-		ofs = np->msgin[4];
-		if (ofs==0) per=255;
+	cp->nego_status = NS_SYNC;
 
-		/*
-		**      if target sends SDTR message,
-		**	      it CAN transfer synch.
-		*/
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "sync msgout", np->msgout);
+	}
 
-		if (ofs)
-			tp->inq_byte7 |= INQ7_SYNC;
+	np->msgin [0] = M_NOOP;
 
-		/*
-		**	check values against driver limits.
-		*/
+	if (!ofs)
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
+	else
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, sdtr_resp));
+}
 
-		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;}
+/*==========================================================
+**
+**	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;
 
-		/*
-		**	Check against controller limits.
-		*/
-		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;
-		}
+	/*
+	**	Wide request message received.
+	*/
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "wide msgin", np->msgin);
+	};
 
-		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);
-		}
+	/*
+	**	get requested values.
+	*/
 
-		if (INB (HS_PRT) == HS_NEGOTIATE) {
-			OUTB (HS_PRT, HS_BUSY);
-			switch (cp->nego_status) {
+	chg  = 0;
+	wide = np->msgin[3];
 
-			case NS_SYNC:
+	/*
+	**      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) {
 				/*
-				**      This was an answer message
+				**	Answer wasn't acceptable.
 				*/
-				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;
-
-			case NS_WIDE:
-				ncr_setwide (np, cp, 0, 0);
-				break;
+				ncr_setwide (np, cp, 0, 1);
+				OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+				ncr_setwide (np, cp, wide, 1);
+				OUTL_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
-		*/
+	/*
+	**	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_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.
+	*/
 
-		ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+	if   ((per == 0x09) && ofs && (!wth || !dt))  
+		chg = 1;
+	else if (( (per > 0x09) && dt) ) 
+		chg = 2;
 
-		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) {
+		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 (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgout: ");
-			(void) ncr_show_msg (np->msgout);
-			printk (".\n");
-		}
+	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_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+
+				if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+					(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+				  ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth);
+				else
+				  ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth);
 
-		if (!ofs) {
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
+				OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
+				
+			};
 			return;
-		}
-		np->msgin [0] = M_NOOP;
 
-		break;
+		case NS_SYNC:
+			ncr_setsync (np, cp, 0, 0xe0, 0);
+			break;
 
-	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");
+		case NS_WIDE:
+			ncr_setwide (np, cp, 0, 0);
+			break;
 		};
+	};
 
-		/*
-		**	get requested values.
-		*/
+	/*
+	**	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.
+	*/
 
-		chg  = 0;
-		wide = np->msgin[3];
+	if  ((per == 0x09) && ofs && (!wth || !dt)) {
+		per = 0x0A;
+		dt = 0;
+                ofs &= 0x1f;
+	}
+	else if ( (per > 0x09) && dt) {
+		dt = 0;
+                ofs &= 0x1f;
+	}
 
-		/*
-		**      if target sends WDTR message,
-		**	      it CAN transfer wide.
-		*/
+	if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+			(np->device_id != PCI_DEVICE_ID_LSI_53C1010_66))
+		ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth);
+	else
+		ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth);
 
-		if (wide)
-			tp->inq_byte7 |= INQ7_WIDE16;
+	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;
 
-		/*
-		**	check values against driver limits.
-		*/
+	cp->nego_status = NS_PPR;
 
-		if (wide > tp->usrwide)
-			{chg = 1; wide = tp->usrwide;}
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "ppr msgout", np->msgout);
+	}
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide: wide=%d chg=%d.\n", wide, chg);
-		}
+	np->msgin [0] = M_NOOP;
 
-		if (INB (HS_PRT) == HS_NEGOTIATE) {
-			OUTB (HS_PRT, HS_BUSY);
-			switch (cp->nego_status) {
+	if (!ofs)
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
+	else
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, ppr_resp));
+}
 
-			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));
-				};
-				return;
 
-			case NS_SYNC:
-				ncr_setsync (np, cp, 0, 0xe0);
-				break;
-			};
-		};
 
-		/*
-		**	It was a request, set value and
-		**      prepare an answer message
-		*/
+/*
+**	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) {
 
-		ncr_setwide (np, cp, wide, 1);
+	case NS_SYNC:
+		ncr_setsync (np, cp, 0, 0xe0, 0);
+		break;
 
-		np->msgout[0] = M_EXTENDED;
-		np->msgout[1] = 2;
-		np->msgout[2] = M_X_WIDE_REQ;
-		np->msgout[3] = wide;
+	case NS_WIDE:
+		ncr_setwide (np, cp, 0, 0);
+		break;
 
-		np->msgin [0] = M_NOOP;
+	case NS_PPR:
+		/*
+		 * ppr_negotiation is set to 1 on the first ppr nego command.
+		 * If ppr is successful, it is reset to 2.
+		 * If unsuccessful it is reset to 0.
+		 */
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			tcb_p tp=&np->target[cp->target];
+			u_char factor, offset, width;
 
-		cp->nego_status = NS_WIDE;
+			ncr_get_xfer_info ( np, tp, &factor, &offset, &width);
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgout: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
+			printk("Current factor %d offset %d width %d\n",
+				factor, offset, width);	
+		}
+		if (tp->ppr_negotiation == 2)
+			ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0);
+		else if (tp->ppr_negotiation == 1) {
+
+			/* First ppr command has received a  M REJECT.
+			 * Do not change the existing wide/sync parameter
+			 * values (asyn/narrow if this as the first nego;
+			 * may be different if target initiates nego.).
+			 */
+			tp->ppr_negotiation = 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
 **
-**	Processing of special messages
+**==========================================================
+**
+**	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);
+}
 
-	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;
 
-/*--------------------------------------------------------------------
+/*==========================================================
+**
+**
+**      ncr chip exception handler for programmed interrupts.
 **
-**	Processing of special messages
 **
-**--------------------------------------------------------------------
+**==========================================================
 */
 
-	case SIR_IGN_RESIDUE:
-		/*-----------------------------------------------
-		**
-		**	We received an IGNORE RESIDUE message,
-		**	which couldn't be handled by the script.
-		**
-		**-----------------------------------------------
-		*/
+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;
 
-		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.
-		**
-		**-----------------------------------------------
-		*/
+	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
 
-		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;
+	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:
+	case SIR_AUTO_SENSE_DONE:
+		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_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 (!cp->xerr_status)
+					OUTOFFB (HF_PRT, HF_EXT_ERR);
+			}
+		}
+		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) {
+                        OUTONB (HF_PRT, HF_EXT_ERR);
+                        cp->xerr_status |= XE_SWIDE_OVRUN;
+                }
+		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) {
+                        OUTONB (HF_PRT, HF_EXT_ERR);
+                        cp->xerr_status |= XE_SODL_UNRUN;
+                }
+		goto out;
+	/*
+	**	The device wants us to tranfer more data than 
+	**	expected or in the wrong direction.
+	**	The number of extra bytes is in scratcha.
+	**	It is a data overrun condition.
+	*/
+	case SIR_DATA_OVERRUN:
+		if (cp) {
+			OUTONB (HF_PRT, HF_EXT_ERR);
+			cp->xerr_status |= XE_EXTRA_DATA;
+			cp->extra_bytes += INL (nc_scratcha);
+		}
+		goto out;
+	/*
+	**	The device switched to an illegal phase (4/5).
+	*/
+	case SIR_BAD_PHASE:
+		if (cp) {
+			OUTONB (HF_PRT, HF_EXT_ERR);
+			cp->xerr_status |= XE_BAD_PHASE;
+		}
+		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 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;
+		/*
+		**	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;
+	/*
+	**	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_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));
+	OUTONB_STD ();
+	return;
+out_reject:
+	OUTL_DSP (NCB_SCRIPTH_PHYS (np, msg_bad));
+	return;
+out_clrack:
+	OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
+	return;
 out_stuck:
 }
 
+
 /*==========================================================
 **
 **
@@ -8553,7 +11533,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 +11577,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 +11597,7 @@
 	/*
 	**	Remember all informations needed to free this CCB.
 	*/
+	cp->to_abort = 0;
 	cp->tag	   = tag;
 	cp->target = tn;
 	cp->lun    = ln;
@@ -8659,10 +11641,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);
@@ -8695,7 +11676,7 @@
 	/*
 	**	Allocate memory for this CCB.
 	*/
-	cp = m_calloc(sizeof(struct ccb), "CCB", MEMO_WARN);
+	cp = m_calloc_dma(sizeof(struct ccb), "CCB");
 	if (!cp)
 		return 0;
 
@@ -8723,6 +11704,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(NCB_PHYS(np, msgin[2]));
+
+	/*
 	**	Chain into wakeup list and free ccb queue.
 	*/
 	cp->link_ccb	= np->ccbc;
@@ -8772,26 +11758,7 @@
 **------------------------------------------------------------------------
 */
 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 +11766,11 @@
 		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) ||
+		(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)){
+		assert (( (offsetof(struct ncr_reg, nc_scntl4) ^
+			offsetof(struct tcb    , uval    )) &3) == 0);
+	}
 }
 
 /*------------------------------------------------------------------------
@@ -8823,33 +11795,46 @@
 	**	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_dma(256, "LUNTBL");
+		if (!tp->luntbl)
+			goto fail;
+		for (i = 0 ; i < 64 ; i++)
+			tp->luntbl[i] = cpu_to_scr(NCB_PHYS(np, resel_badlun));
+		tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
+	}
 
 	/*
 	**	Allocate the table of pointers for LUN(s) > 0, if needed.
 	*/
 	if (ln && !tp->lmp) {
-		tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP", MEMO_WARN);
+		tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP");
 		if (!tp->lmp)
 			goto fail;
 	}
 
 	/*
 	**	Allocate the lcb.
+	**	Make it available to the chip.
 	*/
-	lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN);
+	lp = m_calloc_dma(sizeof(struct lcb), "LCB");
 	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 +11884,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 +11936,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_dma(MAX_TASKS*4, "TASKTBL");
 		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");
+		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 +12000,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 
@@ -9033,7 +12025,7 @@
 
 #define CROSS_16MB(p, n) (((((u_long) p) + n - 1) ^ ((u_long) p)) & ~0xffffff)
 
-static	int ncr_scatter_no_sglist(ccb_p cp, Scsi_Cmnd *cmd)
+static	int ncr_scatter_no_sglist(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd)
 {
 	struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER-1];
 	int segment;
@@ -9041,7 +12033,8 @@
 	cp->data_len = cmd->request_bufflen;
 
 	if (cmd->request_bufflen) {
-		u_long baddr = vtobus(cmd->request_buffer);
+		u_long baddr = map_scsi_single_data(np, cmd);
+
 		SCATTER_ONE(data, baddr, cmd->request_bufflen);
 		if (CROSS_16MB(baddr, cmd->request_bufflen)) {
 			cp->host_flags |= HF_PM_TO_C;
@@ -9072,7 +12065,7 @@
 **	nicely power-of-two sized and aligned. But, since this may change 
 **	at any time, a work-around was required.
 */
-static int ncr_scatter_896R1(ccb_p cp, Scsi_Cmnd *cmd)
+static int ncr_scatter_896R1(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd)
 {
 	int segn;
 	int use_sg = (int) cmd->use_sg;
@@ -9080,18 +12073,23 @@
 	cp->data_len = 0;
 
 	if (!use_sg)
-		segn = ncr_scatter_no_sglist(cp, cmd);
+		segn = ncr_scatter_no_sglist(np, cp, cmd);
 	else if (use_sg > MAX_SCATTER)
 		segn = -1;
 	else {
 		struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
-		struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg];
+		struct scr_tblmove *data;
+
+		use_sg = map_scsi_sg_data(np, cmd);
+		data = &cp->phys.data[MAX_SCATTER - use_sg];
 
 		for (segn = 0; segn < use_sg; segn++) {
-			u_long baddr = vtobus(scatter[segn].address);
+			u_long baddr = scsi_sg_dma_address(&scatter[segn]);
+			unsigned int len = scsi_sg_dma_len(&scatter[segn]);
+
 			SCATTER_ONE(&data[segn],
 				    baddr,
-				    scatter[segn].length);
+				    len);
 			if (CROSS_16MB(baddr, scatter[segn].length)) {
 				cp->host_flags |= HF_PM_TO_C;
 #ifdef DEBUG_896R1
@@ -9099,14 +12097,14 @@
 	baddr, scatter[segn].length);
 #endif
 			}
-			cp->data_len += scatter[segn].length;
+			cp->data_len += len;
 		}
 	}
 
 	return segn;
 }
 
-static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd)
+static int ncr_scatter(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd)
 {
 	int segment;
 	int use_sg = (int) cmd->use_sg;
@@ -9114,19 +12112,24 @@
 	cp->data_len = 0;
 
 	if (!use_sg)
-		segment = ncr_scatter_no_sglist(cp, cmd);
+		segment = ncr_scatter_no_sglist(np, cp, cmd);
 	else if (use_sg > MAX_SCATTER)
 		segment = -1;
 	else {
 		struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
-		struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - use_sg];
+		struct scr_tblmove *data;
+
+		use_sg = map_scsi_sg_data(np, cmd);
+		data = &cp->phys.data[MAX_SCATTER - use_sg];
 
 		for (segment = 0; segment < use_sg; segment++) {
-			u_long baddr = vtobus(scatter[segment].address);
+			u_long baddr = scsi_sg_dma_address(&scatter[segment]);
+			unsigned int len = scsi_sg_dma_len(&scatter[segment]);
+
 			SCATTER_ONE(&data[segment],
 				    baddr,
-				    scatter[segment].length);
-			cp->data_len += scatter[segment].length;
+				    len);
+			cp->data_len += len;
 		}
 	}
 
@@ -9144,10 +12147,8 @@
 **==========================================================
 */
 
-#ifndef NCR_IOMAPPED
-__initfunc(
-static int ncr_regtest (struct ncb* np)
-)
+#ifndef SCSI_NCR_IOMAPPED
+static int __init ncr_regtest (struct ncb* np)
 {
 	register volatile u_int32 data;
 	/*
@@ -9171,13 +12172,11 @@
 }
 #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;
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	if (np->reg) {
             err |= ncr_regtest (np);
             if (err) return (err);
@@ -9197,8 +12196,8 @@
 	/*
 	**	Start script (exchange values)
 	*/
-	OUTL (nc_dsa, vtobus(np));
-	OUTL (nc_dsp, pc);
+	OUTL (nc_dsa, np->p_ncb);
+	OUTL_DSP (pc);
 	/*
 	**	Wait 'til done (with timeout)
 	*/
@@ -9256,100 +12255,6 @@
 
 /*==========================================================
 **
-**
-**	Profiling the drivers and targets performance.
-**
-**
-**==========================================================
-*/
-
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-
-static	void ncb_profile (ncb_p np, ccb_p cp)
-{
-	int num_disc	= (cp->phys.num_disc & 0xff);
-	int num_disc0	= (cp->phys.num_disc >> 8);
-
-	++np->profile.num_trans;
-	np->profile.num_disc	+= num_disc;
-	np->profile.num_disc0	+= num_disc0;
-	np->profile.num_kbytes	+= (cp->data_len >> 10);
-#if 000
-	if (num_disc > num_disc0) {
-		if (cp->data_len <= 1024)
-			np->profile.num_br1k += (num_disc - num_disc0);
-		else if (cp->data_len <= 2048)
-			np->profile.num_br2k += (num_disc - num_disc0);
-		else if (cp->data_len <= 4096)
-			np->profile.num_br4k += (num_disc - num_disc0);
-		else if (cp->data_len <= 8192)
-			np->profile.num_br8k += (num_disc - num_disc0);
-		else
-			np->profile.num_brnk += (num_disc - num_disc0);
-	}
-#endif
-}
-
-#endif /* SCSI_NCR_PROFILE_SUPPORT */
-
-/*==========================================================
-**
-**
-**	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 +12269,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 +12291,20 @@
 		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->device_id != PCI_DEVICE_ID_LSI_53C1010_66) && 
+						(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 +12315,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 +12336,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,30 +12359,51 @@
  	 */
  	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);
+	unsigned char scntl3 = np->sv_scntl3;
+	unsigned char stest1 = np->sv_stest1;
 	unsigned f1;
 
 	np->multiplier = 1;
 	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 +12412,43 @@
 	}
 
 	/*
+	**	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)  ||
+			(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)) {
+		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;
 
-		if (f1 < 80000 && mult > 1) {
+		/*
+		**	Suggest to also check the PCI clock frequency 
+		**	to make sure our frequency calculation algorithm 
+		**	is not too biased.
+		*/
+		if (np->features & FE_66MHZ) {
+			np->pciclock_min = (66000*55+80-1)/80;
+			np->pciclock_max = (66000*55)/40;
+		}
+		else {
+			np->pciclock_min = (33000*55+80-1)/80;
+			np->pciclock_max = (33000*55)/40;
+		}
+
+		if (f1 == 40000 && mult > 1) {
 			if (bootverbose >= 2)
 				printk ("%s: clock multiplier assumed\n", ncr_name(np));
 			np->multiplier	= mult;
@@ -9516,6 +12468,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 +12535,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 +12552,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 +12564,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 +12581,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 +12690,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,10 +12704,17 @@
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+	return 1;
 }
 
-static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
-	     uchar bus, uchar device_fn, ncr_device *device);
+#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, pcidev_t pdev, ncr_device *device);
 
 /*
 **   Linux entry point for SYM53C8XX devices detection routine.
@@ -9748,9 +12731,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,31 +12790,30 @@
 #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;
+	pcidev_t dev = PCIDEV_NULL;
 
-	for(index=0; index < SCSI_NCR_MAX_PQS_BUS; index ++) {
-		u_char tmp, bus, device_fn;
+	for(index=0; index < SCSI_NCR_MAX_PQS_BUS; index++) {
+		u_char tmp;
 
-		if (pcibios_find_device(0x101a, 0x0009, index, &bus, 
-					&device_fn) != PCIBIOS_SUCCESSFUL) {
+		dev = pci_find_device(0x101a, 0x0009, dev);
+		if (dev == PCIDEV_NULL) {
 			pqs_bus[index] = -1;
 			break;
 		}
-		printk(KERN_INFO NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", bus);
-		pcibios_read_config_byte(bus, device_fn, 0x44, &tmp);
+		printk(KERN_INFO NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", PciBusNumber(dev));
+		pci_read_config_byte(dev, 0x44, &tmp);
 		/* bit 1: allow individual 875 configuration */
 		tmp |= 0x2;
-		pcibios_write_config_byte(bus, device_fn, 0x44, tmp);
-		pcibios_read_config_byte(bus, device_fn, 0x45, &tmp);
+		pci_write_config_byte(dev, 0x44, tmp);
+		pci_read_config_byte(dev, 0x45, &tmp);
 		/* bit 2: drive individual 875 interrupts to the bus */
 		tmp |= 0x4;
-		pcibios_write_config_byte(bus, device_fn, 0x45, tmp);
+		pci_write_config_byte(dev, 0x45, tmp);
 
-		pqs_bus[index] = bus;
+		pqs_bus[index] = PciBusNumber(dev);
 	}
 }
 #endif /* SCSI_NCR_PQS_PDS_SUPPORT */
@@ -9849,13 +12829,10 @@
 **    the the order they are detected.
 **===================================================================
 */
-__initfunc(
-int sym53c8xx_detect(Scsi_Host_Template *tpnt)
-)
+int __init sym53c8xx_detect(Scsi_Host_Template *tpnt)
 {
+	pcidev_t pcidev;
 	int i, j, chips, hosts, count;
-	u_char bus, device_fn;
-	short index;
 	int attach_count = 0;
 	ncr_device *devtbl, *devp;
 #ifdef SCSI_NCR_NVRAM_SUPPORT
@@ -9865,24 +12842,24 @@
 	/*
 	**    PCI is required.
 	*/
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,92)
 	if (!pci_present())
-#else
-	if (!pcibios_present())
-#endif
 		return 0;
 
 	/*
 	**    Initialize driver general stuff.
 	*/
 #ifdef SCSI_NCR_PROC_INFO_SUPPORT
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
      tpnt->proc_dir  = &proc_scsi_sym53c8xx;
+#else
+     tpnt->proc_name = NAME53C8XX;
+#endif
      tpnt->proc_info = sym53c8xx_proc_info;
 #endif
 
 #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;
@@ -9896,7 +12873,7 @@
 	**	overflow the kernel stack.
 	**	1 x 4K PAGE is enough for more than 40 devices for i386.
 	*/
-	devtbl = m_calloc(PAGE_SIZE, "devtbl", MEMO_WARN);
+	devtbl = m_calloc(PAGE_SIZE, "devtbl");
 	if (!devtbl)
 		return 0;
 
@@ -9918,8 +12895,8 @@
 	nvp = (driver_setup.use_nvram & 0x1) ? &nvram0 : 0;
 #endif
 	j = 0;
-	index = 0;
 	count = 0;
+	pcidev = PCIDEV_NULL;
 	while (1) {
 		char *msg = "";
 		if (count >= hosts)
@@ -9927,17 +12904,24 @@
 		if (j >= chips)
 			break;
 		i = driver_setup.reverse_probe ? chips - 1 - j : j;
-		if (pcibios_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
-					index, &bus, &device_fn)) {
+		pcidev = pci_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
+					 pcidev);
+		if (pcidev == PCIDEV_NULL) {
 			++j;
-			index = 0;
 			continue;
 		}
-		++index;
+		/* Some HW as the HP LH4 may report twice PCI devices */
+		for (i = 0; i < count ; i++) {
+			if (devtbl[i].slot.bus	     == PciBusNumber(pcidev) && 
+			    devtbl[i].slot.device_fn == PciDeviceFn(pcidev))
+				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;
-		if (sym53c8xx_pci_init(tpnt, bus, device_fn, devp)) {
+		if (sym53c8xx_pci_init(tpnt, pcidev, devp)) {
 			continue;
 		}
 		++count;
@@ -10032,105 +13016,55 @@
 }
 
 /*===================================================================
-**   Generically read a base address from the PCI configuration space.
-**   Return the offset immediately after the base address that has 
-**   been read. Btw, we blindly assume that the high 32 bits of 64 bit 
-**   base addresses are set to zero on 32 bit architectures.
-**===================================================================
-*/
-#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
-__initfunc(
-static int 
-pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
-)
-{
-	u_int32 tmp;
-
-	pcibios_read_config_dword(bus, device_fn, offset, &tmp);
-	*base = tmp;
-	offset += sizeof(u_int32);
-	if ((tmp & 0x7) == 0x4) {
-#if BITS_PER_LONG > 32
-		pcibios_read_config_dword(bus, device_fn, offset, &tmp);
-		*base |= (((u_long)tmp) << 32);
-#endif
-		offset += sizeof(u_int32);
-	}
-	return offset;
-}
-#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */
-__initfunc(
-static int 
-pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
-)
-{
-	*base = pdev->base_address[index++];
-	if ((*base & 0x7) == 0x4) {
-#if BITS_PER_LONG > 32
-		*base |= (((u_long)pdev->base_address[index]) << 32);
-#endif
-		++index;
-	}
-	return index;
-}
-#endif
-
-/*===================================================================
 **   Read and check the PCI configuration for any detected NCR 
 **   boards and save data for attaching after all boards have 
 **   been detected.
 **===================================================================
 */
-__initfunc(
-static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
-			      uchar bus, uchar device_fn, ncr_device *device)
-)
+static int __init
+sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, 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 = driver_setup.pci_fix_up;
 	u_char revision;
-#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
-	struct pci_dev *pdev;
 	u_int irq;
-#else
-	u_char irq;
-#endif
 	u_long base, base_2, io_port; 
 	int i;
 	ncr_chip *chip;
 
 	printk(KERN_INFO NAME53C8XX ": at PCI bus %d, device %d, function %d\n",
-		bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7);
+		PciBusNumber(pdev),
+		(int) (PciDeviceFn(pdev) & 0xf8) >> 3,
+		(int) (PciDeviceFn(pdev) & 7));
+
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+	if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) {
+		printk(KERN_WARNING NAME53C8XX
+		       "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+		return -1;
+	}
+#endif
+
 	/*
 	**    Read info from the PCI config space.
-	**    pcibios_read_config_xxx() functions are assumed to be used for 
+	**    pci_read_config_xxx() functions are assumed to be used for 
 	**    successfully detected PCI devices.
 	*/
-#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
-	pdev = pci_find_slot(bus, device_fn);
-	vendor_id = pdev->vendor;
-	device_id = pdev->device;
-	irq = pdev->irq;
+	vendor_id = PciVendorId(pdev);
+	device_id = PciDeviceId(pdev);
+	irq	  = PciIrqLine(pdev);
 	i =	0;
 	i =	pci_get_base_address(pdev, i, &io_port);
 	i =	pci_get_base_address(pdev, i, &base);
 	(void)	pci_get_base_address(pdev, i, &base_2);
-#else
-	pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id);
-	pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID, &device_id);
-	pcibios_read_config_byte(bus, device_fn, PCI_INTERRUPT_LINE, &irq);
-	i =	PCI_BASE_ADDRESS_0;
-	i =	pci_read_base_address(bus, device_fn, i, &io_port);
-	i =	pci_read_base_address(bus, device_fn, i, &base);
-	(void)	pci_read_base_address(bus, device_fn, i, &base_2);
-#endif
-	pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
-	pcibios_read_config_byte(bus, device_fn, PCI_CLASS_REVISION, &revision);
-	pcibios_read_config_byte(bus, device_fn, PCI_CACHE_LINE_SIZE,
-				 &cache_line_size);
-	pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER,
-				 &latency_timer);
+
+	pci_read_config_word(pdev, PCI_COMMAND,		&command);
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION,	&revision);
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,	&cache_line_size);
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER,	&latency_timer);
+	pci_read_config_word(pdev, PCI_STATUS,		&status_reg);
 
 #ifdef SCSI_NCR_PQS_PDS_SUPPORT
 	/*
@@ -10141,8 +13075,8 @@
 	*/
 	for(i = 0; i < SCSI_NCR_MAX_PQS_BUS && pqs_bus[i] != -1; i++) {
 		u_char tmp;
-		if (pqs_bus[i] == bus) {
-			pcibios_read_config_byte(bus, device_fn, 0x84, &tmp);
+		if (pqs_bus[i] == PciBusNumber(pdev)) {
+			pci_read_config_byte(pdev, 0x84, &tmp);
 			device->pqs_pds = 1;
 			device->host_id = tmp;
 			break;
@@ -10201,7 +13135,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");
@@ -10219,7 +13153,7 @@
 		(command & PCI_COMMAND_IO)     ? "" : " PCI_COMMAND_IO",
 		(command & PCI_COMMAND_MEMORY) ? "" : " PCI_COMMAND_MEMORY");
 		command |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+		pci_write_config_word(pdev, PCI_COMMAND, command);
 	}
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
@@ -10227,26 +13161,26 @@
 		if (io_port >= 0x10000000) {
 			printk(NAME53C8XX ": reallocating io_port (Wacky IBM)");
 			io_port = (io_port & 0x00FFFFFF) | 0x01000000;
-			pcibios_write_config_dword(bus, device_fn,
-						   PCI_BASE_ADDRESS_0, io_port);
+			pci_write_config_dword(pdev,
+					       PCI_BASE_ADDRESS_0, io_port);
 		}
 		if (base >= 0x10000000) {
 			printk(NAME53C8XX ": reallocating base (Wacky IBM)");
 			base = (base & 0x00FFFFFF) | 0x01000000;
-			pcibios_write_config_dword(bus, device_fn,
-						   PCI_BASE_ADDRESS_1, base);
+			pci_write_config_dword(pdev,
+					       PCI_BASE_ADDRESS_1, base);
 		}
 		if (base_2 >= 0x10000000) {
 			printk(NAME53C8XX ": reallocating base2 (Wacky IBM)");
 			base_2 = (base_2 & 0x00FFFFFF) | 0x01000000;
-			pcibios_write_config_dword(bus, device_fn,
-						   PCI_BASE_ADDRESS_2, base_2);
+			pci_write_config_dword(pdev,
+					       PCI_BASE_ADDRESS_2, base_2);
 		}
 	}
 #endif
 #endif	/* __powerpc__ */
 
-#ifdef __sparc__
+#if defined(__sparc__) && (LINUX_VERSION_CODE < LinuxVersionCode(2,3,0))
 	/*
 	**    Fix-ups for sparc.
 	**
@@ -10297,9 +13231,9 @@
 	**    from attaching devices from the both drivers.
 	**    If you have a better idea, let me know.
 	*/
-/* #ifdef NCR_IOMAPPED */
+/* #ifdef SCSI_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;
@@ -10314,7 +13248,7 @@
 	base	&= PCI_BASE_ADDRESS_MEM_MASK;
 	base_2	&= PCI_BASE_ADDRESS_MEM_MASK;
 
-/* #ifdef NCR_IOMAPPED */
+/* #ifdef SCSI_NCR_IOMAPPED */
 #if 1
 	if (io_port && check_region (io_port, 128)) {
 		printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n",
@@ -10324,7 +13258,7 @@
 	if (!io_port)
 		return -1;
 #endif
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_IOMAPPED
 	if (!base) {
 		printk(NAME53C8XX ": MMIO base address disabled.\n");
 		return -1;
@@ -10340,7 +13274,7 @@
 		(command & PCI_COMMAND_MASTER) ? "" : " PCI_COMMAND_MASTER",
 		(command & PCI_COMMAND_PARITY) ? "" : " PCI_COMMAND_PARITY");
 		command |= (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY);
-		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+		pci_write_config_word(pdev, PCI_COMMAND, command);
 	}
 
 	/*
@@ -10354,33 +13288,82 @@
 		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;
+			pci_write_config_word(pdev, PCI_STATUS, status_reg);
+			pci_read_config_word(pdev, 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.
+	*/
+	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,
-				PCI_CACHE_LINE_SIZE, cache_line_size);
+		pci_write_config_byte(pdev,
+				      PCI_CACHE_LINE_SIZE, cache_line_size);
 		printk(NAME53C8XX ": PCI_CACHE_LINE_SIZE set to %d (fix-up).\n",
 			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;
-		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+		pci_write_config_word(pdev, PCI_COMMAND, command);
 	}
 
 	/*
@@ -10388,15 +13371,15 @@
 	**    (latency timer >= burst length + 6, we add 10 to be quite sure)
 	*/
 
-	if ((driver_setup.pci_fix_up & 4) && chip->burst_max) {
+	if (chip->burst_max && (latency_timer == 0 || (pci_fix_up & 4))) {
 		uchar lt = (1 << chip->burst_max) + 6 + 10;
 		if (latency_timer < lt) {
-			latency_timer = lt;
 			printk(NAME53C8XX 
-			       ": setting PCI_LATENCY_TIMER to %d (fix-up).\n",
-			       latency_timer);
-			pcibios_write_config_byte(bus, device_fn,
-					PCI_LATENCY_TIMER, latency_timer);
+			       ": changing PCI_LATENCY_TIMER from %d to %d.\n",
+			       (int) latency_timer, (int) lt);
+			latency_timer = lt;
+			pci_write_config_byte(pdev,
+					      PCI_LATENCY_TIMER, latency_timer);
 		}
 	}
 
@@ -10405,8 +13388,9 @@
  	/*
 	**    Initialise ncr_device structure with items required by ncr_attach.
 	*/
-	device->slot.bus	= bus;
-	device->slot.device_fn	= device_fn;
+	device->pdev		= pdev;
+	device->slot.bus	= PciBusNumber(pdev);
+	device->slot.device_fn	= PciDeviceFn(pdev);
 	device->slot.base	= base;
 	device->slot.base_2	= base_2;
 	device->slot.io_port	= io_port;
@@ -10430,7 +13414,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)
@@ -10438,7 +13422,7 @@
 	/*
 	**    Get access to chip IO registers
 	*/
-#ifdef NCR_IOMAPPED
+#ifdef SCSI_NCR_IOMAPPED
 	request_region(devp->slot.io_port, 128, NAME53C8XX);
 	devp->slot.base_io = devp->slot.io_port;
 #else
@@ -10451,9 +13435,10 @@
 	**    Try to read SYMBIOS nvram.
 	**    Try to read TEKRAM nvram if Symbios nvram not found.
 	*/
-	if	(!ncr_get_Symbios_nvram(&devp->slot, &nvp->data.Symbios))
+	if	(!sym_read_Symbios_nvram(&devp->slot, &nvp->data.Symbios))
 		nvp->type = SCSI_NCR_SYMBIOS_NVRAM;
-	else if	(!ncr_get_Tekram_nvram(&devp->slot, &nvp->data.Tekram))
+	else if	(!sym_read_Tekram_nvram(&devp->slot, devp->chip.device_id,
+					&nvp->data.Tekram))
 		nvp->type = SCSI_NCR_TEKRAM_NVRAM;
 	else {
 		nvp->type = 0;
@@ -10463,7 +13448,7 @@
 	/*
 	** Release access to chip IO registers
 	*/
-#ifdef NCR_IOMAPPED
+#ifdef SCSI_NCR_IOMAPPED
 	release_region(devp->slot.base_io, 128);
 #else
 	unmap_pci_mem((u_long) devp->slot.reg, 128ul);
@@ -10557,8 +13542,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 +13568,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
 }
 
 /*
@@ -10612,6 +13589,10 @@
      cmd->host_scribble = NULL;
      cmd->SCp.ptr       = NULL;
      cmd->SCp.buffer    = NULL;
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+     cmd->__data_mapped = 0;
+     cmd->__data_mapping = 0;
+#endif
 
      NCR_LOCK_NCB(np, flags);
 
@@ -10628,8 +13609,10 @@
 
      NCR_UNLOCK_NCB(np, flags);
 
-     if (sts != DID_OK)
+     if (sts != DID_OK) {
+          unmap_scsi_data(np, cmd);
           done(cmd);
+     }
 
      return sts;
 }
@@ -10900,7 +13883,7 @@
 /*=========================================================================
 **	Proc file system stuff
 **
-**	A read operation returns profile information.
+**	A read operation returns adapter information.
 **	A write operation is a control command.
 **	The string is parsed in the driver code and the command is passed 
 **	to the ncr_usercmd() function.
@@ -10990,8 +13973,10 @@
 		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, "clearprof")) != 0)
-		uc->cmd = UC_CLEARPROF;
+	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;
 	else
 		arg_len = 0;
 
@@ -11008,6 +13993,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 +14038,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 +14054,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;
@@ -11156,14 +14137,15 @@
 }
 
 /*
-**	Copy formatted profile information into the input buffer.
+**	Copy formatted information into the input buffer.
 */
 
-#define to_ms(t) ((t) * 1000 / HZ)
-
 static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len)
 {
 	struct info_str info;
+#ifdef CONFIG_ALL_PPC
+	struct device_node* of_node;
+#endif
 
 	info.buffer	= ptr;
 	info.length	= len;
@@ -11171,50 +14153,35 @@
 	info.pos	= 0;
 
 	copy_info(&info, "General information:\n");
-	copy_info(&info, "  Chip " NAME53C "%s, ", np->chip_name);
-	copy_info(&info, "device id 0x%x, ",	np->device_id);
-	copy_info(&info, "revision id 0x%x\n",	np->revision_id);
-
-	copy_info(&info, "  IO port address 0x%lx, ", (u_long) np->base_io);
+	copy_info(&info, "  Chip " NAME53C "%s, device id 0x%x, "
+			 "revision id 0x%x\n",
+			 np->chip_name, np->device_id,	np->revision_id);
+	copy_info(&info, "  On PCI bus %d, device %d, function %d, "
 #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);
+		"IRQ %s\n",
 #else
-	copy_info(&info, "IRQ number %d\n", (int) np->irq);
+		"IRQ %d\n",
 #endif
-
-#ifndef NCR_IOMAPPED
-	if (np->reg)
-		copy_info(&info, "  Using memory mapped IO at virtual address 0x%lx\n",
-		                  (u_long) np->reg);
+		np->bus, (np->device_fn & 0xf8) >> 3, np->device_fn & 7,
+#ifdef __sparc__
+		__irq_itoa(np->irq));
+#else
+		(int) np->irq);
 #endif
-	copy_info(&info, "  Synchronous period factor %d, ", (int) np->minsync);
-	copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+#ifdef CONFIG_ALL_PPC
+	of_node = find_pci_device_OFnode(np->bus, np->device_fn);
+	if (of_node && of_node->full_name)
+	    copy_info(&info, "PPC OpenFirmware path : %s\n", of_node->full_name);
+#endif
+	copy_info(&info, "  Synchronous period factor %d, "
+			 "max commands per lun %d\n",
+			 (int) np->minsync, MAX_TAGS);
 
 	if (driver_setup.debug || driver_setup.verbose > 1) {
-		copy_info(&info, "  Debug flags 0x%x, ", driver_setup.debug);
-		copy_info(&info, "verbosity level %d\n", driver_setup.verbose);
+		copy_info(&info, "  Debug flags 0x%x, verbosity level %d\n",
+			  driver_setup.debug, driver_setup.verbose);
 	}
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	copy_info(&info, "Profiling information:\n");
-	copy_info(&info, "  %-12s = %lu\n", "num_fly",	np->profile.num_fly);
-	copy_info(&info, "  %-12s = %lu\n", "num_trans",np->profile.num_trans);
-	copy_info(&info, "  %-12s = %lu\n", "num_disc",	np->profile.num_disc);
-	copy_info(&info, "  %-12s = %lu\n", "num_disc0",np->profile.num_disc0);
-	copy_info(&info, "  %-12s = %lu\n", "num_break",np->profile.num_break);
-#if 000
-	copy_info(&info, "  %-12s = %lu\n", "num_br1k",np->profile.num_br1k);
-	copy_info(&info, "  %-12s = %lu\n", "num_br2k",np->profile.num_br2k);
-	copy_info(&info, "  %-12s = %lu\n", "num_br4k",np->profile.num_br4k);
-	copy_info(&info, "  %-12s = %lu\n", "num_br8k",np->profile.num_br8k);
-	copy_info(&info, "  %-12s = %lu\n", "num_brnk",np->profile.num_brnk);
-#endif
-	copy_info(&info, "  %-12s = %lu\n", "num_int",	np->profile.num_int);
-	copy_info(&info, "  %-12s = %lu\n","num_kbytes",np->profile.num_kbytes);
-#endif
-
 	return info.pos > info.offset? info.pos - info.offset : 0;
 }
 
@@ -11222,7 +14189,7 @@
 
 /*
 **	Entry point of the scsi proc fs of the driver.
-**	- func = 0 means read  (returns profile data)
+**	- func = 0 means read  (returns adapter infos)
 **	- func = 1 means write (parse user control command)
 */
 
@@ -11268,57 +14235,164 @@
 #endif
 	}
 
-	return retv;
+	return retv;
+}
+
+
+/*=========================================================================
+**	End of proc file system stuff
+**=========================================================================
+*/
+#endif
+
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+
+/*
+ *  24C16 EEPROM reading.
+ *
+ *  GPOI0 - data in/data out
+ *  GPIO1 - clock
+ *  Symbios NVRAM wiring now also used by Tekram.
+ */
+
+#define SET_BIT 0
+#define CLR_BIT 1
+#define SET_CLK 2
+#define CLR_CLK 3
+
+/*
+ *  Set/clear data/clock bit in GPIO0
+ */
+static void __init
+S24C16_set_bit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
+{
+	UDELAY (5);
+	switch (bit_mode){
+	case SET_BIT:
+		*gpreg |= write_bit;
+		break;
+	case CLR_BIT:
+		*gpreg &= 0xfe;
+		break;
+	case SET_CLK:
+		*gpreg |= 0x02;
+		break;
+	case CLR_CLK:
+		*gpreg &= 0xfd;
+		break;
+
+	}
+	OUTB (nc_gpreg, *gpreg);
+	UDELAY (5);
+}
+
+/*
+ *  Send START condition to NVRAM to wake it up.
+ */
+static void __init S24C16_start(ncr_slot *np, u_char *gpreg)
+{
+	S24C16_set_bit(np, 1, gpreg, SET_BIT);
+	S24C16_set_bit(np, 0, gpreg, SET_CLK);
+	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
+	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
+}
+
+/*
+ *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
+ */
+static void __init S24C16_stop(ncr_slot *np, u_char *gpreg)
+{
+	S24C16_set_bit(np, 0, gpreg, SET_CLK);
+	S24C16_set_bit(np, 1, gpreg, SET_BIT);
+}
+
+/*
+ *  Read or write a bit to the NVRAM,
+ *  read if GPIO0 input else write if GPIO0 output
+ */
+static void __init 
+S24C16_do_bit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
+{
+	S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
+	S24C16_set_bit(np, 0, gpreg, SET_CLK);
+	if (read_bit)
+		*read_bit = INB (nc_gpreg);
+	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
+	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
 }
 
+/*
+ *  Output an ACK to the NVRAM after reading,
+ *  change GPIO0 to output and when done back to an input
+ */
+static void __init
+S24C16_write_ack(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
+{
+	OUTB (nc_gpcntl, *gpcntl & 0xfe);
+	S24C16_do_bit(np, 0, write_bit, gpreg);
+	OUTB (nc_gpcntl, *gpcntl);
+}
 
-/*=========================================================================
-**	End of proc file system stuff
-**=========================================================================
-*/
-#endif
+/*
+ *  Input an ACK from NVRAM after writing,
+ *  change GPIO0 to input and when done back to an output
+ */
+static void __init 
+S24C16_read_ack(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
+{
+	OUTB (nc_gpcntl, *gpcntl | 0x01);
+	S24C16_do_bit(np, read_bit, 1, gpreg);
+	OUTB (nc_gpcntl, *gpcntl);
+}
 
+/*
+ *  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
+ */
+static void __init 
+S24C16_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, 
+		  u_char *gpreg, u_char *gpcntl)
+{
+	int x;
+	
+	for (x = 0; x < 8; x++)
+		S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
+		
+	S24C16_read_ack(np, ack_data, gpreg, gpcntl);
+}
 
-#ifdef SCSI_NCR_NVRAM_SUPPORT
+/*
+ *  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
+ */
+static void __init 
+S24C16_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;
 
-/* ---------------------------------------------------------------------
-**
-**	Try reading Symbios format nvram
-**
-** ---------------------------------------------------------------------
-**
-** GPOI0 - data in/data out
-** GPIO1 - clock
-**
-**	return 0 if NVRAM data OK, 1 if NVRAM data not OK
-** ---------------------------------------------------------------------
-*/
+	*read_data = 0;
+	for (x = 0; x < 8; x++) {
+		S24C16_do_bit(np, &read_bit, 1, gpreg);
+		*read_data |= ((read_bit & 0x01) << (7 - x));
+	}
 
-#define SET_BIT 0
-#define CLR_BIT 1
-#define SET_CLK 2
-#define CLR_CLK 3
+	S24C16_write_ack(np, ack_data, gpreg, gpcntl);
+}
 
-static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl);
-static void nvram_start(ncr_slot *np, u_char *gpreg);
-static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl);
-static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl);
-static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl);
-static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl);
-static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg);
-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)
-)
+/*
+ *  Read 'len' bytes starting at 'offset'.
+ */
+static int __init 
+sym_read_S24C16_nvram (ncr_slot *np, int offset, u_char *data, int len)
 {
-	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
 	u_char	gpcntl, gpreg;
 	u_char	old_gpcntl, old_gpreg;
-	u_short	csum;
 	u_char	ack_data;
 	int	retv = 1;
+	int	x;
 
 	/* save current state of GPCNTL and GPREG */
 	old_gpreg	= INB (nc_gpreg);
@@ -11331,33 +14405,33 @@
 
 	/* this is to set NVRAM into a known state with GPIO0/1 both low */
 	gpreg = old_gpreg;
-	nvram_setBit(np, 0, &gpreg, CLR_CLK);
-	nvram_setBit(np, 0, &gpreg, CLR_BIT);
+	S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
+	S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
 		
 	/* now set NVRAM inactive with GPIO0/1 both high */
-	nvram_stop(np, &gpreg);
+	S24C16_stop(np, &gpreg);
 	
 	/* activate NVRAM */
-	nvram_start(np, &gpreg);
+	S24C16_start(np, &gpreg);
 
 	/* write device code and random address MSB */
-	nvram_write_byte(np, &ack_data,
-		0xa0 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl);
+	S24C16_write_byte(np, &ack_data,
+		0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
 	if (ack_data & 0x01)
 		goto out;
 
 	/* write random address LSB */
-	nvram_write_byte(np, &ack_data,
-		(SYMBIOS_NVRAM_ADDRESS & 0x7f) << 1, &gpreg, &gpcntl);
+	S24C16_write_byte(np, &ack_data,
+		offset & 0xff, &gpreg, &gpcntl);
 	if (ack_data & 0x01)
 		goto out;
 
 	/* regenerate START state to set up for reading */
-	nvram_start(np, &gpreg);
+	S24C16_start(np, &gpreg);
 	
 	/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
-	nvram_write_byte(np, &ack_data,
-		0xa1 | ((SYMBIOS_NVRAM_ADDRESS >> 7) & 0x0e), &gpreg, &gpcntl);
+	S24C16_write_byte(np, &ack_data,
+		0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
 	if (ack_data & 0x01)
 		goto out;
 
@@ -11365,30 +14439,15 @@
 	gpcntl |= 0x01;
 	OUTB (nc_gpcntl, gpcntl);
 		
-	/* input all active data - only part of total NVRAM */
-	csum = nvram_read_data(np,
-			(u_char *) nvram, sizeof(*nvram), &gpreg, &gpcntl);
+	/* input all requested data - only part of total NVRAM */
+	for (x = 0; x < len; x++) 
+		S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
 
 	/* finally put NVRAM back in inactive mode */
 	gpcntl &= 0xfe;
 	OUTB (nc_gpcntl, gpcntl);
-	nvram_stop(np, &gpreg);
-	
-#ifdef SCSI_NCR_DEBUG_NVRAM
-printk("sym53c8xx: NvRAM type=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
-	nvram->type,
-	nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
-	nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
-	nvram->byte_count, sizeof(*nvram) - 12,
-	nvram->checksum, csum);
-#endif
-
-	/* check valid NVRAM signature, verify byte count and checksum */
-	if (nvram->type == 0 &&
-	    !memcmp(nvram->trailer, Symbios_trailer, 6) &&
-	    nvram->byte_count == sizeof(*nvram) - 12 &&
-	    csum == nvram->checksum)
-		retv = 0;
+	S24C16_stop(np, &gpreg);
+	retv = 0;
 out:
 	/* return GPIO0/1 to original states after having accessed NVRAM */
 	OUTB (nc_gpcntl, old_gpcntl);
@@ -11397,190 +14456,170 @@
 	return retv;
 }
 
+#undef SET_BIT
+#undef CLR_BIT
+#undef SET_CLK
+#undef CLR_CLK
+
 /*
- * Read Symbios NvRAM data and compute checksum.
+ *  Try reading Symbios NVRAM.
+ *  Return 0 if OK.
  */
-__initfunc(
-static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
-)
+static int __init sym_read_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
 {
-	int	x;
+	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
+	u_char *data = (u_char *) nvram;
+	int len  = sizeof(*nvram);
 	u_short	csum;
+	int x;
 
-	for (x = 0; x < len; x++) 
-		nvram_read_byte(np, &data[x], (x == (len - 1)), gpreg, gpcntl);
+	/* probe the 24c16 and read the SYMBIOS 24c16 area */
+	if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
+		return 1;
 
+	/* check valid NVRAM signature, verify byte count and checksum */
+	if (nvram->type != 0 ||
+	    memcmp(nvram->trailer, Symbios_trailer, 6) ||
+	    nvram->byte_count != len - 12)
+		return 1;
+
+	/* verify checksum */
 	for (x = 6, csum = 0; x < len - 6; x++)
 		csum += data[x];
+	if (csum != nvram->checksum)
+		return 1;
 
-	return csum;
+	return 0;
 }
 
 /*
- * Send START condition to NVRAM to wake it up.
+ *  93C46 EEPROM reading.
+ *
+ *  GPOI0 - data in
+ *  GPIO1 - data out
+ *  GPIO2 - clock
+ *  GPIO4 - chip select
+ *
+ *  Used by Tekram.
  */
-__initfunc(
-static void nvram_start(ncr_slot *np, u_char *gpreg)
-)
-{
-	nvram_setBit(np, 1, gpreg, SET_BIT);
-	nvram_setBit(np, 0, gpreg, SET_CLK);
-	nvram_setBit(np, 0, gpreg, CLR_BIT);
-	nvram_setBit(np, 0, gpreg, CLR_CLK);
-}
 
 /*
- * 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
+ *  Pulse clock bit in GPIO0
  */
-__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 T93C46_Clk(ncr_slot *np, u_char *gpreg)
 {
-	int x;
-	
-	for (x = 0; x < 8; x++)
-		nvram_doBit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
-		
-	nvram_readAck(np, ack_data, gpreg, gpcntl);
+	OUTB (nc_gpreg, *gpreg | 0x04);
+	UDELAY (2);
+	OUTB (nc_gpreg, *gpreg);
 }
 
-/*
- * 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
+/* 
+ *  Read bit from NVRAM
  */
-__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 T93C46_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
 {
-	int x;
-	u_char read_bit;
-
-	*read_data = 0;
-	for (x = 0; x < 8; x++) {
-		nvram_doBit(np, &read_bit, 1, gpreg);
-		*read_data |= ((read_bit & 0x01) << (7 - x));
-	}
-
-	nvram_writeAck(np, ack_data, gpreg, gpcntl);
+	UDELAY (2);
+	T93C46_Clk(np, gpreg);
+	*read_bit = INB (nc_gpreg);
 }
 
 /*
- * Output an ACK to the NVRAM after reading,
- * change GPIO0 to output and when done back to an input
+ *  Write bit to GPIO0
  */
-__initfunc(
-static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
-)
+static void __init T93C46_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
 {
-	OUTB (nc_gpcntl, *gpcntl & 0xfe);
-	nvram_doBit(np, 0, write_bit, gpreg);
-	OUTB (nc_gpcntl, *gpcntl);
+	if (write_bit & 0x01)
+		*gpreg |= 0x02;
+	else
+		*gpreg &= 0xfd;
+		
+	*gpreg |= 0x10;
+		
+	OUTB (nc_gpreg, *gpreg);
+	UDELAY (2);
+
+	T93C46_Clk(np, gpreg);
 }
 
 /*
- * Input an ACK from NVRAM after writing,
- * change GPIO0 to input and when done back to an output
+ *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
  */
-__initfunc(
-static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
-)
+static void __init T93C46_Stop(ncr_slot *np, u_char *gpreg)
 {
-	OUTB (nc_gpcntl, *gpcntl | 0x01);
-	nvram_doBit(np, read_bit, 1, gpreg);
-	OUTB (nc_gpcntl, *gpcntl);
+	*gpreg &= 0xef;
+	OUTB (nc_gpreg, *gpreg);
+	UDELAY (2);
+
+	T93C46_Clk(np, gpreg);
 }
 
 /*
- * Read or write a bit to the NVRAM,
- * read if GPIO0 input else write if GPIO0 output
+ *  Send read command and address to NVRAM
  */
-__initfunc(
-static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
-)
+static void __init 
+T93C46_Send_Command(ncr_slot *np, u_short write_data, 
+		    u_char *read_bit, u_char *gpreg)
 {
-	nvram_setBit(np, write_bit, gpreg, SET_BIT);
-	nvram_setBit(np, 0, gpreg, SET_CLK);
-	if (read_bit)
-		*read_bit = INB (nc_gpreg);
-	nvram_setBit(np, 0, gpreg, CLR_CLK);
-	nvram_setBit(np, 0, gpreg, CLR_BIT);
+	int x;
+
+	/* send 9 bits, start bit (1), command (2), address (6)  */
+	for (x = 0; x < 9; x++)
+		T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
+
+	*read_bit = INB (nc_gpreg);
 }
 
 /*
- * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
+ *  READ 2 bytes from the NVRAM
  */
-__initfunc(
-static void nvram_stop(ncr_slot *np, u_char *gpreg)
-)
+static void __init 
+T93C46_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
 {
-	nvram_setBit(np, 0, gpreg, SET_CLK);
-	nvram_setBit(np, 1, gpreg, SET_BIT);
+	int x;
+	u_char read_bit;
+
+	*nvram_data = 0;
+	for (x = 0; x < 16; x++) {
+		T93C46_Read_Bit(np, &read_bit, gpreg);
+
+		if (read_bit & 0x01)
+			*nvram_data |=  (0x01 << (15 - x));
+		else
+			*nvram_data &= ~(0x01 << (15 - x));
+	}
 }
 
 /*
- * Set/clear data/clock bit in GPIO0
+ *  Read Tekram NvRAM data.
  */
-__initfunc(
-static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
-)
+static int __init 
+T93C46_Read_Data(ncr_slot *np, u_short *data,int len,u_char *gpreg)
 {
-	UDELAY (5);
-	switch (bit_mode){
-	case SET_BIT:
-		*gpreg |= write_bit;
-		break;
-	case CLR_BIT:
-		*gpreg &= 0xfe;
-		break;
-	case SET_CLK:
-		*gpreg |= 0x02;
-		break;
-	case CLR_CLK:
-		*gpreg &= 0xfd;
-		break;
-
-	}
-	OUTB (nc_gpreg, *gpreg);
-	UDELAY (5);
-}
+	u_char	read_bit;
+	int	x;
 
-#undef SET_BIT 0
-#undef CLR_BIT 1
-#undef SET_CLK 2
-#undef CLR_CLK 3
+	for (x = 0; x < len; x++)  {
 
+		/* output read command and address */
+		T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
+		if (read_bit & 0x01)
+			return 1; /* Bad */
+		T93C46_Read_Word(np, &data[x], gpreg);
+		T93C46_Stop(np, gpreg);
+	}
 
-/* ---------------------------------------------------------------------
-**
-**	Try reading Tekram format nvram
-**
-** ---------------------------------------------------------------------
-**
-** GPOI0 - data in
-** GPIO1 - data out
-** GPIO2 - clock
-** GPIO4 - chip select
-**
-**	return 0 if NVRAM data OK, 1 if NVRAM data not OK
-** ---------------------------------------------------------------------
-*/
+	return 0;
+}
 
-static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg);
-static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg);
-static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg);
-static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg);
-static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg);
-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)
-)
+/*
+ *  Try reading 93C46 Tekram NVRAM.
+ */
+static int __init 
+sym_read_T93C46_nvram (ncr_slot *np, Tekram_nvram *nvram)
 {
 	u_char gpcntl, gpreg;
 	u_char old_gpcntl, old_gpreg;
-	u_short csum;
+	int retv = 1;
 
 	/* save current state of GPCNTL and GPREG */
 	old_gpreg	= INB (nc_gpreg);
@@ -11594,140 +14633,54 @@
 	OUTB (nc_gpcntl, gpcntl);
 
 	/* input all of NVRAM, 64 words */
-	csum = Tnvram_read_data(np, (u_short *) nvram,
-			sizeof(*nvram) / sizeof(short), &gpreg);
+	retv = T93C46_Read_Data(np, (u_short *) nvram,
+				sizeof(*nvram) / sizeof(short), &gpreg);
 	
 	/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
 	OUTB (nc_gpcntl, old_gpcntl);
 	OUTB (nc_gpreg,  old_gpreg);
 
-	/* check data valid */
-	if (csum != 0x1234)
-		return 1;
-
-	return 0;
+	return retv;
 }
 
 /*
- * Read Tekram NvRAM data and compute checksum.
+ *  Try reading Tekram NVRAM.
+ *  Return 0 if OK.
  */
-__initfunc(
-static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
-)
+static int __init 
+sym_read_Tekram_nvram (ncr_slot *np, u_short device_id, Tekram_nvram *nvram)
 {
-	u_char	read_bit;
+	u_char *data = (u_char *) nvram;
+	int len = sizeof(*nvram);
 	u_short	csum;
-	int	x;
-
-	for (x = 0, csum = 0; x < len; x++)  {
-
-		/* output read command and address */
-		Tnvram_Send_Command(np, 0x180 | x, &read_bit, gpreg);
-		if (read_bit & 0x01)
-			return 0; /* Force bad checksum */
-
-		Tnvram_Read_Word(np, &data[x], gpreg);
-		csum += data[x];
-
-		Tnvram_Stop(np, gpreg);
-	}
-
-	return csum;
-}
-
-/*
- * 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)
-)
-{
 	int x;
 
-	/* send 9 bits, start bit (1), command (2), address (6)  */
-	for (x = 0; x < 9; x++)
-		Tnvram_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
-
-	*read_bit = INB (nc_gpreg);
-}
-
-/*
- * READ a byte from the NVRAM
- */
-__initfunc(
-static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
-)
-{
-	int x;
-	u_char read_bit;
-
-	*nvram_data = 0;
-	for (x = 0; x < 16; x++) {
-		Tnvram_Read_Bit(np, &read_bit, gpreg);
-
-		if (read_bit & 0x01)
-			*nvram_data |=  (0x01 << (15 - x));
-		else
-			*nvram_data &= ~(0x01 << (15 - x));
+	switch (device_id) {
+	case PCI_DEVICE_ID_NCR_53C885:
+	case PCI_DEVICE_ID_NCR_53C895:
+	case PCI_DEVICE_ID_NCR_53C896:
+		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
+					  data, len);
+		break;
+	case PCI_DEVICE_ID_NCR_53C875:
+		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
+					  data, len);
+		if (!x)
+			break;
+	default:
+		x = sym_read_T93C46_nvram(np, nvram);
+		break;
 	}
-}
-
-/* 
- * Read bit from NVRAM
- */
-__initfunc(
-static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
-)
-{
-	UDELAY (2);
-	Tnvram_Clk(np, gpreg);
-	*read_bit = INB (nc_gpreg);
-}
-
-/*
- * Write bit to GPIO0
- */
-__initfunc(
-static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
-)
-{
-	if (write_bit & 0x01)
-		*gpreg |= 0x02;
-	else
-		*gpreg &= 0xfd;
-		
-	*gpreg |= 0x10;
-		
-	OUTB (nc_gpreg, *gpreg);
-	UDELAY (2);
-
-	Tnvram_Clk(np, gpreg);
-}
-
-/*
- * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
- */
-__initfunc(
-static void Tnvram_Stop(ncr_slot *np, u_char *gpreg)
-)
-{
-	*gpreg &= 0xef;
-	OUTB (nc_gpreg, *gpreg);
-	UDELAY (2);
+	if (x)
+		return 1;
 
-	Tnvram_Clk(np, gpreg);
-}
+	/* verify checksum */
+	for (x = 0, csum = 0; x < len - 1; x += 2)
+		csum += data[x] + (data[x+1] << 8);
+	if (csum != 0x1234)
+		return 1;
 
-/*
- * Pulse clock bit in GPIO0
- */
-__initfunc(
-static void Tnvram_Clk(ncr_slot *np, u_char *gpreg)
-)
-{
-	OUTB (nc_gpreg, *gpreg | 0x04);
-	UDELAY (2);
-	OUTB (nc_gpreg, *gpreg);
+	return 0;
 }
 
 #endif	/* SCSI_NCR_NVRAM_SUPPORT */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sym53c8xx.h linux.18p8/drivers/scsi/sym53c8xx.h
--- linux.vanilla/drivers/scsi/sym53c8xx.h	Wed May  3 22:31:20 2000
+++ linux.18p8/drivers/scsi/sym53c8xx.h	Fri Sep 15 15:13:38 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-2000  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 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sym53c8xx_comm.h linux.18p8/drivers/scsi/sym53c8xx_comm.h
--- linux.vanilla/drivers/scsi/sym53c8xx_comm.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/scsi/sym53c8xx_comm.h	Sun Sep 10 14:49:10 2000
@@ -0,0 +1,2717 @@
+/******************************************************************************
+**  High Performance device driver for the Symbios 53C896 controller.
+**
+**  Copyright (C) 1998-2000  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 
+**  revisions of 53C815 controllers.
+**
+**  This driver is based on the Linux port of the FreeBSD ncr driver.
+** 
+**  Copyright (C) 1994  Wolfgang Stanglmeier
+**  
+**-----------------------------------------------------------------------------
+**  
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+**
+**  The Linux port of the FreeBSD ncr driver has been achieved in 
+**  november 1995 by:
+**
+**          Gerard Roudier              <groudier@club-internet.fr>
+**
+**  Being given that this driver originates from the FreeBSD version, and
+**  in order to keep synergy on both, any suggested enhancements and corrections
+**  received on Linux are automatically a potential candidate for the FreeBSD 
+**  version.
+**
+**  The original driver has been written for 386bsd and FreeBSD by
+**          Wolfgang Stanglmeier        <wolf@cologne.de>
+**          Stefan Esser                <se@mi.Uni-Koeln.de>
+**
+**-----------------------------------------------------------------------------
+**
+**  Major contributions:
+**  --------------------
+**
+**  NVRAM detection and reading.
+**    Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+**
+*******************************************************************************
+*/
+
+/*
+**	This file contains definitions and code that the 
+**	sym53c8xx and ncr53c8xx drivers should share.
+**	The sharing will be achieved in a further version  
+**	of the driver bundle. For now, only the ncr53c8xx 
+**	driver includes	this file.
+*/
+
+#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
+#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
+
+/*==========================================================
+**
+**	Hmmm... What complex some PCI-HOST bridges actually 
+**	are, despite the fact that the PCI specifications 
+**	are looking so smart and simple! ;-)
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,47)
+#define SCSI_NCR_DYNAMIC_DMA_MAPPING
+#endif
+
+/*==========================================================
+**
+**	Miscallaneous defines.
+**
+**==========================================================
+*/
+
+#define u_char		unsigned char
+#define u_short		unsigned short
+#define u_int		unsigned int
+#define u_long		unsigned long
+
+#ifndef bcopy
+#define bcopy(s, d, n)	memcpy((d), (s), (n))
+#endif
+
+#ifndef bcmp
+#define bcmp(s, d, n)	memcmp((d), (s), (n))
+#endif
+
+#ifndef bzero
+#define bzero(d, n)	memset((d), 0, (n))
+#endif
+ 
+#ifndef offsetof
+#define offsetof(t, m)	((size_t) (&((t *)0)->m))
+#endif
+
+/*==========================================================
+**
+**	assert ()
+**
+**==========================================================
+**
+**	modified copy from 386bsd:/usr/include/sys/assert.h
+**
+**----------------------------------------------------------
+*/
+
+#define	assert(expression) { \
+	if (!(expression)) { \
+		(void)panic( \
+			"assertion \"%s\" failed: file \"%s\", line %d\n", \
+			#expression, \
+			__FILE__, __LINE__); \
+	} \
+}
+
+/*==========================================================
+**
+**	Debugging tags
+**
+**==========================================================
+*/
+
+#define DEBUG_ALLOC    (0x0001)
+#define DEBUG_PHASE    (0x0002)
+#define DEBUG_QUEUE    (0x0008)
+#define DEBUG_RESULT   (0x0010)
+#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_SCATTER  (0x0800)
+#define DEBUG_IC        (0x1000)
+
+/*
+**    Enable/Disable debug messages.
+**    Can be changed at runtime too.
+*/
+
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
+static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
+	#define DEBUG_FLAGS ncr_debug
+#else
+	#define DEBUG_FLAGS	SCSI_NCR_DEBUG_FLAGS
+#endif
+
+/*==========================================================
+**
+**	A la VMS/CAM-3 queue management.
+**	Implemented from linux list management.
+**
+**==========================================================
+*/
+
+typedef struct xpt_quehead {
+	struct xpt_quehead *flink;	/* Forward  pointer */
+	struct xpt_quehead *blink;	/* Backward pointer */
+} XPT_QUEHEAD;
+
+#define xpt_que_init(ptr) do { \
+	(ptr)->flink = (ptr); (ptr)->blink = (ptr); \
+} while (0)
+
+static inline void __xpt_que_add(struct xpt_quehead * new,
+	struct xpt_quehead * blink,
+	struct xpt_quehead * flink)
+{
+	flink->blink	= new;
+	new->flink	= flink;
+	new->blink	= blink;
+	blink->flink	= new;
+}
+
+static inline void __xpt_que_del(struct xpt_quehead * blink,
+	struct xpt_quehead * flink)
+{
+	flink->blink = blink;
+	blink->flink = flink;
+}
+
+static inline int xpt_que_empty(struct xpt_quehead *head)
+{
+	return head->flink == head;
+}
+
+static inline void xpt_que_splice(struct xpt_quehead *list,
+	struct xpt_quehead *head)
+{
+	struct xpt_quehead *first = list->flink;
+
+	if (first != list) {
+		struct xpt_quehead *last = list->blink;
+		struct xpt_quehead *at   = head->flink;
+
+		first->blink = head;
+		head->flink  = first;
+
+		last->flink = at;
+		at->blink   = last;
+	}
+}
+
+#define xpt_que_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+
+#define xpt_insque(new, pos)		__xpt_que_add(new, pos, (pos)->flink)
+
+#define xpt_remque(el)			__xpt_que_del((el)->blink, (el)->flink)
+
+#define xpt_insque_head(new, head)	__xpt_que_add(new, head, (head)->flink)
+
+static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head)
+{
+	struct xpt_quehead *elem = head->flink;
+
+	if (elem != head)
+		__xpt_que_del(head, elem->flink);
+	else
+		elem = 0;
+	return elem;
+}
+
+#define xpt_insque_tail(new, head)	__xpt_que_add(new, (head)->blink, head)
+
+static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
+{
+	struct xpt_quehead *elem = head->blink;
+
+	if (elem != head)
+		__xpt_que_del(elem->blink, head);
+	else
+		elem = 0;
+	return elem;
+}
+
+/*==========================================================
+**
+**	Simple Wrapper to kernel PCI bus interface.
+**
+**	This wrapper allows to get rid of old kernel PCI 
+**	interface and still allows to preserve linux-2.0 
+**	compatibilty. In fact, it is mostly an incomplete 
+**	emulation of the new PCI code for pre-2.2 kernels.
+**	When kernel-2.0 support will be dropped, we will 
+**	just have to remove most of this code.
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0)
+
+typedef struct pci_dev *pcidev_t;
+#define PCIDEV_NULL		(0)
+#define PciBusNumber(d)		(d)->bus->number
+#define PciDeviceFn(d)		(d)->devfn
+#define PciVendorId(d)		(d)->vendor
+#define PciDeviceId(d)		(d)->device
+#define PciIrqLine(d)		(d)->irq
+
+#if 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;
+}
+#else
+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) {
+#if BITS_PER_LONG > 32
+		*base |= (((u_long)pdev->base_address[index]) << 32);
+#endif
+		++index;
+	}
+	return index;
+}
+#endif
+
+#else	/* Incomplete emulation of current PCI code for pre-2.2 kernels */
+
+typedef unsigned int pcidev_t;
+#define PCIDEV_NULL		(~0u)
+#define PciBusNumber(d)		((d)>>8)
+#define PciDeviceFn(d)		((d)&0xff)
+#define __PciDev(busn, devfn)	(((busn)<<8)+(devfn))
+
+#define pci_present pcibios_present
+
+#define pci_read_config_byte(d, w, v) \
+	pcibios_read_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_read_config_word(d, w, v) \
+	pcibios_read_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_read_config_dword(d, w, v) \
+	pcibios_read_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
+
+#define pci_write_config_byte(d, w, v) \
+	pcibios_write_config_byte(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_write_config_word(d, w, v) \
+	pcibios_write_config_word(PciBusNumber(d), PciDeviceFn(d), w, v)
+#define pci_write_config_dword(d, w, v) \
+	pcibios_write_config_dword(PciBusNumber(d), PciDeviceFn(d), w, v)
+
+static pcidev_t __init
+pci_find_device(unsigned int vendor, unsigned int device, pcidev_t prev)
+{
+	static unsigned short pci_index;
+	int retv;
+	unsigned char bus_number, device_fn;
+
+	if (prev == PCIDEV_NULL)
+		pci_index = 0;
+	else
+		++pci_index;
+	retv = pcibios_find_device (vendor, device, pci_index,
+				    &bus_number, &device_fn);
+	return retv ? PCIDEV_NULL : __PciDev(bus_number, device_fn);
+}
+
+static u_short __init PciVendorId(pcidev_t dev)
+{
+	u_short vendor_id;
+	pci_read_config_word(dev, PCI_VENDOR_ID, &vendor_id);
+	return vendor_id;
+}
+
+static u_short __init PciDeviceId(pcidev_t dev)
+{
+	u_short device_id;
+	pci_read_config_word(dev, PCI_DEVICE_ID, &device_id);
+	return device_id;
+}
+
+static u_int __init PciIrqLine(pcidev_t dev)
+{
+	u_char irq;
+	pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	return irq;
+}
+
+static int __init 
+pci_get_base_address(pcidev_t dev, int offset, u_long *base)
+{
+	u_int32 tmp;
+	
+	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
+	*base = tmp;
+	offset += sizeof(u_int32);
+	if ((tmp & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+		pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + offset, &tmp);
+		*base |= (((u_long)tmp) << 32);
+#endif
+		offset += sizeof(u_int32);
+	}
+	return offset;
+}
+
+#endif	/* LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) */
+
+/*==========================================================
+**
+**	SMP threading.
+**
+**	Assuming that SMP systems are generally high end 
+**	systems and may use several SCSI adapters, we are 
+**	using one lock per controller instead of some global 
+**	one. For the moment (linux-2.1.95), driver's entry 
+**	points are called with the 'io_request_lock' lock 
+**	held, so:
+**	- We are uselessly loosing a couple of micro-seconds 
+**	  to lock the controller data structure.
+**	- But the driver is not broken by design for SMP and 
+**	  so can be more resistant to bugs or bad changes in 
+**	  the IO sub-system code.
+**	- A small advantage could be that the interrupt code 
+**	  is grained as wished (e.g.: by controller).
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+spinlock_t DRIVER_SMP_LOCK = SPIN_LOCK_UNLOCKED;
+#define	NCR_LOCK_DRIVER(flags)     spin_lock_irqsave(&DRIVER_SMP_LOCK, flags)
+#define	NCR_UNLOCK_DRIVER(flags)   \
+		spin_unlock_irqrestore(&DRIVER_SMP_LOCK, flags)
+
+#define NCR_INIT_LOCK_NCB(np)      spin_lock_init(&np->smp_lock)
+#define	NCR_LOCK_NCB(np, flags)    spin_lock_irqsave(&np->smp_lock, flags)
+#define	NCR_UNLOCK_NCB(np, flags)  spin_unlock_irqrestore(&np->smp_lock, flags)
+
+#define	NCR_LOCK_SCSI_DONE(np, flags) \
+		spin_lock_irqsave(&io_request_lock, flags)
+#define	NCR_UNLOCK_SCSI_DONE(np, flags) \
+		spin_unlock_irqrestore(&io_request_lock, flags)
+
+#else
+
+#define	NCR_LOCK_DRIVER(flags)     do { save_flags(flags); cli(); } while (0)
+#define	NCR_UNLOCK_DRIVER(flags)   do { restore_flags(flags); } while (0)
+
+#define	NCR_INIT_LOCK_NCB(np)      do { } while (0)
+#define	NCR_LOCK_NCB(np, flags)    do { save_flags(flags); cli(); } while (0)
+#define	NCR_UNLOCK_NCB(np, flags)  do { restore_flags(flags); } while (0)
+
+#define	NCR_LOCK_SCSI_DONE(np, flags)    do {;} while (0)
+#define	NCR_UNLOCK_SCSI_DONE(np, flags)  do {;} while (0)
+
+#endif
+
+/*==========================================================
+**
+**	Memory mapped IO
+**
+**	Since linux-2.1, we must use ioremap() to map the io 
+**	memory space and iounmap() to unmap it. This allows 
+**	portability. Linux 1.3.X and 2.0.X allow to remap 
+**	physical pages addresses greater than the highest 
+**	physical memory address to kernel virtual pages with 
+**	vremap() / vfree(). That was not portable but worked 
+**	with i386 architecture.
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
+#define ioremap vremap
+#define iounmap vfree
+#endif
+
+#ifdef __sparc__
+#  include <asm/irq.h>
+#  define pcivtobus(p)			bus_dvma_to_mem(p)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
+#elif defined(__alpha__)
+#  define pcivtobus(p)			((p) & 0xfffffffful)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
+#else	/* others */
+#  define pcivtobus(p)			(p)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
+#endif
+
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+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;
+	u_long page_remapped	= (u_long) ioremap(page_base, page_offs+size);
+
+	return page_remapped? (page_remapped + page_offs) : 0UL;
+}
+
+static void __init unmap_pci_mem(u_long vaddr, u_long size)
+{
+	if (vaddr)
+		iounmap((void *) (vaddr & PAGE_MASK));
+}
+
+#endif /* not def SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
+
+/*==========================================================
+**
+**	Insert a delay in micro-seconds and milli-seconds.
+**
+**	Under Linux, udelay() is restricted to delay < 
+**	1 milli-second. In fact, it generally works for up 
+**	to 1 second delay. Since 2.1.105, the mdelay() function 
+**	is provided for delays in milli-seconds.
+**	Under 2.0 kernels, udelay() is an inline function 
+**	that is very inaccurate on Pentium processors.
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105)
+#define UDELAY udelay
+#define MDELAY mdelay
+#else
+static void UDELAY(long us) { udelay(us); }
+static void MDELAY(long ms) { while (ms--) UDELAY(1000); }
+#endif
+
+/*==========================================================
+**
+**	Simple power of two buddy-like allocator.
+**
+**	This simple code is not intended to be fast, but to 
+**	provide power of 2 aligned memory allocations.
+**	Since the SCRIPTS processor only supplies 8 bit 
+**	arithmetic, this allocator allows simple and fast 
+**	address calculations  from the SCRIPTS code.
+**	In addition, cache line alignment is guaranteed for 
+**	power of 2 cache line size.
+**	Enhanced in linux-2.3.44 to provide a memory pool 
+**	per pcidev to support dynamic dma mapping. (I would 
+**	have preferred a real bus astraction, btw).
+**
+**==========================================================
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
+#define __GetFreePages(flags, order) __get_free_pages(flags, order)
+#else
+#define __GetFreePages(flags, order) __get_free_pages(flags, order, 0)
+#endif
+
+#define MEMO_SHIFT	4	/* 16 bytes minimum memory chunk */
+#if PAGE_SIZE >= 8192
+#define MEMO_PAGE_ORDER	0	/* 1 PAGE  maximum */
+#else
+#define MEMO_PAGE_ORDER	1	/* 2 PAGES maximum */
+#endif
+#define MEMO_FREE_UNUSED	/* Free unused pages immediately */
+#define MEMO_WARN	1
+#define MEMO_GFP_FLAGS	GFP_ATOMIC
+#define MEMO_CLUSTER_SHIFT	(PAGE_SHIFT+MEMO_PAGE_ORDER)
+#define MEMO_CLUSTER_SIZE	(1UL << MEMO_CLUSTER_SHIFT)
+#define MEMO_CLUSTER_MASK	(MEMO_CLUSTER_SIZE-1)
+
+typedef u_long m_addr_t;	/* Enough bits to bit-hack addresses */
+typedef pcidev_t m_bush_t;	/* Something that addresses DMAable */
+
+typedef struct m_link {		/* Link between free memory chunks */
+	struct m_link *next;
+} m_link_s;
+
+#ifdef	SCSI_NCR_DYNAMIC_DMA_MAPPING
+typedef struct m_vtob {		/* Virtual to Bus address translation */
+	struct m_vtob *next;
+	m_addr_t vaddr;
+	m_addr_t baddr;
+} m_vtob_s;
+#define VTOB_HASH_SHIFT		5
+#define VTOB_HASH_SIZE		(1UL << VTOB_HASH_SHIFT)
+#define VTOB_HASH_MASK		(VTOB_HASH_SIZE-1)
+#define VTOB_HASH_CODE(m)	\
+	((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK)
+#endif
+
+typedef struct m_pool {		/* Memory pool of a given kind */
+#ifdef	SCSI_NCR_DYNAMIC_DMA_MAPPING
+	m_bush_t bush;
+	m_addr_t (*getp)(struct m_pool *);
+	void (*freep)(struct m_pool *, m_addr_t);
+#define M_GETP()		mp->getp(mp)
+#define M_FREEP(p)		mp->freep(mp, p)
+#define GetPages()		__GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
+#define FreePages(p)		free_pages(p, MEMO_PAGE_ORDER)
+	int nump;
+	m_vtob_s *(vtob[VTOB_HASH_SIZE]);
+	struct m_pool *next;
+#else
+#define M_GETP()		__GetFreePages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER)
+#define M_FREEP(p)		free_pages(p, MEMO_PAGE_ORDER)
+#endif	/* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+	struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
+} m_pool_s;
+
+static void *___m_alloc(m_pool_s *mp, int size)
+{
+	int i = 0;
+	int s = (1 << MEMO_SHIFT);
+	int j;
+	m_addr_t a;
+	m_link_s *h = mp->h;
+
+	if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
+		return 0;
+
+	while (size > s) {
+		s <<= 1;
+		++i;
+	}
+
+	j = i;
+	while (!h[j].next) {
+		if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
+			h[j].next = (m_link_s *) M_GETP();
+			if (h[j].next)
+				h[j].next->next = 0;
+			break;
+		}
+		++j;
+		s <<= 1;
+	}
+	a = (m_addr_t) h[j].next;
+	if (a) {
+		h[j].next = h[j].next->next;
+		while (j > i) {
+			j -= 1;
+			s >>= 1;
+			h[j].next = (m_link_s *) (a+s);
+			h[j].next->next = 0;
+		}
+	}
+#ifdef DEBUG
+	printk("___m_alloc(%d) = %p\n", size, (void *) a);
+#endif
+	return (void *) a;
+}
+
+static void ___m_free(m_pool_s *mp, void *ptr, int size)
+{
+	int i = 0;
+	int s = (1 << MEMO_SHIFT);
+	m_link_s *q;
+	m_addr_t a, b;
+	m_link_s *h = mp->h;
+
+#ifdef DEBUG
+	printk("___m_free(%p, %d)\n", ptr, size);
+#endif
+
+	if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
+		return;
+
+	while (size > s) {
+		s <<= 1;
+		++i;
+	}
+
+	a = (m_addr_t) ptr;
+
+	while (1) {
+#ifdef MEMO_FREE_UNUSED
+		if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
+			M_FREEP(a);
+			break;
+		}
+#endif
+		b = a ^ s;
+		q = &h[i];
+		while (q->next && q->next != (m_link_s *) b) {
+			q = q->next;
+		}
+		if (!q->next) {
+			((m_link_s *) a)->next = h[i].next;
+			h[i].next = (m_link_s *) a;
+			break;
+		}
+		q->next = q->next->next;
+		a = a & b;
+		s <<= 1;
+		++i;
+	}
+}
+
+static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags)
+{
+	void *p;
+
+	p = ___m_alloc(mp, size);
+
+	if (DEBUG_FLAGS & DEBUG_ALLOC)
+		printk ("new %-10s[%4d] @%p.\n", name, size, p);
+
+	if (p)
+		bzero(p, size);
+	else if (uflags & MEMO_WARN)
+		printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size);
+
+	return p;
+}
+
+#define __m_calloc(mp, s, n)	__m_calloc2(mp, s, n, MEMO_WARN)
+
+static void __m_free(m_pool_s *mp, void *ptr, int size, char *name)
+{
+	if (DEBUG_FLAGS & DEBUG_ALLOC)
+		printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
+
+	___m_free(mp, ptr, size);
+
+}
+
+/*
+ * With pci bus iommu support, we use a default pool of unmapped memory 
+ * for memory we donnot need to DMA from/to and one pool per pcidev for 
+ * memory accessed by the PCI chip. `mp0' is the default not DMAable pool.
+ */
+
+#ifndef	SCSI_NCR_DYNAMIC_DMA_MAPPING
+
+static m_pool_s mp0;
+
+#else
+
+static m_addr_t ___mp0_getp(m_pool_s *mp)
+{
+	m_addr_t m = GetPages();
+	if (m)
+		++mp->nump;
+	return m;
+}
+
+static void ___mp0_freep(m_pool_s *mp, m_addr_t m)
+{
+	FreePages(m);
+	--mp->nump;
+}
+
+static m_pool_s mp0 = {0, ___mp0_getp, ___mp0_freep};
+
+#endif	/* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+static void *m_calloc(int size, char *name)
+{
+	u_long flags;
+	void *m;
+	NCR_LOCK_DRIVER(flags);
+	m = __m_calloc(&mp0, size, name);
+	NCR_UNLOCK_DRIVER(flags);
+	return m;
+}
+
+static void m_free(void *ptr, int size, char *name)
+{
+	u_long flags;
+	NCR_LOCK_DRIVER(flags);
+	__m_free(&mp0, ptr, size, name);
+	NCR_UNLOCK_DRIVER(flags);
+}
+
+/*
+ * DMAable pools.
+ */
+
+#ifndef	SCSI_NCR_DYNAMIC_DMA_MAPPING
+
+/* Without pci bus iommu support, all the memory is assumed DMAable */
+
+#define __m_calloc_dma(b, s, n)		m_calloc(s, n)
+#define __m_free_dma(b, p, s, n)	m_free(p, s, n)
+#define __vtobus(b, p)			virt_to_bus(p)
+
+#else
+
+/*
+ * With pci bus iommu support, we maintain one pool per pcidev and a 
+ * hashed reverse table for virtual to bus physical address translations.
+ */
+static m_addr_t ___dma_getp(m_pool_s *mp)
+{
+	m_addr_t vp;
+	m_vtob_s *vbp;
+
+	vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB");
+	if (vbp) {
+		dma_addr_t daddr;
+		vp = (m_addr_t) pci_alloc_consistent(mp->bush,
+						PAGE_SIZE<<MEMO_PAGE_ORDER,
+						&daddr);
+		if (vp) {
+			int hc = VTOB_HASH_CODE(vp);
+			vbp->vaddr = vp;
+			vbp->baddr = daddr;
+			vbp->next = mp->vtob[hc];
+			mp->vtob[hc] = vbp;
+			++mp->nump;
+			return vp;
+		}
+	}
+	if (vbp)
+		__m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+	return 0;
+}
+
+static void ___dma_freep(m_pool_s *mp, m_addr_t m)
+{
+	m_vtob_s **vbpp, *vbp;
+	int hc = VTOB_HASH_CODE(m);
+
+	vbpp = &mp->vtob[hc];
+	while (*vbpp && (*vbpp)->vaddr != m)
+		vbpp = &(*vbpp)->next;
+	if (*vbpp) {
+		vbp = *vbpp;
+		*vbpp = (*vbpp)->next;
+		pci_free_consistent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER,
+				    (void *)vbp->vaddr, (dma_addr_t)vbp->baddr);
+		__m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+		--mp->nump;
+	}
+}
+
+static inline m_pool_s *___get_dma_pool(m_bush_t bush)
+{
+	m_pool_s *mp;
+	for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next);
+	return mp;
+}
+
+static m_pool_s *___cre_dma_pool(m_bush_t bush)
+{
+	m_pool_s *mp;
+	mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL");
+	if (mp) {
+		bzero(mp, sizeof(*mp));
+		mp->bush = bush;
+		mp->getp = ___dma_getp;
+		mp->freep = ___dma_freep;
+		mp->next = mp0.next;
+		mp0.next = mp;
+	}
+	return mp;
+}
+
+static void ___del_dma_pool(m_pool_s *p)
+{
+	struct m_pool **pp = &mp0.next;
+
+	while (*pp && *pp != p)
+		pp = &(*pp)->next;
+	if (*pp) {
+		*pp = (*pp)->next;
+		__m_free(&mp0, p, sizeof(*p), "MPOOL");
+	}
+}
+
+static void *__m_calloc_dma(m_bush_t bush, int size, char *name)
+{
+	u_long flags;
+	struct m_pool *mp;
+	void *m = 0;
+
+	NCR_LOCK_DRIVER(flags);
+	mp = ___get_dma_pool(bush);
+	if (!mp)
+		mp = ___cre_dma_pool(bush);
+	if (mp)
+		m = __m_calloc(mp, size, name);
+	if (mp && !mp->nump)
+		___del_dma_pool(mp);
+	NCR_UNLOCK_DRIVER(flags);
+
+	return m;
+}
+
+static void __m_free_dma(m_bush_t bush, void *m, int size, char *name)
+{
+	u_long flags;
+	struct m_pool *mp;
+
+	NCR_LOCK_DRIVER(flags);
+	mp = ___get_dma_pool(bush);
+	if (mp)
+		__m_free(mp, m, size, name);
+	if (mp && !mp->nump)
+		___del_dma_pool(mp);
+	NCR_UNLOCK_DRIVER(flags);
+}
+
+static m_addr_t __vtobus(m_bush_t bush, void *m)
+{
+	u_long flags;
+	m_pool_s *mp;
+	int hc = VTOB_HASH_CODE(m);
+	m_vtob_s *vp = 0;
+	m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK;
+
+	NCR_LOCK_DRIVER(flags);
+	mp = ___get_dma_pool(bush);
+	if (mp) {
+		vp = mp->vtob[hc];
+		while (vp && (m_addr_t) vp->vaddr != a)
+			vp = vp->next;
+	}
+	NCR_UNLOCK_DRIVER(flags);
+	return vp ? vp->baddr + (((m_addr_t) m) - a) : 0;
+}
+
+#endif	/* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+#define _m_calloc_dma(np, s, n)		__m_calloc_dma(np->pdev, s, n)
+#define _m_free_dma(np, p, s, n)	__m_free_dma(np->pdev, p, s, n)
+#define m_calloc_dma(s, n)		_m_calloc_dma(np, s, n)
+#define m_free_dma(p, s, n)		_m_free_dma(np, p, s, n)
+#define _vtobus(np, p)			__vtobus(np->pdev, p)
+#define vtobus(p)			_vtobus(np, p)
+
+/*
+ *  Deal with DMA mapping/unmapping.
+ */
+
+#ifndef SCSI_NCR_DYNAMIC_DMA_MAPPING
+
+/* Linux versions prior to pci bus iommu kernel interface */
+
+#define __unmap_scsi_data(pdev, cmd)	do {; } while (0)
+#define __map_scsi_single_data(pdev, cmd) (__vtobus(pdev,(cmd)->request_buffer))
+#define __map_scsi_sg_data(pdev, cmd)	((cmd)->use_sg)
+#define __sync_scsi_data(pdev, cmd)	do {; } while (0)
+
+#define scsi_sg_dma_address(sc)		vtobus((sc)->address)
+#define scsi_sg_dma_len(sc)		((sc)->length)
+
+#else
+
+/* Linux version with pci bus iommu kernel interface */
+
+/* To keep track of the dma mapping (sg/single) that has been set */
+#define __data_mapped	SCp.phase
+#define __data_mapping	SCp.have_data_in
+
+static void __unmap_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	switch(cmd->__data_mapped) {
+	case 2:
+		pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+		break;
+	case 1:
+		pci_unmap_single(pdev, cmd->__data_mapping,
+				 cmd->request_bufflen, dma_dir);
+		break;
+	}
+	cmd->__data_mapped = 0;
+}
+
+static u_long __map_scsi_single_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+	dma_addr_t mapping;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	if (cmd->request_bufflen == 0)
+		return 0;
+
+	mapping = pci_map_single(pdev, cmd->request_buffer,
+				 cmd->request_bufflen, dma_dir);
+	cmd->__data_mapped = 1;
+	cmd->__data_mapping = mapping;
+
+	return mapping;
+}
+
+static int __map_scsi_sg_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+	int use_sg;
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	if (cmd->use_sg == 0)
+		return 0;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+	cmd->__data_mapped = 2;
+	cmd->__data_mapping = use_sg;
+
+	return use_sg;
+}
+
+static void __sync_scsi_data(pcidev_t pdev, Scsi_Cmnd *cmd)
+{
+	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+
+	switch(cmd->__data_mapped) {
+	case 2:
+		pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+		break;
+	case 1:
+		pci_dma_sync_single(pdev, cmd->__data_mapping,
+				    cmd->request_bufflen, dma_dir);
+		break;
+	}
+}
+
+#define scsi_sg_dma_address(sc)		sg_dma_address(sc)
+#define scsi_sg_dma_len(sc)		sg_dma_len(sc)
+
+#endif	/* SCSI_NCR_DYNAMIC_DMA_MAPPING */
+
+#define unmap_scsi_data(np, cmd)	__unmap_scsi_data(np->pdev, cmd)
+#define map_scsi_single_data(np, cmd)	__map_scsi_single_data(np->pdev, cmd)
+#define map_scsi_sg_data(np, cmd)	__map_scsi_sg_data(np->pdev, cmd)
+#define sync_scsi_data(np, cmd)		__sync_scsi_data(np->pdev, cmd)
+
+/*==========================================================
+**
+**	SCSI data transfer direction
+**
+**	Until some linux kernel version near 2.3.40, 
+**	low-level scsi drivers were not told about data 
+**	transfer direction. We check the existence of this 
+**	feature that has been expected for a _long_ time by 
+**	all SCSI driver developers by just testing against 
+**	the definition of SCSI_DATA_UNKNOWN. Indeed this is 
+**	a hack, but testing against a kernel version would 
+**	have been a shame. ;-)
+**
+**==========================================================
+*/
+#ifdef	SCSI_DATA_UNKNOWN
+
+#define scsi_data_direction(cmd)	(cmd->sc_data_direction)
+
+#else
+
+#define	SCSI_DATA_UNKNOWN	0
+#define	SCSI_DATA_WRITE		1
+#define	SCSI_DATA_READ		2
+#define	SCSI_DATA_NONE		3
+
+static __inline__ int scsi_data_direction(Scsi_Cmnd *cmd)
+{
+	int direction;
+
+	switch((int) cmd->cmnd[0]) {
+	case 0x08:  /*	READ(6)				08 */
+	case 0x28:  /*	READ(10)			28 */
+	case 0xA8:  /*	READ(12)			A8 */
+		direction = SCSI_DATA_READ;
+		break;
+	case 0x0A:  /*	WRITE(6)			0A */
+	case 0x2A:  /*	WRITE(10)			2A */
+	case 0xAA:  /*	WRITE(12)			AA */
+		direction = SCSI_DATA_WRITE;
+		break;
+	default:
+		direction = SCSI_DATA_UNKNOWN;
+		break;
+	}
+
+	return direction;
+}
+
+#endif	/* SCSI_DATA_UNKNOWN */
+
+/*==========================================================
+**
+**	Driver setup.
+**
+**	This structure is initialized from linux config 
+**	options. It can be overridden at boot-up by the boot 
+**	command line.
+**
+**==========================================================
+*/
+static struct ncr_driver_setup
+	driver_setup			= SCSI_NCR_DRIVER_SETUP;
+
+#ifdef	SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+static struct ncr_driver_setup
+	driver_safe_setup __initdata	= SCSI_NCR_DRIVER_SAFE_SETUP;
+#endif
+
+#define initverbose (driver_setup.verbose)
+#define bootverbose (np->verbose)
+
+
+/*==========================================================
+**
+**	Structures used by the detection routine to transmit 
+**	device configuration to the attach function.
+**
+**==========================================================
+*/
+typedef struct {
+	int	bus;
+	u_char	device_fn;
+	u_long	base;
+	u_long	base_2;
+	u_long	io_port;
+	int	irq;
+/* port and reg fields to use INB, OUTB macros */
+	u_long	base_io;
+	volatile struct ncr_reg	*reg;
+} ncr_slot;
+
+/*==========================================================
+**
+**	Structure used to store the NVRAM content.
+**
+**==========================================================
+*/
+typedef struct {
+	int type;
+#define	SCSI_NCR_SYMBIOS_NVRAM	(1)
+#define	SCSI_NCR_TEKRAM_NVRAM	(2)
+#ifdef	SCSI_NCR_NVRAM_SUPPORT
+	union {
+		Symbios_nvram Symbios;
+		Tekram_nvram Tekram;
+	} data;
+#endif
+} ncr_nvram;
+
+/*==========================================================
+**
+**	Structure used by detection routine to save data on 
+**	each detected board for attach.
+**
+**==========================================================
+*/
+typedef struct {
+	pcidev_t  pdev;
+	ncr_slot  slot;
+	ncr_chip  chip;
+	ncr_nvram *nvram;
+	u_char host_id;
+#ifdef	SCSI_NCR_PQS_PDS_SUPPORT
+	u_char pqs_pds;
+#endif
+	int attach_done;
+} ncr_device;
+
+static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device);
+
+/*==========================================================
+**
+**	NVRAM detection and reading.
+**	 
+**	Currently supported:
+**	- 24C16 EEPROM with both Symbios and Tekram layout.
+**	- 93C46 EEPROM with Tekram layout.
+**
+**==========================================================
+*/
+
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+/*
+ *  24C16 EEPROM reading.
+ *
+ *  GPOI0 - data in/data out
+ *  GPIO1 - clock
+ *  Symbios NVRAM wiring now also used by Tekram.
+ */
+
+#define SET_BIT 0
+#define CLR_BIT 1
+#define SET_CLK 2
+#define CLR_CLK 3
+
+/*
+ *  Set/clear data/clock bit in GPIO0
+ */
+static void __init
+S24C16_set_bit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
+{
+	UDELAY (5);
+	switch (bit_mode){
+	case SET_BIT:
+		*gpreg |= write_bit;
+		break;
+	case CLR_BIT:
+		*gpreg &= 0xfe;
+		break;
+	case SET_CLK:
+		*gpreg |= 0x02;
+		break;
+	case CLR_CLK:
+		*gpreg &= 0xfd;
+		break;
+
+	}
+	OUTB (nc_gpreg, *gpreg);
+	UDELAY (5);
+}
+
+/*
+ *  Send START condition to NVRAM to wake it up.
+ */
+static void __init S24C16_start(ncr_slot *np, u_char *gpreg)
+{
+	S24C16_set_bit(np, 1, gpreg, SET_BIT);
+	S24C16_set_bit(np, 0, gpreg, SET_CLK);
+	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
+	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
+}
+
+/*
+ *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
+ */
+static void __init S24C16_stop(ncr_slot *np, u_char *gpreg)
+{
+	S24C16_set_bit(np, 0, gpreg, SET_CLK);
+	S24C16_set_bit(np, 1, gpreg, SET_BIT);
+}
+
+/*
+ *  Read or write a bit to the NVRAM,
+ *  read if GPIO0 input else write if GPIO0 output
+ */
+static void __init 
+S24C16_do_bit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
+{
+	S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
+	S24C16_set_bit(np, 0, gpreg, SET_CLK);
+	if (read_bit)
+		*read_bit = INB (nc_gpreg);
+	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
+	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
+}
+
+/*
+ *  Output an ACK to the NVRAM after reading,
+ *  change GPIO0 to output and when done back to an input
+ */
+static void __init
+S24C16_write_ack(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
+{
+	OUTB (nc_gpcntl, *gpcntl & 0xfe);
+	S24C16_do_bit(np, 0, write_bit, gpreg);
+	OUTB (nc_gpcntl, *gpcntl);
+}
+
+/*
+ *  Input an ACK from NVRAM after writing,
+ *  change GPIO0 to input and when done back to an output
+ */
+static void __init 
+S24C16_read_ack(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
+{
+	OUTB (nc_gpcntl, *gpcntl | 0x01);
+	S24C16_do_bit(np, read_bit, 1, gpreg);
+	OUTB (nc_gpcntl, *gpcntl);
+}
+
+/*
+ *  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
+ */
+static void __init 
+S24C16_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, 
+		  u_char *gpreg, u_char *gpcntl)
+{
+	int x;
+	
+	for (x = 0; x < 8; x++)
+		S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
+		
+	S24C16_read_ack(np, ack_data, gpreg, gpcntl);
+}
+
+/*
+ *  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
+ */
+static void __init 
+S24C16_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;
+
+	*read_data = 0;
+	for (x = 0; x < 8; x++) {
+		S24C16_do_bit(np, &read_bit, 1, gpreg);
+		*read_data |= ((read_bit & 0x01) << (7 - x));
+	}
+
+	S24C16_write_ack(np, ack_data, gpreg, gpcntl);
+}
+
+/*
+ *  Read 'len' bytes starting at 'offset'.
+ */
+static int __init 
+sym_read_S24C16_nvram (ncr_slot *np, int offset, u_char *data, int len)
+{
+	u_char	gpcntl, gpreg;
+	u_char	old_gpcntl, old_gpreg;
+	u_char	ack_data;
+	int	retv = 1;
+	int	x;
+
+	/* save current state of GPCNTL and GPREG */
+	old_gpreg	= INB (nc_gpreg);
+	old_gpcntl	= INB (nc_gpcntl);
+	gpcntl		= old_gpcntl & 0xfc;
+
+	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
+	OUTB (nc_gpreg,  old_gpreg);
+	OUTB (nc_gpcntl, gpcntl);
+
+	/* this is to set NVRAM into a known state with GPIO0/1 both low */
+	gpreg = old_gpreg;
+	S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
+	S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
+		
+	/* now set NVRAM inactive with GPIO0/1 both high */
+	S24C16_stop(np, &gpreg);
+	
+	/* activate NVRAM */
+	S24C16_start(np, &gpreg);
+
+	/* write device code and random address MSB */
+	S24C16_write_byte(np, &ack_data,
+		0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
+	if (ack_data & 0x01)
+		goto out;
+
+	/* write random address LSB */
+	S24C16_write_byte(np, &ack_data,
+		offset & 0xff, &gpreg, &gpcntl);
+	if (ack_data & 0x01)
+		goto out;
+
+	/* regenerate START state to set up for reading */
+	S24C16_start(np, &gpreg);
+	
+	/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
+	S24C16_write_byte(np, &ack_data,
+		0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
+	if (ack_data & 0x01)
+		goto out;
+
+	/* now set up GPIO0 for inputting data */
+	gpcntl |= 0x01;
+	OUTB (nc_gpcntl, gpcntl);
+		
+	/* input all requested data - only part of total NVRAM */
+	for (x = 0; x < len; x++) 
+		S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
+
+	/* finally put NVRAM back in inactive mode */
+	gpcntl &= 0xfe;
+	OUTB (nc_gpcntl, gpcntl);
+	S24C16_stop(np, &gpreg);
+	retv = 0;
+out:
+	/* return GPIO0/1 to original states after having accessed NVRAM */
+	OUTB (nc_gpcntl, old_gpcntl);
+	OUTB (nc_gpreg,  old_gpreg);
+
+	return retv;
+}
+
+#undef SET_BIT 0
+#undef CLR_BIT 1
+#undef SET_CLK 2
+#undef CLR_CLK 3
+
+/*
+ *  Try reading Symbios NVRAM.
+ *  Return 0 if OK.
+ */
+static int __init sym_read_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
+{
+	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
+	u_char *data = (u_char *) nvram;
+	int len  = sizeof(*nvram);
+	u_short	csum;
+	int x;
+
+	/* probe the 24c16 and read the SYMBIOS 24c16 area */
+	if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
+		return 1;
+
+	/* check valid NVRAM signature, verify byte count and checksum */
+	if (nvram->type != 0 ||
+	    memcmp(nvram->trailer, Symbios_trailer, 6) ||
+	    nvram->byte_count != len - 12)
+		return 1;
+
+	/* verify checksum */
+	for (x = 6, csum = 0; x < len - 6; x++)
+		csum += data[x];
+	if (csum != nvram->checksum)
+		return 1;
+
+	return 0;
+}
+
+/*
+ *  93C46 EEPROM reading.
+ *
+ *  GPOI0 - data in
+ *  GPIO1 - data out
+ *  GPIO2 - clock
+ *  GPIO4 - chip select
+ *
+ *  Used by Tekram.
+ */
+
+/*
+ *  Pulse clock bit in GPIO0
+ */
+static void __init T93C46_Clk(ncr_slot *np, u_char *gpreg)
+{
+	OUTB (nc_gpreg, *gpreg | 0x04);
+	UDELAY (2);
+	OUTB (nc_gpreg, *gpreg);
+}
+
+/* 
+ *  Read bit from NVRAM
+ */
+static void __init T93C46_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
+{
+	UDELAY (2);
+	T93C46_Clk(np, gpreg);
+	*read_bit = INB (nc_gpreg);
+}
+
+/*
+ *  Write bit to GPIO0
+ */
+static void __init T93C46_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
+{
+	if (write_bit & 0x01)
+		*gpreg |= 0x02;
+	else
+		*gpreg &= 0xfd;
+		
+	*gpreg |= 0x10;
+		
+	OUTB (nc_gpreg, *gpreg);
+	UDELAY (2);
+
+	T93C46_Clk(np, gpreg);
+}
+
+/*
+ *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
+ */
+static void __init T93C46_Stop(ncr_slot *np, u_char *gpreg)
+{
+	*gpreg &= 0xef;
+	OUTB (nc_gpreg, *gpreg);
+	UDELAY (2);
+
+	T93C46_Clk(np, gpreg);
+}
+
+/*
+ *  Send read command and address to NVRAM
+ */
+static void __init 
+T93C46_Send_Command(ncr_slot *np, u_short write_data, 
+		    u_char *read_bit, u_char *gpreg)
+{
+	int x;
+
+	/* send 9 bits, start bit (1), command (2), address (6)  */
+	for (x = 0; x < 9; x++)
+		T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
+
+	*read_bit = INB (nc_gpreg);
+}
+
+/*
+ *  READ 2 bytes from the NVRAM
+ */
+static void __init 
+T93C46_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
+{
+	int x;
+	u_char read_bit;
+
+	*nvram_data = 0;
+	for (x = 0; x < 16; x++) {
+		T93C46_Read_Bit(np, &read_bit, gpreg);
+
+		if (read_bit & 0x01)
+			*nvram_data |=  (0x01 << (15 - x));
+		else
+			*nvram_data &= ~(0x01 << (15 - x));
+	}
+}
+
+/*
+ *  Read Tekram NvRAM data.
+ */
+static int __init 
+T93C46_Read_Data(ncr_slot *np, u_short *data,int len,u_char *gpreg)
+{
+	u_char	read_bit;
+	int	x;
+
+	for (x = 0; x < len; x++)  {
+
+		/* output read command and address */
+		T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
+		if (read_bit & 0x01)
+			return 1; /* Bad */
+		T93C46_Read_Word(np, &data[x], gpreg);
+		T93C46_Stop(np, gpreg);
+	}
+
+	return 0;
+}
+
+/*
+ *  Try reading 93C46 Tekram NVRAM.
+ */
+static int __init 
+sym_read_T93C46_nvram (ncr_slot *np, Tekram_nvram *nvram)
+{
+	u_char gpcntl, gpreg;
+	u_char old_gpcntl, old_gpreg;
+	int retv = 1;
+
+	/* save current state of GPCNTL and GPREG */
+	old_gpreg	= INB (nc_gpreg);
+	old_gpcntl	= INB (nc_gpcntl);
+
+	/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
+	   1/2/4 out */
+	gpreg = old_gpreg & 0xe9;
+	OUTB (nc_gpreg, gpreg);
+	gpcntl = (old_gpcntl & 0xe9) | 0x09;
+	OUTB (nc_gpcntl, gpcntl);
+
+	/* input all of NVRAM, 64 words */
+	retv = T93C46_Read_Data(np, (u_short *) nvram,
+				sizeof(*nvram) / sizeof(short), &gpreg);
+	
+	/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
+	OUTB (nc_gpcntl, old_gpcntl);
+	OUTB (nc_gpreg,  old_gpreg);
+
+	return retv;
+}
+
+/*
+ *  Try reading Tekram NVRAM.
+ *  Return 0 if OK.
+ */
+static int __init 
+sym_read_Tekram_nvram (ncr_slot *np, u_short device_id, Tekram_nvram *nvram)
+{
+	u_char *data = (u_char *) nvram;
+	int len = sizeof(*nvram);
+	u_short	csum;
+	int x;
+
+	switch (device_id) {
+	case PCI_DEVICE_ID_NCR_53C885:
+	case PCI_DEVICE_ID_NCR_53C895:
+	case PCI_DEVICE_ID_NCR_53C896:
+		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
+					  data, len);
+		break;
+	case PCI_DEVICE_ID_NCR_53C875:
+		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
+					  data, len);
+		if (!x)
+			break;
+	default:
+		x = sym_read_T93C46_nvram(np, nvram);
+		break;
+	}
+	if (x)
+		return 1;
+
+	/* verify checksum */
+	for (x = 0, csum = 0; x < len - 1; x += 2)
+		csum += data[x] + (data[x+1] << 8);
+	if (csum != 0x1234)
+		return 1;
+
+	return 0;
+}
+
+#endif	/* SCSI_NCR_NVRAM_SUPPORT */
+
+/*===================================================================
+**
+**    Detect and try to read SYMBIOS and TEKRAM NVRAM.
+**
+**    Data can be used to order booting of boards.
+**
+**    Data is saved in ncr_device structure if NVRAM found. This
+**    is then used to find drive boot order for ncr_attach().
+**
+**    NVRAM data is passed to Scsi_Host_Template later during 
+**    ncr_attach() for any device set up.
+**
+**===================================================================
+*/
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+static void __init ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp)
+{
+	devp->nvram = nvp;
+	if (!nvp)
+		return;
+	/*
+	**    Get access to chip IO registers
+	*/
+#ifdef SCSI_NCR_IOMAPPED
+	request_region(devp->slot.io_port, 128, NAME53C8XX);
+	devp->slot.base_io = devp->slot.io_port;
+#else
+	devp->slot.reg = (struct ncr_reg *) remap_pci_mem(devp->slot.base, 128);
+	if (!devp->slot.reg)
+		return;
+#endif
+
+	/*
+	**    Try to read SYMBIOS nvram.
+	**    Try to read TEKRAM nvram if Symbios nvram not found.
+	*/
+	if	(!sym_read_Symbios_nvram(&devp->slot, &nvp->data.Symbios))
+		nvp->type = SCSI_NCR_SYMBIOS_NVRAM;
+	else if	(!sym_read_Tekram_nvram(&devp->slot, devp->chip.device_id,
+					&nvp->data.Tekram))
+		nvp->type = SCSI_NCR_TEKRAM_NVRAM;
+	else {
+		nvp->type = 0;
+		devp->nvram = 0;
+	}
+
+	/*
+	** Release access to chip IO registers
+	*/
+#ifdef SCSI_NCR_IOMAPPED
+	release_region(devp->slot.base_io, 128);
+#else
+	unmap_pci_mem((u_long) devp->slot.reg, 128ul);
+#endif
+
+}
+
+/*===================================================================
+**
+**	Display the content of NVRAM for debugging purpose.
+**
+**===================================================================
+*/
+#ifdef	SCSI_NCR_DEBUG_NVRAM
+static void __init ncr_display_Symbios_nvram(Symbios_nvram *nvram)
+{
+	int i;
+
+	/* display Symbios nvram host data */
+	printk(KERN_DEBUG NAME53C8XX ": HOST ID=%d%s%s%s%s%s\n",
+		nvram->host_id & 0x0f,
+		(nvram->flags  & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
+		(nvram->flags  & SYMBIOS_PARITY_ENABLE)	? " PARITY"	:"",
+		(nvram->flags  & SYMBIOS_VERBOSE_MSGS)	? " VERBOSE"	:"", 
+		(nvram->flags  & SYMBIOS_CHS_MAPPING)	? " CHS_ALT"	:"", 
+		(nvram->flags1 & SYMBIOS_SCAN_HI_LO)	? " HI_LO"	:"");
+
+	/* display Symbios nvram drive data */
+	for (i = 0 ; i < 15 ; i++) {
+		struct Symbios_target *tn = &nvram->target[i];
+		printk(KERN_DEBUG NAME53C8XX 
+		"-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
+		i,
+		(tn->flags & SYMBIOS_DISCONNECT_ENABLE)	? " DISC"	: "",
+		(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)	? " SCAN_BOOT"	: "",
+		(tn->flags & SYMBIOS_SCAN_LUNS)		? " SCAN_LUNS"	: "",
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ"	: "",
+		tn->bus_width,
+		tn->sync_period / 4,
+		tn->timeout);
+	}
+}
+
+static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120};
+
+static void __init ncr_display_Tekram_nvram(Tekram_nvram *nvram)
+{
+	int i, tags, boot_delay;
+	char *rem;
+
+	/* display Tekram nvram host data */
+	tags = 2 << nvram->max_tags_index;
+	boot_delay = 0;
+	if (nvram->boot_delay_index < 6)
+		boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
+	switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
+	default:
+	case 0:	rem = "";			break;
+	case 1: rem = " REMOVABLE=boot device";	break;
+	case 2: rem = " REMOVABLE=all";		break;
+	}
+
+	printk(KERN_DEBUG NAME53C8XX
+		": HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
+		nvram->host_id & 0x0f,
+		(nvram->flags1 & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
+		(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
+		(nvram->flags & TEKRAM_DRIVES_SUP_1GB)	? " >1GB"	:"",
+		(nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET"	:"",
+		(nvram->flags & TEKRAM_ACTIVE_NEGATION)	? " ACT_NEG"	:"",
+		(nvram->flags & TEKRAM_IMMEDIATE_SEEK)	? " IMM_SEEK"	:"",
+		(nvram->flags & TEKRAM_SCAN_LUNS)	? " SCAN_LUNS"	:"",
+		(nvram->flags1 & TEKRAM_F2_F6_ENABLED)	? " F2_F6"	:"",
+		rem, boot_delay, tags);
+
+	/* display Tekram nvram drive data */
+	for (i = 0; i <= 15; i++) {
+		int sync, j;
+		struct Tekram_target *tn = &nvram->target[i];
+		j = tn->sync_index & 0xf;
+		sync = Tekram_sync[j];
+		printk(KERN_DEBUG NAME53C8XX "-%d:%s%s%s%s%s%s PERIOD=%d\n",
+		i,
+		(tn->flags & TEKRAM_PARITY_CHECK)	? " PARITY"	: "",
+		(tn->flags & TEKRAM_SYNC_NEGO)		? " SYNC"	: "",
+		(tn->flags & TEKRAM_DISCONNECT_ENABLE)	? " DISC"	: "",
+		(tn->flags & TEKRAM_START_CMD)		? " START"	: "",
+		(tn->flags & TEKRAM_TAGGED_COMMANDS)	? " TCQ"	: "",
+		(tn->flags & TEKRAM_WIDE_NEGO)		? " WIDE"	: "",
+		sync);
+	}
+}
+#endif /* SCSI_NCR_DEBUG_NVRAM */
+#endif	/* SCSI_NCR_NVRAM_SUPPORT */
+
+
+/*===================================================================
+**
+**	Utility routines that protperly return data through /proc FS.
+**
+**===================================================================
+*/
+#ifdef SCSI_NCR_USER_INFO_SUPPORT
+
+struct info_str
+{
+	char *buffer;
+	int length;
+	int offset;
+	int pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->length)
+		len = info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+	if (info->pos < info->offset) {
+		data += (info->offset - info->pos);
+		len  -= (info->offset - info->pos);
+	}
+
+	if (len > 0) {
+		memcpy(info->buffer + info->pos, data, len);
+		info->pos += len;
+	}
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[81];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+	return len;
+}
+
+#endif
+
+/*===================================================================
+**
+**	Driver setup from the boot command line
+**
+**===================================================================
+*/
+
+#ifdef MODULE
+#define	ARG_SEP	' '
+#else
+#define	ARG_SEP	','
+#endif
+
+#define OPT_TAGS		1
+#define OPT_MASTER_PARITY	2
+#define OPT_SCSI_PARITY		3
+#define OPT_DISCONNECTION	4
+#define OPT_SPECIAL_FEATURES	5
+#define OPT_ULTRA_SCSI		6
+#define OPT_FORCE_SYNC_NEGO	7
+#define OPT_REVERSE_PROBE	8
+#define OPT_DEFAULT_SYNC	9
+#define OPT_VERBOSE		10
+#define OPT_DEBUG		11
+#define OPT_BURST_MAX		12
+#define OPT_LED_PIN		13
+#define OPT_MAX_WIDE		14
+#define OPT_SETTLE_DELAY	15
+#define OPT_DIFF_SUPPORT	16
+#define OPT_IRQM		17
+#define OPT_PCI_FIX_UP		18
+#define OPT_BUS_CHECK		19
+#define OPT_OPTIMIZE		20
+#define OPT_RECOVERY		21
+#define OPT_SAFE_SETUP		22
+#define OPT_USE_NVRAM		23
+#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:"
+	"specf:"  "ultra:"
+	"fsn:"    "revprob:"
+	"sync:"   "verb:"
+	"debug:"  "burst:"
+	"led:"    "wide:"
+	"settle:" "diff:"
+	"irqm:"   "pcifix:"
+	"buschk:" "optim:"
+	"recovery:"
+	"safe:"   "nvram:"
+	"excl:"   "hostid:"
+#ifdef SCSI_NCR_IARB_SUPPORT
+	"iarb:"
+#endif
+	;	/* DONNOT REMOVE THIS ';' */
+
+#ifdef MODULE
+#define	ARG_SEP	' '
+#else
+#define	ARG_SEP	','
+#endif
+
+static int __init get_setup_token(char *p)
+{
+	char *cur = setup_token;
+	char *pc;
+	int i = 0;
+
+	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+		++pc;
+		++i;
+		if (!strncmp(p, cur, pc - cur))
+			return i;
+		cur = pc;
+	}
+	return 0;
+}
+
+
+static int __init sym53c8xx__setup(char *str)
+{
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+	char *cur = str;
+	char *pc, *pv;
+	int i, val, c;
+	int xi = 0;
+
+	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+		char *pe;
+
+		val = 0;
+		pv = pc;
+		c = *++pv;
+
+		if	(c == 'n')
+			val = 0;
+		else if	(c == 'y')
+			val = 1;
+		else
+			val = (int) simple_strtoul(pv, &pe, 0);
+
+		switch (get_setup_token(cur)) {
+		case OPT_TAGS:
+			driver_setup.default_tags = val;
+			if (pe && *pe == '/') {
+				i = 0;
+				while (*pe && *pe != ARG_SEP && 
+					i < sizeof(driver_setup.tag_ctrl)-1) {
+					driver_setup.tag_ctrl[i++] = *pe++;
+				}
+				driver_setup.tag_ctrl[i] = '\0';
+			}
+			break;
+		case OPT_MASTER_PARITY:
+			driver_setup.master_parity = val;
+			break;
+		case OPT_SCSI_PARITY:
+			driver_setup.scsi_parity = val;
+			break;
+		case OPT_DISCONNECTION:
+			driver_setup.disconnection = val;
+			break;
+		case OPT_SPECIAL_FEATURES:
+			driver_setup.special_features = val;
+			break;
+		case OPT_ULTRA_SCSI:
+			driver_setup.ultra_scsi	= val;
+			break;
+		case OPT_FORCE_SYNC_NEGO:
+			driver_setup.force_sync_nego = val;
+			break;
+		case OPT_REVERSE_PROBE:
+			driver_setup.reverse_probe = val;
+			break;
+		case OPT_DEFAULT_SYNC:
+			driver_setup.default_sync = val;
+			break;
+		case OPT_VERBOSE:
+			driver_setup.verbose = val;
+			break;
+		case OPT_DEBUG:
+			driver_setup.debug = val;
+			break;
+		case OPT_BURST_MAX:
+			driver_setup.burst_max = val;
+			break;
+		case OPT_LED_PIN:
+			driver_setup.led_pin = val;
+			break;
+		case OPT_MAX_WIDE:
+			driver_setup.max_wide = val? 1:0;
+			break;
+		case OPT_SETTLE_DELAY:
+			driver_setup.settle_delay = val;
+			break;
+		case OPT_DIFF_SUPPORT:
+			driver_setup.diff_support = val;
+			break;
+		case OPT_IRQM:
+			driver_setup.irqm = val;
+			break;
+		case OPT_PCI_FIX_UP:
+			driver_setup.pci_fix_up	= val;
+			break;
+		case OPT_BUS_CHECK:
+			driver_setup.bus_check = val;
+			break;
+		case OPT_OPTIMIZE:
+			driver_setup.optimize = val;
+			break;
+		case OPT_RECOVERY:
+			driver_setup.recovery = val;
+			break;
+		case OPT_USE_NVRAM:
+			driver_setup.use_nvram = val;
+			break;
+		case OPT_SAFE_SETUP:
+			memcpy(&driver_setup, &driver_safe_setup,
+				sizeof(driver_setup));
+			break;
+		case OPT_EXCLUDE:
+			if (xi < SCSI_NCR_MAX_EXCLUDES)
+				driver_setup.excludes[xi++] = val;
+			break;
+		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;
+		}
+
+		if ((cur = strchr(cur, ARG_SEP)) != NULL)
+			++cur;
+	}
+#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+	return 1;
+}
+
+/*===================================================================
+**
+**	Get device queue depth from boot command line.
+**
+**===================================================================
+*/
+#define DEF_DEPTH	(driver_setup.default_tags)
+#define ALL_TARGETS	-2
+#define NO_TARGET	-1
+#define ALL_LUNS	-2
+#define NO_LUN		-1
+
+static int device_queue_depth(int unit, int target, int lun)
+{
+	int c, h, t, u, v;
+	char *p = driver_setup.tag_ctrl;
+	char *ep;
+
+	h = -1;
+	t = NO_TARGET;
+	u = NO_LUN;
+	while ((c = *p++) != 0) {
+		v = simple_strtoul(p, &ep, 0);
+		switch(c) {
+		case '/':
+			++h;
+			t = ALL_TARGETS;
+			u = ALL_LUNS;
+			break;
+		case 't':
+			if (t != target)
+				t = (target == v) ? v : NO_TARGET;
+			u = ALL_LUNS;
+			break;
+		case 'u':
+			if (u != lun)
+				u = (lun == v) ? v : NO_LUN;
+			break;
+		case 'q':
+			if (h == unit &&
+				(t == ALL_TARGETS || t == target) &&
+				(u == ALL_LUNS    || u == lun))
+				return v;
+			break;
+		case '-':
+			t = ALL_TARGETS;
+			u = ALL_LUNS;
+			break;
+		default:
+			break;
+		}
+		p = ep;
+	}
+	return DEF_DEPTH;
+}
+
+/*===================================================================
+**
+**	Print out information about driver configuration.
+**
+**===================================================================
+*/
+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,"
+		"burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n",
+		YesNo(driver_setup.disconnection),
+		driver_setup.special_features,
+		driver_setup.ultra_scsi,
+		driver_setup.default_tags,
+		driver_setup.default_sync,
+		driver_setup.burst_max,
+		YesNo(driver_setup.max_wide),
+		driver_setup.diff_support,
+		YesNo(driver_setup.reverse_probe),
+		driver_setup.bus_check);
+
+	printk (NAME53C8XX ": setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,"
+		"led:%c,settle:%d,irqm:0x%x,nvram:0x%x,pcifix:0x%x\n",
+		YesNo(driver_setup.master_parity),
+		YesNo(driver_setup.scsi_parity),
+		YesNo(driver_setup.force_sync_nego),
+		driver_setup.verbose,
+		driver_setup.debug,
+		YesNo(driver_setup.led_pin),
+		driver_setup.settle_delay,
+		driver_setup.irqm,
+		driver_setup.use_nvram,
+		driver_setup.pci_fix_up);
+#undef YesNo
+}
+
+/*===================================================================
+**
+**   SYM53C8XX devices description table.
+**
+**===================================================================
+*/
+
+static ncr_chip	ncr_chip_table[] __initdata	= SCSI_NCR_CHIP_TABLE;
+
+#ifdef	SCSI_NCR_PQS_PDS_SUPPORT
+/*===================================================================
+**
+**    Detect all NCR PQS/PDS boards and keep track of their bus nr.
+**
+**    The NCR PQS or PDS card is constructed as a DEC bridge
+**    behind which sit a proprietary NCR memory controller and
+**    four or two 53c875s as separate devices.  In its usual mode
+**    of operation, the 875s are slaved to the memory controller
+**    for all transfers.  We can tell if an 875 is part of a
+**    PQS/PDS or not since if it is, it will be on the same bus
+**    as the memory controller.  To operate with the Linux
+**    driver, the memory controller is disabled and the 875s
+**    freed to function independently.  The only wrinkle is that
+**    the preset SCSI ID (which may be zero) must be read in from
+**    a special configuration space register of the 875.
+**
+**===================================================================
+*/
+#define	SCSI_NCR_MAX_PQS_BUS	16
+static int pqs_bus[SCSI_NCR_MAX_PQS_BUS] __initdata = { 0 };
+
+static void __init ncr_detect_pqs_pds(void)
+{
+	short index;
+	pcidev_t dev = PCIDEV_NULL;
+
+	for(index=0; index < SCSI_NCR_MAX_PQS_BUS; index++) {
+		u_char tmp;
+
+		dev = pci_find_device(0x101a, 0x0009, dev);
+		if (dev == PCIDEV_NULL) {
+			pqs_bus[index] = -1;
+			break;
+		}
+		printk(KERN_INFO NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", PciBusNumber(dev));
+		pci_read_config_byte(dev, 0x44, &tmp);
+		/* bit 1: allow individual 875 configuration */
+		tmp |= 0x2;
+		pci_write_config_byte(dev, 0x44, tmp);
+		pci_read_config_byte(dev, 0x45, &tmp);
+		/* bit 2: drive individual 875 interrupts to the bus */
+		tmp |= 0x4;
+		pci_write_config_byte(dev, 0x45, tmp);
+
+		pqs_bus[index] = PciBusNumber(dev);
+	}
+}
+#endif /* SCSI_NCR_PQS_PDS_SUPPORT */
+
+/*===================================================================
+**
+**   Read and check the PCI configuration for any detected NCR 
+**   boards and save data for attaching after all boards have 
+**   been detected.
+**
+**===================================================================
+*/
+static int __init
+sym53c8xx_pci_init(Scsi_Host_Template *tpnt, pcidev_t pdev, ncr_device *device)
+{
+	u_short vendor_id, device_id, command;
+	u_char cache_line_size, latency_timer;
+	u_char suggested_cache_line_size = 0;
+	u_char pci_fix_up = driver_setup.pci_fix_up;
+	u_char revision;
+	u_int irq;
+	u_long base, base_2, io_port; 
+	int i;
+	ncr_chip *chip;
+
+	printk(KERN_INFO NAME53C8XX ": at PCI bus %d, device %d, function %d\n",
+		PciBusNumber(pdev),
+		(int) (PciDeviceFn(pdev) & 0xf8) >> 3,
+		(int) (PciDeviceFn(pdev) & 7));
+
+#ifdef SCSI_NCR_DYNAMIC_DMA_MAPPING
+	if (!pci_dma_supported(pdev, (dma_addr_t) (0xffffffffUL))) {
+		printk(KERN_WARNING NAME53C8XX
+		       "32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+		return -1;
+	}
+#endif
+
+	/*
+	**    Read info from the PCI config space.
+	**    pci_read_config_xxx() functions are assumed to be used for 
+	**    successfully detected PCI devices.
+	*/
+	vendor_id = PciVendorId(pdev);
+	device_id = PciDeviceId(pdev);
+	irq	  = PciIrqLine(pdev);
+	i =	0;
+	i =	pci_get_base_address(pdev, i, &io_port);
+	i =	pci_get_base_address(pdev, i, &base);
+	(void)	pci_get_base_address(pdev, i, &base_2);
+
+	pci_read_config_word(pdev, PCI_COMMAND,		&command);
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION,	&revision);
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,	&cache_line_size);
+	pci_read_config_byte(pdev, PCI_LATENCY_TIMER,	&latency_timer);
+
+#ifdef SCSI_NCR_PQS_PDS_SUPPORT
+	/*
+	**    Match the BUS number for PQS/PDS devices.
+	**    Read the SCSI ID from a special register mapped
+	**    into the configuration space of the individual
+	**    875s.  This register is set up by the PQS bios
+	*/
+	for(i = 0; i < SCSI_NCR_MAX_PQS_BUS && pqs_bus[i] != -1; i++) {
+		u_char tmp;
+		if (pqs_bus[i] == PciBusNumber(pdev)) {
+			pci_read_config_byte(pdev, 0x84, &tmp);
+			device->pqs_pds = 1;
+			device->host_id = tmp;
+			break;
+		}
+	}
+#endif /* SCSI_NCR_PQS_PDS_SUPPORT */
+
+	/*
+	**	If user excludes this chip, donnot initialize it.
+	*/
+	for (i = 0 ; i < SCSI_NCR_MAX_EXCLUDES ; i++) {
+		if (driver_setup.excludes[i] ==
+				(io_port & PCI_BASE_ADDRESS_IO_MASK))
+			return -1;
+	}
+	/*
+	**    Check if the chip is supported
+	*/
+	if ((device_id == PCI_DEVICE_ID_LSI_53C1010) ||
+			(device_id == PCI_DEVICE_ID_LSI_53C1010_66)){
+		printk(NAME53C8XX ": not initializing, device not supported\n");
+		return -1;
+	}
+	chip = 0;
+	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)
+			continue;
+		chip = &device->chip;
+		memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
+		chip->revision_id = revision;
+		break;
+	}
+
+	/*
+	**	Ignore Symbios chips controlled by SISL RAID controller.
+	**	This controller sets value 0x52414944 at RAM end - 16.
+	*/
+#if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
+	if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
+		unsigned int ram_size, ram_val;
+		u_long ram_ptr;
+
+		if (chip->features & FE_RAM8K)
+			ram_size = 8192;
+		else
+			ram_size = 4096;
+
+		ram_ptr = remap_pci_mem(base_2 & PCI_BASE_ADDRESS_MEM_MASK,
+					ram_size);
+		if (ram_ptr) {
+			ram_val = readl_raw(ram_ptr + ram_size - 16);
+			unmap_pci_mem(ram_ptr, ram_size);
+			if (ram_val == 0x52414944) {
+				printk(NAME53C8XX": not initializing, "
+				       "driven by SISL RAID controller.\n");
+				return -1;
+			}
+		}
+	}
+#endif /* i386 and PCI MEMORY accessible */
+
+	if (!chip) {
+		printk(NAME53C8XX ": not initializing, device not supported\n");
+		return -1;
+	}
+
+#ifdef __powerpc__
+	/*
+	**	Fix-up for power/pc.
+	**	Should not be performed by the driver.
+	*/
+	if ((command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
+		    != (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+		printk(NAME53C8XX ": setting%s%s...\n",
+		(command & PCI_COMMAND_IO)     ? "" : " PCI_COMMAND_IO",
+		(command & PCI_COMMAND_MEMORY) ? "" : " PCI_COMMAND_MEMORY");
+		command |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+		pci_write_config_word(pdev, PCI_COMMAND, command);
+	}
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
+	if ( is_prep ) {
+		if (io_port >= 0x10000000) {
+			printk(NAME53C8XX ": reallocating io_port (Wacky IBM)");
+			io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+			pci_write_config_dword(pdev,
+					       PCI_BASE_ADDRESS_0, io_port);
+		}
+		if (base >= 0x10000000) {
+			printk(NAME53C8XX ": reallocating base (Wacky IBM)");
+			base = (base & 0x00FFFFFF) | 0x01000000;
+			pci_write_config_dword(pdev,
+					       PCI_BASE_ADDRESS_1, base);
+		}
+		if (base_2 >= 0x10000000) {
+			printk(NAME53C8XX ": reallocating base2 (Wacky IBM)");
+			base_2 = (base_2 & 0x00FFFFFF) | 0x01000000;
+			pci_write_config_dword(pdev,
+					       PCI_BASE_ADDRESS_2, base_2);
+		}
+	}
+#endif
+#endif	/* __powerpc__ */
+
+#if defined(__sparc__) && (LINUX_VERSION_CODE < LinuxVersionCode(2,3,0))
+	/*
+	 *	Severall fix-ups for sparc.
+	 *
+	 *	Should not be performed by the driver, which is why all
+	 *	this crap is cleaned up in 2.4.x
+	 */
+
+	base = __pa(base);
+	base_2 = __pa(base_2);
+
+	if (!(command & PCI_COMMAND_MASTER)) {
+		if (initverbose >= 2)
+			printk("ncr53c8xx: setting PCI_COMMAND_MASTER bit (fixup)\n");
+		command |= PCI_COMMAND_MASTER;
+		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+		pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+	}
+
+	if ((chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
+		if (initverbose >= 2)
+			printk("ncr53c8xx: setting PCI_COMMAND_INVALIDATE bit (fixup)\n");
+		command |= PCI_COMMAND_INVALIDATE;
+		pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+		pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command);
+	}
+
+	if ((chip->features & FE_CLSE) && !cache_line_size) {
+		/* 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);
+		pcibios_write_config_byte(bus, device_fn,
+					  PCI_CACHE_LINE_SIZE, cache_line_size);
+		pcibios_read_config_byte(bus, device_fn,
+					 PCI_CACHE_LINE_SIZE, &cache_line_size);
+	}
+
+	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);
+		pcibios_write_config_byte(bus, device_fn,
+					  PCI_LATENCY_TIMER, latency_timer);
+		pcibios_read_config_byte(bus, device_fn,
+					 PCI_LATENCY_TIMER, &latency_timer);
+	}
+#endif /* __sparc__ && (LINUX_VERSION_CODE < LinuxVersionCode(2,3,0)) */
+
+#if defined(__i386__) && !defined(MODULE)
+	if (!cache_line_size) {
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
+		extern char x86;
+		switch(x86) {
+#else
+		switch(boot_cpu_data.x86) {
+#endif
+		case 4:	suggested_cache_line_size = 4; break;
+		case 6:
+		case 5:	suggested_cache_line_size = 8; break;
+		}
+	}
+#endif	/* __i386__ */
+
+	/*
+	**    Check availability of IO space, memory space.
+	**    Enable master capability if not yet.
+	**
+	**    We shouldn't have to care about the IO region when 
+	**    we are using MMIO. But calling check_region() from 
+	**    both the ncr53c8xx and the sym53c8xx drivers prevents 
+	**    from attaching devices from the both drivers.
+	**    If you have a better idea, let me know.
+	*/
+/* #ifdef SCSI_NCR_IOMAPPED */
+#if 1
+	if (!(command & PCI_COMMAND_IO)) { 
+		printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n",
+			(long) io_port);
+		io_port = 0;
+	}
+#endif
+	if (!(command & PCI_COMMAND_MEMORY)) {
+		printk(NAME53C8XX ": PCI_COMMAND_MEMORY not set.\n");
+		base	= 0;
+		base_2	= 0;
+	}
+	io_port &= PCI_BASE_ADDRESS_IO_MASK;
+	base	&= PCI_BASE_ADDRESS_MEM_MASK;
+	base_2	&= PCI_BASE_ADDRESS_MEM_MASK;
+
+/* #ifdef SCSI_NCR_IOMAPPED */
+#if 1
+	if (io_port && check_region (io_port, 128)) {
+		printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n",
+			(long) io_port);
+		io_port = 0;
+	}
+	if (!io_port)
+		return -1;
+#endif
+#ifndef SCSI_NCR_IOMAPPED
+	if (!base) {
+		printk(NAME53C8XX ": MMIO base address disabled.\n");
+		return -1;
+	}
+#endif
+
+/* The ncr53c8xx driver never did set the PCI parity bit.	*/
+/* Since setting this bit is known to trigger spurious MDPE	*/
+/* errors on some 895 controllers when noise on power lines is	*/
+/* too high, I donnot want to change previous ncr53c8xx driver	*/
+/* behaviour on that point (the sym53c8xx driver set this bit).	*/
+#if 0
+	/*
+	**    Set MASTER capable and PARITY bit, if not yet.
+	*/
+	if ((command & (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY))
+		     != (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)) {
+		printk(NAME53C8XX ": setting%s%s...(fix-up)\n",
+		(command & PCI_COMMAND_MASTER) ? "" : " PCI_COMMAND_MASTER",
+		(command & PCI_COMMAND_PARITY) ? "" : " PCI_COMMAND_PARITY");
+		command |= (PCI_COMMAND_MASTER | PCI_COMMAND_PARITY);
+		pci_write_config_word(pdev, PCI_COMMAND, command);
+	}
+#else
+	/*
+	**    Set MASTER capable if not yet.
+	*/
+	if ((command & PCI_COMMAND_MASTER) != PCI_COMMAND_MASTER) {
+		printk(NAME53C8XX ": setting PCI_COMMAND_MASTER...(fix-up)\n");
+		command |= PCI_COMMAND_MASTER;
+		pci_write_config_word(pdev, PCI_COMMAND, command);
+	}
+#endif
+
+	/*
+	**    Fix some features according to driver setup.
+	*/
+	if (!(driver_setup.special_features & 1))
+		chip->features &= ~FE_SPECIAL_SET;
+	else {
+		if (driver_setup.special_features & 2)
+			chip->features &= ~FE_WRIE;
+		if (driver_setup.special_features & 4)
+			chip->features &= ~FE_NOPM;
+	}
+	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;
+
+	/*
+	**	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.
+	*/
+	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 ((pci_fix_up & 1) && (chip->features & FE_CLSE) && 
+	    !cache_line_size && suggested_cache_line_size) {
+		cache_line_size = suggested_cache_line_size;
+		pci_write_config_byte(pdev,
+				      PCI_CACHE_LINE_SIZE, cache_line_size);
+		printk(NAME53C8XX ": PCI_CACHE_LINE_SIZE set to %d (fix-up).\n",
+			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;
+		pci_write_config_word(pdev, PCI_COMMAND, command);
+	}
+
+	/*
+	**    Tune PCI LATENCY TIMER according to burst max length transfer.
+	**    (latency timer >= burst length + 6, we add 10 to be quite sure)
+	*/
+
+	if (chip->burst_max && (latency_timer == 0 || (pci_fix_up & 4))) {
+		u_char lt = (1 << chip->burst_max) + 6 + 10;
+		if (latency_timer < lt) {
+			printk(NAME53C8XX 
+			       ": changing PCI_LATENCY_TIMER from %d to %d.\n",
+			       (int) latency_timer, (int) lt);
+			latency_timer = lt;
+			pci_write_config_byte(pdev,
+					      PCI_LATENCY_TIMER, latency_timer);
+		}
+	}
+
+#endif	/* SCSI_NCR_PCI_FIX_UP_SUPPORT */
+
+ 	/*
+	**    Initialise ncr_device structure with items required by ncr_attach.
+	*/
+	device->pdev		= pdev;
+	device->slot.bus	= PciBusNumber(pdev);
+	device->slot.device_fn	= PciDeviceFn(pdev);
+	device->slot.base	= base;
+	device->slot.base_2	= base_2;
+	device->slot.io_port	= io_port;
+	device->slot.irq	= irq;
+	device->attach_done	= 0;
+
+	return 0;
+}
+
+/*===================================================================
+**
+**    Detect all 53c8xx hosts and then attach them.
+**
+**    If we are using NVRAM, once all hosts are detected, we need to 
+**    check any NVRAM for boot order in case detect and boot order 
+**    differ and attach them using the order in the NVRAM.
+**
+**    If no NVRAM is found or data appears invalid attach boards in 
+**    the the order they are detected.
+**
+**===================================================================
+*/
+static int __init 
+sym53c8xx__detect(Scsi_Host_Template *tpnt, u_short ncr_chip_ids[], int chips)
+{
+	pcidev_t pcidev;
+	int i, j, hosts, count;
+	int attach_count = 0;
+	ncr_device *devtbl, *devp;
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	ncr_nvram  nvram0, nvram, *nvp;
+#endif
+
+	/*
+	**    PCI is required.
+	*/
+	if (!pci_present())
+		return 0;
+
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
+	ncr_debug = driver_setup.debug;
+#endif
+	if (initverbose >= 2)
+		ncr_print_driver_setup();
+
+	/*
+	**	Allocate the device table since we donnot want to 
+	**	overflow the kernel stack.
+	**	1 x 4K PAGE is enough for more than 40 devices for i386.
+	*/
+	devtbl = m_calloc(PAGE_SIZE, "devtbl");
+	if (!devtbl)
+		return 0;
+
+	/*
+	**    Detect all NCR PQS/PDS memory controllers.
+	*/
+#ifdef	SCSI_NCR_PQS_PDS_SUPPORT
+	ncr_detect_pqs_pds();
+#endif
+
+	/* 
+	**    Detect all 53c8xx hosts.
+	**    Save the first Symbios NVRAM content if any 
+	**    for the boot order.
+	*/
+	hosts	= PAGE_SIZE		/ sizeof(*devtbl);
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	nvp = (driver_setup.use_nvram & 0x1) ? &nvram0 : 0;
+#endif
+	j = 0;
+	count = 0;
+	pcidev = PCIDEV_NULL;
+	while (1) {
+		char *msg = "";
+		if (count >= hosts)
+			break;
+		if (j >= chips)
+			break;
+		i = driver_setup.reverse_probe ? chips - 1 - j : j;
+		pcidev = pci_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i],
+					 pcidev);
+		if (pcidev == PCIDEV_NULL) {
+			++j;
+			continue;
+		}
+		/* Some HW as the HP LH4 may report twice PCI devices */
+		for (i = 0; i < count ; i++) {
+			if (devtbl[i].slot.bus	     == PciBusNumber(pcidev) && 
+			    devtbl[i].slot.device_fn == PciDeviceFn(pcidev))
+				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;
+		if (sym53c8xx_pci_init(tpnt, pcidev, devp)) {
+			continue;
+		}
+		++count;
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+		if (nvp) {
+			ncr_get_nvram(devp, nvp);
+			switch(nvp->type) {
+			case SCSI_NCR_SYMBIOS_NVRAM:
+				/*
+				 *   Switch to the other nvram buffer, so that 
+				 *   nvram0 will contain the first Symbios 
+				 *   format NVRAM content with boot order.
+				 */
+				nvp = &nvram;
+				msg = "with Symbios NVRAM";
+				break;
+			case SCSI_NCR_TEKRAM_NVRAM:
+				msg = "with Tekram NVRAM";
+				break;
+			}
+		}
+#endif
+#ifdef	SCSI_NCR_PQS_PDS_SUPPORT
+		if (devp->pqs_pds)
+			msg = "(NCR PQS/PDS)";
+#endif
+		printk(KERN_INFO NAME53C8XX ": 53c%s detected %s\n",
+		       devp->chip.name, msg);
+	}
+
+	/*
+	**    If we have found a SYMBIOS NVRAM, use first the NVRAM boot 
+	**    sequence as device boot order.
+	**    check devices in the boot record against devices detected. 
+	**    attach devices if we find a match. boot table records that 
+	**    do not match any detected devices will be ignored. 
+	**    devices that do not match any boot table will not be attached
+	**    here but will attempt to be attached during the device table 
+	**    rescan.
+	*/
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+	if (!nvp || nvram0.type != SCSI_NCR_SYMBIOS_NVRAM)
+		goto next;
+	for (i = 0; i < 4; i++) {
+		Symbios_host *h = &nvram0.data.Symbios.host[i];
+		for (j = 0 ; j < count ; j++) {
+			devp = &devtbl[j];
+			if (h->device_fn != devp->slot.device_fn ||
+			    h->bus_nr	 != devp->slot.bus	 ||
+			    h->device_id != devp->chip.device_id)
+				continue;
+			if (devp->attach_done)
+				continue;
+			if (h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) {
+				ncr_get_nvram(devp, nvp);
+				if (!ncr_attach (tpnt, attach_count, devp))
+					attach_count++;
+			}
+#if 0	/* Restore previous behaviour of ncr53c8xx driver */
+			else if (!(driver_setup.use_nvram & 0x80))
+				printk(KERN_INFO NAME53C8XX
+				       ": 53c%s state OFF thus not attached\n",
+				       devp->chip.name);
+#endif
+			else
+				continue;
+
+			devp->attach_done = 1;
+			break;
+		}
+	}
+next:
+#endif
+
+	/* 
+	**    Rescan device list to make sure all boards attached.
+	**    Devices without boot records will not be attached yet
+	**    so try to attach them here.
+	*/
+	for (i= 0; i < count; i++) {
+		devp = &devtbl[i];
+		if (!devp->attach_done) {
+#ifdef SCSI_NCR_NVRAM_SUPPORT
+			ncr_get_nvram(devp, nvp);
+#endif
+			if (!ncr_attach (tpnt, attach_count, devp))
+				attach_count++;
+		}
+	}
+
+	m_free(devtbl, PAGE_SIZE, "devtbl");
+
+	return attach_count;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sym53c8xx_defs.h linux.18p8/drivers/scsi/sym53c8xx_defs.h
--- linux.vanilla/drivers/scsi/sym53c8xx_defs.h	Sun Jun 11 21:44:17 2000
+++ linux.18p8/drivers/scsi/sym53c8xx_defs.h	Fri Sep 15 15:13:38 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-2000  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.
  */
@@ -96,13 +95,18 @@
 #define SCSI_NCR_DEBUG_INFO_SUPPORT
 #define SCSI_NCR_PCI_FIX_UP_SUPPORT
 #ifdef	SCSI_NCR_PROC_INFO_SUPPORT
-#	ifdef	CONFIG_SCSI_NCR53C8XX_PROFILE
-#		define	SCSI_NCR_PROFILE_SUPPORT
-#	endif
 #	define	SCSI_NCR_USER_COMMAND_SUPPORT
 #	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 +126,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 +137,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
@@ -165,12 +180,16 @@
 #endif
 
 /*
- * Use normal IO if configured. Forced for alpha and ppc.
+ * Use normal IO if configured. Forced for alpha and powerpc.
+ * Powerpc fails copying to on-chip RAM using memcpy_toio().
  */
 #if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED)
 #define	SCSI_NCR_IOMAPPED
-#elif defined(__alpha__) || defined(__powerpc__)
+#elif defined(__alpha__)
+#define	SCSI_NCR_IOMAPPED
+#elif defined(__powerpc__)
 #define	SCSI_NCR_IOMAPPED
+#define SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 #elif defined(__sparc__)
 #undef SCSI_NCR_IOMAPPED
 #endif
@@ -183,8 +202,22 @@
 #undef SCSI_NCR_USE_64BIT_DAC
 
 /*
+ * Immediate arbitration
+ */
+#if defined(CONFIG_SCSI_NCR53C8XX_IARB)
+#define SCSI_NCR_IARB_SUPPORT
+#endif
+
+/*
+ * Should we enable DAC cycles on sparc64 platforms?
+ * Until further investigation we do not enable it
+ * anywhere at the moment.
+ */
+#undef SCSI_NCR_USE_64BIT_DAC
+
+/*
  * 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)
@@ -201,8 +234,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
 
 /*
@@ -246,7 +281,7 @@
  */
 #ifdef CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
 #define SCSI_NCR_SETUP_LED_PIN		(1)
-#define SCSI_NCR_SETUP_DIFF_SUPPORT	(3)
+#define SCSI_NCR_SETUP_DIFF_SUPPORT	(4)
 #else
 #define SCSI_NCR_SETUP_LED_PIN		(0)
 #define SCSI_NCR_SETUP_DIFF_SUPPORT	(0)
@@ -258,6 +293,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.
 */
@@ -266,16 +352,16 @@
 #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 */
@@ -287,11 +373,22 @@
 #ifndef HOSTS_C
 
 /*
-**	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.
-**	MMIO is not used on PPC.
+**	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 CPU support.
+ *  For now, the NCR is only supported in little endian addressing mode, 
+ */
 
 #ifdef	__BIG_ENDIAN
 
@@ -299,19 +396,14 @@
 #error	"BIG ENDIAN byte ordering needs kernel version >= 2.1.0"
 #endif
 
-#if defined(__powerpc__)
 #define	inw_l2b		inw
 #define	inl_l2b		inl
 #define	outw_b2l	outw
 #define	outl_b2l	outl
-#elif defined(__sparc__)
 #define	readw_l2b	readw
 #define	readl_l2b	readl
 #define	writew_b2l	writew
 #define	writel_b2l	writel
-#else
-#error	"Support for BIG ENDIAN is only available for PowerPC and SPARC"
-#endif
 
 #else	/* little endian */
 
@@ -327,7 +419,7 @@
 #define writew_raw(b,a)	((*(volatile unsigned short *) (a)) = (b))
 #define writel_raw(b,a)	((*(volatile unsigned int *) (a)) = (b))
 
-#else	/* Other little-endian (for now alpha) */
+#else	/* Other little-endian */
 #define	inw_raw		inw
 #define	inl_raw		inl
 #define	outw_raw	outw
@@ -344,6 +436,204 @@
 #error	"The NCR in BIG ENDIAN addressing mode is not (yet) supported"
 #endif
 
+
+/*
+ *  IA32 architecture does not reorder STORES and prevents
+ *  LOADS from passing STORES. It is called `program order' 
+ *  by Intel and allows device drivers to deal with memory 
+ *  ordering by only ensuring that the code is not reordered  
+ *  by the compiler when ordering is required.
+ *  Other architectures implement a weaker ordering that 
+ *  requires memory barriers (and also IO barriers when they 
+ *  make sense) to be used.
+ *  We want to be paranoid for ppc and ia64. :)
+ */
+
+#if	defined	__i386__
+#define MEMORY_BARRIER()	do { ; } while(0)
+#elif	defined	__powerpc__
+#define MEMORY_BARRIER()	__asm__ volatile("eieio; sync" : : : "memory")
+#elif	defined	__ia64__
+#define MEMORY_BARRIER()	__asm__ volatile("mf.a; mf" : : : "memory")
+#else
+#define MEMORY_BARRIER()	mb()
+#endif
+
+
+/*
+ *  If the NCR uses big endian addressing mode over the 
+ *  PCI, actual io register addresses for byte and word 
+ *  accesses must be changed according to lane routing.
+ *  Btw, ncr_offb() and ncr_offw() macros only apply to 
+ *  constants and so donnot generate bloated code.
+ */
+
+#if	defined(SCSI_NCR_BIG_ENDIAN)
+
+#define ncr_offb(o)	(((o)&~3)+((~((o)&3))&3))
+#define ncr_offw(o)	(((o)&~3)+((~((o)&3))&2))
+
+#else
+
+#define ncr_offb(o)	(o)
+#define ncr_offw(o)	(o)
+
+#endif
+
+/*
+ *  If the CPU and the NCR use same endian-ness adressing,
+ *  no byte reordering is needed for script patching.
+ *  Macro cpu_to_scr() is to be used for script patching.
+ *  Macro scr_to_cpu() is to be used for getting a DWORD 
+ *  from the script.
+ */
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_le32(dw)
+#define scr_to_cpu(dw)	le32_to_cpu(dw)
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_be32(dw)
+#define scr_to_cpu(dw)	be32_to_cpu(dw)
+
+#else
+
+#define cpu_to_scr(dw)	(dw)
+#define scr_to_cpu(dw)	(dw)
+
+#endif
+
+/*
+ *  Access to the controller chip.
+ *
+ *  If SCSI_NCR_IOMAPPED is defined, the driver will use 
+ *  normal IOs instead of the MEMORY MAPPED IO method  
+ *  recommended by PCI specifications.
+ *  If all PCI bridges, host brigdes and architectures 
+ *  would have been correctly designed for PCI, this 
+ *  option would be useless.
+ *
+ *  If the CPU and the NCR use same endian-ness adressing,
+ *  no byte reordering is needed for accessing chip io 
+ *  registers. Functions suffixed by '_raw' are assumed 
+ *  to access the chip over the PCI without doing byte 
+ *  reordering. Functions suffixed by '_l2b' are 
+ *  assumed to perform little-endian to big-endian byte 
+ *  reordering, those suffixed by '_b2l' blah, blah,
+ *  blah, ...
+ */
+
+#if defined(SCSI_NCR_IOMAPPED)
+
+/*
+ *  IO mapped only input / ouput
+ */
+
+#define	INB_OFF(o)		inb (np->base_io + ncr_offb(o))
+#define	OUTB_OFF(o, val)	outb ((val), np->base_io + ncr_offb(o))
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define	INW_OFF(o)		inw_l2b (np->base_io + ncr_offw(o))
+#define	INL_OFF(o)		inl_l2b (np->base_io + (o))
+
+#define	OUTW_OFF(o, val)	outw_b2l ((val), np->base_io + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_b2l ((val), np->base_io + (o))
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define	INW_OFF(o)		inw_b2l (np->base_io + ncr_offw(o))
+#define	INL_OFF(o)		inl_b2l (np->base_io + (o))
+
+#define	OUTW_OFF(o, val)	outw_l2b ((val), np->base_io + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_l2b ((val), np->base_io + (o))
+
+#else
+
+#define	INW_OFF(o)		inw_raw (np->base_io + ncr_offw(o))
+#define	INL_OFF(o)		inl_raw (np->base_io + (o))
+
+#define	OUTW_OFF(o, val)	outw_raw ((val), np->base_io + ncr_offw(o))
+#define	OUTL_OFF(o, val)	outl_raw ((val), np->base_io + (o))
+
+#endif	/* ENDIANs */
+
+#else	/* defined SCSI_NCR_IOMAPPED */
+
+/*
+ *  MEMORY mapped IO input / output
+ */
+
+#define INB_OFF(o)		readb((char *)np->reg + ncr_offb(o))
+#define OUTB_OFF(o, val)	writeb((val), (char *)np->reg + ncr_offb(o))
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_l2b((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_l2b((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_b2l((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_b2l((val), (char *)np->reg + (o))
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_b2l((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_b2l((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_l2b((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_l2b((val), (char *)np->reg + (o))
+
+#else
+
+#define INW_OFF(o)		readw_raw((char *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_raw((char *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_raw((val), (char *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_raw((val), (char *)np->reg + (o))
+
+#endif
+
+#endif	/* defined SCSI_NCR_IOMAPPED */
+
+#define INB(r)		INB_OFF (offsetof(struct ncr_reg,r))
+#define INW(r)		INW_OFF (offsetof(struct ncr_reg,r))
+#define INL(r)		INL_OFF (offsetof(struct ncr_reg,r))
+
+#define OUTB(r, val)	OUTB_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTW(r, val)	OUTW_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTL(r, val)	OUTL_OFF (offsetof(struct ncr_reg,r), (val))
+
+/*
+ *  Set bit field ON, OFF 
+ */
+
+#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
+#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
+
+/*
+ *  We normally want the chip to have a consistent view
+ *  of driver internal data structures when we restart it.
+ *  Thus these macros.
+ */
+#define OUTL_DSP(v)				\
+	do {					\
+		MEMORY_BARRIER();		\
+		OUTL (nc_dsp, (v));		\
+	} while (0)
+
+#define OUTONB_STD()				\
+	do {					\
+		MEMORY_BARRIER();		\
+		OUTONB (nc_dcntl, (STD|NOCOM));	\
+	} while (0)
+
+
 /*
 **	NCR53C8XX Device Ids
 */
@@ -400,6 +690,15 @@
 #define PCI_DEVICE_ID_NCR_53C1510D 0xa
 #endif
 
+#ifndef PCI_DEVICE_ID_LSI_53C1010
+#define PCI_DEVICE_ID_LSI_53C1010 0x20
+#endif
+
+#ifndef PCI_DEVICE_ID_LSI_53C1010_66
+#define PCI_DEVICE_ID_LSI_53C1010_66 0x21
+#endif
+
+
 /*
 **   NCR53C8XX devices features table.
 */
@@ -407,31 +706,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)
@@ -465,49 +768,65 @@
  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}\
+ 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}		\
+ ,									\
+ {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010_66",  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|FE_66MHZ}	\
 }
 
 /*
@@ -526,7 +845,9 @@
 	PCI_DEVICE_ID_NCR_53C895,	\
 	PCI_DEVICE_ID_NCR_53C896,	\
 	PCI_DEVICE_ID_NCR_53C895A,	\
-	PCI_DEVICE_ID_NCR_53C1510D	\
+	PCI_DEVICE_ID_NCR_53C1510D,	\
+ 	PCI_DEVICE_ID_LSI_53C1010,	\
+ 	PCI_DEVICE_ID_LSI_53C1010_66	\
 }
 
 /*
@@ -560,7 +881,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];
 };
 
@@ -579,7 +901,7 @@
 	0,					\
 	0,					\
 	1,					\
-	1,					\
+	0,					\
 	SCSI_NCR_SETUP_DEFAULT_TAGS,		\
 	SCSI_NCR_SETUP_DEFAULT_SYNC,		\
 	0x00,					\
@@ -592,7 +914,8 @@
 	1,					\
 	0,					\
 	0,					\
-	255					\
+	255,					\
+	0x00					\
 }
 
 /*
@@ -722,7 +1045,8 @@
 **	Tekram NvRAM data format.
 */
 #define TEKRAM_NVRAM_SIZE 64
-#define TEKRAM_NVRAM_ADDRESS 0
+#define TEKRAM_93C46_NVRAM_ADDRESS 0
+#define TEKRAM_24C16_NVRAM_ADDRESS 0x40
 
 struct Tekram_nvram {
 	struct Tekram_target {
@@ -771,6 +1095,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 */
@@ -781,12 +1106,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               */
 
@@ -837,7 +1164,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     */
@@ -858,12 +1188,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              */
 
@@ -874,6 +1206,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       */
@@ -894,7 +1227,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      */
@@ -905,6 +1238,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;
 
@@ -934,6 +1268,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		*/
   
@@ -954,6 +1289,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  */
@@ -967,6 +1303,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    */
@@ -988,12 +1325,28 @@
 /*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_char   nc_aipcntl0;	/* Epat Control 1 C1010 only        */
+/*bf*/  u_char   nc_aipcntl1;	/* AIP Control C1010_66 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;
@@ -1001,6 +1354,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              */ 
+
 };
 
 /*-----------------------------------------------------------
@@ -1013,16 +1377,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.
+**
 **-----------------------------------------------------------
 */
 
@@ -1030,11 +1392,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.
@@ -1053,9 +1418,15 @@
 **-----------------------------------------------------------
 */
 
-#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 OPC_MOVE          0x08000000
+
+#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;
@@ -1068,7 +1439,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]
@@ -1083,7 +1454,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;
@@ -1302,7 +1673,7 @@
 **	Conditions:
 **	     WHEN (phase)
 **	     IF   (phase)
-**	     CARRY
+**	     CARRYSET
 **	     DATA (data, mask)
 **
 **-----------------------------------------------------------
@@ -1367,6 +1738,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
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/Config.in linux.18p8/drivers/sound/Config.in
--- linux.vanilla/drivers/sound/Config.in	Sat Sep  9 18:42:42 2000
+++ linux.18p8/drivers/sound/Config.in	Wed Sep 13 16:18:07 2000
@@ -19,7 +19,9 @@
 
 dep_tristate 'Crystal CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND
 dep_tristate 'Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND
-dep_tristate 'Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
+if [ "$CONFIG_PCI" = "y" ]; then
+   dep_tristate 'Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
+fi
 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
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/ac97_codec.c linux.18p8/drivers/sound/ac97_codec.c
--- linux.vanilla/drivers/sound/ac97_codec.c	Sat Sep  9 18:42:42 2000
+++ linux.18p8/drivers/sound/ac97_codec.c	Mon Sep  4 16:40:47 2000
@@ -66,6 +66,7 @@
 	{0x43525923, "Cirrus Logic CS4298"    , NULL},
 	{0x4352592B, "Cirrus Logic CS4294"    , NULL},
 	{0x43525931, "Cirrus Logic CS4299"    , NULL},
+	{0x43525934, "Cirrus Logic CS4299"    , NULL},
 	{0x4e534331, "National Semiconductor LM4549" ,	NULL},
 	{0x53494c22, "Silicon Laboratory Si3036"     ,	NULL},
 	{0x53494c23, "Silicon Laboratory Si3038"     ,  NULL},
@@ -556,6 +557,7 @@
 	id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
 	for (i = 0; i < arraysize(ac97_codec_ids); i++) {
 		if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+			codec->id = ac97_codec_ids[i].id;
 			codec->name = ac97_codec_ids[i].name;
 			codec->codec_init = ac97_codec_ids[i].init;
 			break;
@@ -647,6 +649,7 @@
 {
 	codec->codec_write(codec, AC97_POWER_CONTROL,
 		codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
+	return 0;
 }
 	
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs4281.c linux.18p8/drivers/sound/cs4281.c
--- linux.vanilla/drivers/sound/cs4281.c	Sat Sep  9 18:42:42 2000
+++ linux.18p8/drivers/sound/cs4281.c	Wed Sep  6 09:22:43 2000
@@ -75,24 +75,6 @@
 
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE < 0x02030d
-#ifdef MODULE
-#define __exit
-#define module_exit(x) void cleanup_module(void) { x(); }
-#define module_init(x) int init_module(void) { return x(); }
-#else
-#define __exit __attribute__ ((unused, __section__ (".text.init")))
-#define module_exit(x) // nothing 
-#define module_init(x) // nothing 
-#endif
-
-#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL
-#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL}
-#define wait_queue_head_t struct wait_queue *
-#define init_waitqueue_head(w) *(w) = 0
-#define init_MUTEX(m) *(m) = MUTEX
-#endif
-
 // MIDI buffer sizes 
 #define MIDIINBUF  500
 #define MIDIOUTBUF 500
@@ -182,7 +164,7 @@
 };
 
 
-struct cs4281_state *devs = NULL;
+static struct cs4281_state *devs = NULL;
 // --------------------------------------------------------------------- 
 //
 //		Hardware Interfaces For the CS4281
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs46xx.c linux.18p8/drivers/sound/cs46xx.c
--- linux.vanilla/drivers/sound/cs46xx.c	Sat Sep  9 18:42:42 2000
+++ linux.18p8/drivers/sound/cs46xx.c	Tue Sep  5 21:47:23 2000
@@ -1141,10 +1141,16 @@
 	return mask;
 }
 
+/*
+ *	We let users mmap the ring buffer. Its not the real DMA buffer but
+ *	that side of the code is hidden in the IRQ handling. We do a software
+ *	emulation of DMA from a 64K or so buffer into a 2K FIFO. 
+ *	(the hardware probably deserves a moan here but Crystal send me nice
+ *	toys ;)).
+ */
+ 
 static int cs_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	return -EINVAL;
-#if 0	
 	struct cs_state *state = (struct cs_state *)file->private_data;
 	struct dmabuf *dmabuf = &state->dmabuf;
 	int ret;
@@ -1171,7 +1177,6 @@
 	dmabuf->mapped = 1;
 
 	return 0;
-#endif	
 }
 
 static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -1822,34 +1827,15 @@
 	return cs461x_peekBA0(card, BA0_ACSDA);
 }
 
-/*
- *	Do we have the CD potentially enabled either left or right ?
- */
- 
-static int cd_active(int r)
-{
-	int l=(r>>8)&0x7;
-	r&=7;
-	if(l==1 || r==1)
-		return 1;		/* CD input */
-	if(l==5 || r==5)
-		return 1;		/* Mixer input */
-	if(l==6 || r==6)
-		return 1;		/* Mixer 16bit input */
-	return 0;
-}
-
 static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
 {
 	struct cs_card *card = dev->private_data;
 	int count;
 	int val2;
-	int val3;
 	
-	if(reg==AC97_RECORD_SELECT || reg == AC97_CD_VOL)
+	if(reg == AC97_CD_VOL)
 	{
-		val2 = cs_ac97_get(dev, AC97_RECORD_SELECT);
-		val3 = cs_ac97_get(dev, AC97_CD_VOL);
+		val2 = cs_ac97_get(dev, AC97_CD_VOL);
 	}
 	
 	/*
@@ -1907,35 +1893,31 @@
 	 *
 	 *	When the CD mute changes we adjust the power level if the
 	 *	CD was a valid input.
+	 *
+	 *      We also check for CD volume != 0, as the CD mute isn't
+	 *      normally tweaked from userspace.
 	 */
 	 
-	if(reg==AC97_RECORD_SELECT && cd_active(val)!=cd_active(val2))
-	{
-		int n=-1;
-		/* If we are turning on the port and it is not muted then
-		   bump the power level. If we are turning it off and its
-		   not muted drop the power level */
-		if(cd_active(val))
-			n=1;
-		if(!(val3 & 0x8000))
-			card->amplifier_ctrl(card, n);
-	}
-	
 	/* CD mute change ? */
 	
 	if(reg==AC97_CD_VOL)
 	{
-		if(cd_active(val2))
+		/* Mute bit change ? */
+		if((val2^val)&0x8000 || ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val))
 		{
-			/* Mute bit change ? */
-			if((val3^val)&0x8000)
-			{
-				/* Mute on */
-				if(val&0x8000)
-					card->amplifier_ctrl(card, -1);
-				else /* Mute off power on */
-					card->amplifier_ctrl(card, 1);
-			}
+			/* This is a hack but its cleaner than the alternatives.
+			   Right now card->ac97_codec[0] might be NULL as we are
+			   still doing codec setup. This does an early assignment
+			   to avoid the problem if it occurs */
+			   
+			if(card->ac97_codec[0]==NULL)
+				card->ac97_codec[0]=dev;
+				
+			/* Mute on */
+			if(val&0x8000 || val == 0x1f1f)
+				card->amplifier_ctrl(card, -1);
+			else /* Mute off power on */
+				card->amplifier_ctrl(card, 1);
 		}
 	}
 }
@@ -2036,12 +2018,6 @@
 		
 		card->ac97_features = eid;
 			
-		/* If the card has the CD enabled then bump the power to
-		   account for it */
-		   	
-		if(cd_active(cs_ac97_get(codec, AC97_RECORD_SELECT)))
-			card->amplifier_ctrl(card, 1);
-			
 		if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) {
 			printk(KERN_ERR "cs461x: couldn't register mixer!\n");
 			kfree(codec);
@@ -2343,7 +2319,7 @@
 	 *  generating bit clock (so we don't try to start the PLL without an
 	 *  input clock).
 	 */
-	mdelay(5);		/* 1 should be enough ?? */
+	mdelay(5);		/* 1 should be enough ?? (and pigs might fly) */
 
 	/*
 	 *  Set the serial port timing configuration, so that
@@ -2809,4 +2785,4 @@
 MODULE_PARM(external_amp, "i");
 MODULE_PARM(thinkpad, "i");
 
-#endif
\ No newline at end of file
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/8010.h linux.18p8/drivers/sound/emu10k1/8010.h
--- linux.vanilla/drivers/sound/emu10k1/8010.h	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/8010.h	Tue Sep  5 21:50:50 2000
@@ -41,10 +41,14 @@
 
 /* ------------------- DEFINES -------------------- */
 
-#define CMD_WRITEFN0	0x0
-#define CMD_READFN0	0x1
-#define CMD_WRITEPTR	0x2
-#define CMD_READPTR	0x3
+#define CMD_WRITEFN0		0x0
+#define CMD_READFN0		0x1
+#define CMD_WRITEPTR		0x2
+#define CMD_READPTR		0x3
+#define CMD_SETRECSRC		0x4
+#define CMD_GETRECSRC		0x5
+#define CMD_GETVOICEPARAM	0x6
+#define CMD_SETVOICEPARAM	0x7
 
 struct mixer_private_ioctl {
 	u32 cmd;
@@ -175,6 +179,7 @@
 #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_AC3ENABLE_GPSPDIF  0x00000020      /* Channels 0 and 1 replace GPSPDIF             */
 #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	*/
@@ -337,10 +342,12 @@
 #define CCCA_CURRADDR		0x18000008
 
 #define CCR			0x09		/* Cache control register				*/
-#define CCR_CACHEINVALIDSIZE	0xfe000000	/* Number of invalid samples cache for this channel    	*/
+#define CCR_CACHEINVALIDSIZE	0x07190009
+#define CCR_CACHEINVALIDSIZE_MASK	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		0x06100009
 #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	*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/Makefile linux.18p8/drivers/sound/emu10k1/Makefile
--- linux.vanilla/drivers/sound/emu10k1/Makefile	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/Makefile	Tue Sep  5 21:50:50 2000
@@ -4,16 +4,16 @@
 
 ifeq ($(CONFIG_SOUND_EMU10K1),y)
     O_TARGET := emu10k1.o
-    O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o emuadxmg.o \
-             emu_wrapper.o hwaccess.o irqmgr.o main.o midi.o mixer.o \
-             recmgr.o timer.o voicemgr.o
+    O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \
+             emuadxmg.o emu_wrapper.o hwaccess.o irqmgr.o main.o midi.o \
+             mixer.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 emuadxmg.o \
-             emu_wrapper.o hwaccess.o irqmgr.o main.o midi.o mixer.o \
-             recmgr.o timer.o voicemgr.o
+    O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \
+             emuadxmg.o emu_wrapper.o hwaccess.o irqmgr.o main.o midi.o \
+             mixer.o recmgr.o timer.o voicemgr.o
   endif
 endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/audio.c linux.18p8/drivers/sound/emu10k1/audio.c
--- linux.vanilla/drivers/sound/emu10k1/audio.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/audio.c	Mon Sep 11 17:07:42 2000
@@ -34,7 +34,13 @@
 #include <linux/module.h>
 #include <linux/poll.h>
 #include <linux/malloc.h>
+#include <linux/version.h>
+#include <linux/bitops.h>
 #include <asm/io.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/wrapper.h>
+
 
 #include "hwaccess.h"
 #include "cardwo.h"
@@ -47,7 +53,7 @@
 static void calculate_ifrag(struct wiinst *);
 
 /* Audio file operations */
-static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int nOrigin)
+static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int origin)
 {
 	return -ESPIPE;
 }
@@ -61,7 +67,7 @@
 
 	GET_INODE_STRUCT();
 
-	DPD(4, "emu10k1_audio_read(), buffer=%p, count=%d\n", buffer, (u32) count);
+	DPD(3, "emu10k1_audio_read(), buffer=%p, count=%d\n", buffer, (u32) count);
 
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
@@ -112,7 +118,7 @@
 
 		spin_unlock_irqrestore(&wiinst->lock, flags);
 
-		DPD(4, "bytestocopy --> %d\n", bytestocopy);
+		DPD(3, "bytestocopy --> %d\n", bytestocopy);
 
 		if ((bytestocopy >= wiinst->buffer.fragment_size)
 		    || (bytestocopy >= count)) {
@@ -140,7 +146,7 @@
 		}
 	}
 
-	DPD(4, "bytes copied -> %d\n", (u32) ret);
+	DPD(3, "bytes copied -> %d\n", (u32) ret);
 
 	return ret;
 }
@@ -154,7 +160,7 @@
 
 	GET_INODE_STRUCT();
 
-	DPD(4, "emu10k1_audio_write(), buffer=%p, count=%d\n", buffer, (u32) count);
+	DPD(3, "emu10k1_audio_write(), buffer=%p, count=%d\n", buffer, (u32) count);
 
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
@@ -200,7 +206,7 @@
 		emu10k1_waveout_getxfersize(woinst, &bytestocopy);
 		spin_unlock_irqrestore(&woinst->lock, flags);
 
-		DPD(4, "bytestocopy --> %d\n", bytestocopy);
+		DPD(3, "bytestocopy --> %d\n", bytestocopy);
 
 		if ((bytestocopy >= woinst->buffer.fragment_size)
 		    || (bytestocopy >= count)) {
@@ -238,7 +244,7 @@
 		}
 	}
 
-	DPD(4, "bytes copied -> %d\n", (u32) ret);
+	DPD(3, "bytes copied -> %d\n", (u32) ret);
 
 	return ret;
 }
@@ -278,7 +284,7 @@
 
 					/* Undo marking the pages as reserved */
 					for (i = 0; i < woinst->buffer.pages; i++)
-						set_bit(PG_reserved, &mem_map[MAP_NR(woinst->buffer.addr[i])].flags);
+						mem_map_reserve(MAP_NR(woinst->buffer.addr[i]));
 				}
 
 				emu10k1_waveout_close(wave_dev);
@@ -328,7 +334,7 @@
 
 					/* Undo marking the pages as reserved */
 					for (i = 0; i < woinst->buffer.pages; i++)
-						set_bit(PG_reserved, &mem_map[MAP_NR(woinst->buffer.addr[i])].flags);
+						mem_map_reserve(MAP_NR(woinst->buffer.addr[i]));
 				}
 
 				emu10k1_waveout_close(wave_dev);
@@ -367,7 +373,9 @@
 	case SNDCTL_DSP_SPEED:
 		DPF(2, "SNDCTL_DSP_SPEED:\n");
 
-		get_user_ret(val, (int *) arg, -EFAULT);
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+
 		DPD(2, "val is %d\n", val);
 
 		if (val > 0) {
@@ -421,7 +429,9 @@
 	case SNDCTL_DSP_STEREO:
 		DPF(2, "SNDCTL_DSP_STEREO:\n");
 
-		get_user_ret(val, (int *) arg, -EFAULT);
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+
 		DPD(2, " val is %d\n", val);
 
 		if (file->f_mode & FMODE_READ) {
@@ -466,7 +476,9 @@
 	case SNDCTL_DSP_CHANNELS:
 		DPF(2, "SNDCTL_DSP_CHANNELS:\n");
 
-		get_user_ret(val, (int *) arg, -EFAULT);
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+
 		DPD(2, " val is %d\n", val);
 
 		if (val > 0) {
@@ -528,7 +540,9 @@
 	case SNDCTL_DSP_SETFMT:	/* Same as SNDCTL_DSP_SAMPLESIZE */
 		DPF(2, "SNDCTL_DSP_SETFMT:\n");
 
-		get_user_ret(val, (int *) arg, -EFAULT);
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+
 		DPD(2, " val is %d\n", val);
 
 		if (val != AFMT_QUERY) {
@@ -630,7 +644,8 @@
 	case SNDCTL_DSP_SETTRIGGER:
 		DPF(2, "SNDCTL_DSP_SETTRIGGER:\n");
 
-		get_user_ret(val, (int *) arg, -EFAULT);
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
 
 		if (file->f_mode & FMODE_WRITE) {
 			spin_lock_irqsave(&woinst->lock, flags);
@@ -856,7 +871,8 @@
 	case SNDCTL_DSP_SETFRAGMENT:
 		DPF(2, "SNDCTL_DSP_SETFRAGMENT:\n");
 
-		get_user_ret(val, (int *) arg, -EFAULT);
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
 
 		DPD(2, "val is 0x%x\n", val);
 
@@ -947,7 +963,7 @@
 
 			/* Now mark the pages as reserved, otherwise remap_page_range doesn't do what we want */
 			for (i = 0; i < woinst->buffer.pages; i++)
-				set_bit(PG_reserved, &mem_map[MAP_NR(woinst->buffer.addr[i])].flags);
+				mem_map_reserve(MAP_NR(woinst->buffer.addr[i]));
 		}
 
 		size = vma->vm_end - vma->vm_start;
@@ -995,7 +1011,7 @@
 	list_for_each(entry, &emu10k1_devs) {
 		card = list_entry(entry, struct emu10k1_card, list);
 
-		if (!((card->audio1_num ^ minor) & ~0xf) || !((card->audio2_num ^ minor) & ~0xf))
+		if (!((card->audio_num ^ minor) & ~0xf) || !((card->audio1_num ^ minor) & ~0xf))
 			break;
 	}
 
@@ -1026,7 +1042,10 @@
 			return -ENODEV;
 		}
 
-		switch (card->wavein->recsrc) {
+		wiinst->recsrc = card->wavein.recsrc;
+                wiinst->fxwc = card->wavein.fxwc;
+
+		switch (wiinst->recsrc) {
 		case WAVERECORD_AC97:
 			wiinst->format.samplingrate = 8000;
 			wiinst->format.bitsperchannel = 16;
@@ -1040,7 +1059,7 @@
 		case WAVERECORD_FX:
 			wiinst->format.samplingrate = 48000;
 			wiinst->format.bitsperchannel = 16;
-			wiinst->format.channels = 2;
+			wiinst->format.channels = hweight32(wiinst->fxwc);
 			break;
 		default:
 			BUG();
@@ -1049,7 +1068,6 @@
 
 		wiinst->state = WAVE_STATE_CLOSED;
 
-		wiinst->recsrc = card->wavein->recsrc;
 		wiinst->buffer.ossfragshift = 0;
 		wiinst->buffer.fragment_size = 0;
 		wiinst->buffer.numfrags = 0;
@@ -1087,7 +1105,7 @@
 		woinst->buffer.fragment_size = 0;
 		woinst->buffer.ossfragshift = 0;
 		woinst->buffer.numfrags = 0;
-		woinst->device = (card->audio2_num == minor);
+		woinst->device = (card->audio1_num == minor);
 
 		init_waitqueue_head(&woinst->wait_queue);
 
@@ -1149,9 +1167,11 @@
 static int emu10k1_audio_release(struct inode *inode, struct file *file)
 {
 	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
-	struct emu10k1_card *card = wave_dev->card;
+	struct emu10k1_card *card;
 	unsigned long flags;
 
+	card = wave_dev->card;
+
 	DPF(2, "emu10k1_audio_release()\n");
 
 	if (file->f_mode & FMODE_WRITE) {
@@ -1177,7 +1197,7 @@
 
 				/* Undo marking the pages as reserved */
 				for (i = 0; i < woinst->buffer.pages; i++)
-					set_bit(PG_reserved, &mem_map[MAP_NR(woinst->buffer.addr[i])].flags);
+					mem_map_reserve(MAP_NR(woinst->buffer.addr[i]));
 			}
 
 			emu10k1_waveout_close(wave_dev);
@@ -1451,7 +1471,7 @@
 	if (bytestocopy >= wiinst->buffer.fragment_size)
 		wake_up_interruptible(&wiinst->wait_queue);
 	else
-		DPD(4, "Not enough transfer size, %d\n", bytestocopy);
+		DPD(3, "Not enough transfer size, %d\n", bytestocopy);
 
 	return;
 }
@@ -1482,18 +1502,18 @@
 	if (bytestocopy >= woinst->buffer.fragment_size)
 		wake_up_interruptible(&woinst->wait_queue);
 	else
-		DPD(4, "Not enough transfer size -> %d\n", bytestocopy);
+		DPD(3, "Not enough transfer size -> %d\n", bytestocopy);
 
 	return;
 }
 
 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,
+	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,
 };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/cardmi.c linux.18p8/drivers/sound/emu10k1/cardmi.c
--- linux.vanilla/drivers/sound/emu10k1/cardmi.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/cardmi.c	Tue Sep  5 21:50:50 2000
@@ -81,7 +81,7 @@
 	DPF(2, "emu10k1_mpuin_open\n");
 
 	if (!(card_mpuin->status & FLAGS_AVAILABLE))
-		return CTSTATUS_INUSE;
+		return -1;
 
 	/* Copy open info and mark channel as in use */
 	card_mpuin->openinfo = *openinfo;
@@ -98,7 +98,7 @@
 	emu10k1_mpu_reset(card);
 	emu10k1_mpu_acquire(card);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int emu10k1_mpuin_close(struct emu10k1_card *card)
@@ -110,7 +110,7 @@
 	/* Check if there are pending input SysEx buffers */
 	if (card_mpuin->firstmidiq != NULL) {
 		ERROR();
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	/* Disable RX interrupt */
@@ -121,7 +121,7 @@
 	card_mpuin->status |= FLAGS_AVAILABLE;	/* set */
 	card_mpuin->status &= ~FLAGS_MIDM_STARTED;	/* clear */
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /* Adds MIDI buffer to local queue list                         */
@@ -139,7 +139,7 @@
 
 	if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) {
 		/* Message lost */
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	midiq->next = NULL;
@@ -161,7 +161,7 @@
 
 	spin_unlock_irqrestore(&card_mpuin->lock, flags);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /* First set the Time Stamp if MIDI IN has not started.         */
@@ -179,7 +179,7 @@
 	if (card_mpuin->status & FLAGS_MIDM_STARTED) {
 		DPF(2, "Time Stamp not changed\n");
 	} else {
-		while (emu10k1_mpu_read_data(card, &dummy) == CTSTATUS_SUCCESS);
+		while (!emu10k1_mpu_read_data(card, &dummy));
 
 		card_mpuin->status |= FLAGS_MIDM_STARTED;	/* set */
 
@@ -193,7 +193,7 @@
 		emu10k1_irq_enable(card, INTE_MIDIRXENABLE);
 	}
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /* Disable the RX Irq.  If a partial recorded buffer            */
@@ -234,7 +234,7 @@
 		}
 	}
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /* Disable the RX Irq.  If any buffer                           */
@@ -264,7 +264,7 @@
 	card_mpuin->lastmidiq = NULL;
 	card_mpuin->status &= ~FLAGS_MIDM_STARTED;
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /* Passes the message with the data back to the client          */
@@ -307,7 +307,7 @@
 	/* Notify client that Sysex buffer has been sent */
 	emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 void emu10k1_mpuin_bh(unsigned long refdata)
@@ -349,13 +349,13 @@
 	idx = card_mpuin->qtail;
 
 	while (1) {
-		if (emu10k1_mpu_read_data(card, &MPUIvalue) == CTSTATUS_SUCCESS) {
+		if (emu10k1_mpu_read_data(card, &MPUIvalue) < 0) {
+			break;
+		} else {
 			++count;
 			card_mpuin->midiq[idx].data = MPUIvalue;
 			card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ;
 			idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
-		} else {
-			break;
 		}
 	}
 
@@ -365,7 +365,7 @@
 		tasklet_hi_schedule(&card_mpuin->tasklet);
 	}
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /*****************************************************************************/
@@ -385,7 +385,7 @@
 	card_mpuin->timestart = 0;
 	card_mpuin->timein = 0;
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /* FIXME: This should be a macro */
@@ -430,7 +430,7 @@
 
 		case 0x7:
 			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0);
-			return CTSTATUS_ERROR;
+			return -1;
 
 		case 0x2:
 			card_mpuin->laststate = card_mpuin->curstate;
@@ -452,7 +452,7 @@
 
 	default:
 		DPF(2, "BUG: default case hit\n");
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
@@ -494,7 +494,7 @@
 
 		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	card_mpuin->data = data;
@@ -525,7 +525,7 @@
 
 		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	card_mpuin->curstate = STIN_3BYTE;
@@ -537,7 +537,7 @@
 
 	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
@@ -578,7 +578,7 @@
 
 		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	card_mpuin->curstate = STIN_2BYTE;
@@ -588,7 +588,7 @@
 
 	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data)
@@ -620,7 +620,7 @@
 
 		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	card_mpuin->curstate = card_mpuin->laststate;
@@ -630,7 +630,7 @@
 
 	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data)
@@ -662,7 +662,7 @@
 
 		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	card_mpuin->data = data;
@@ -694,7 +694,7 @@
 
 		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	card_mpuin->curstate = card_mpuin->laststate;
@@ -706,7 +706,7 @@
 
 	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data)
@@ -744,7 +744,7 @@
 			kfree(midiq);
 		}
 
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	if (card_mpuin->firstmidiq) {
@@ -780,7 +780,7 @@
 			kfree(midiq);
 		}
 
-		return CTSTATUS_SUCCESS;
+		return 0;
 	}
 
 	if (card_mpuin->firstmidiq) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/cardmo.c linux.18p8/drivers/sound/emu10k1/cardmo.c
--- linux.vanilla/drivers/sound/emu10k1/cardmo.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/cardmo.c	Tue Sep  5 21:50:50 2000
@@ -48,7 +48,7 @@
 	DPF(2, "emu10k1_mpuout_open()\n");
 
 	if (!(card_mpuout->status & FLAGS_AVAILABLE))
-		return CTSTATUS_INUSE;
+		return -1;
 
 	/* Copy open info and mark channel as in use */
 	card_mpuout->intr = 0;
@@ -61,7 +61,7 @@
 	emu10k1_mpu_reset(card);
 	emu10k1_mpu_acquire(card);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int emu10k1_mpuout_close(struct emu10k1_card *card)
@@ -96,7 +96,7 @@
 
 	spin_unlock_irqrestore(&card_mpuout->lock, flags);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /* If there isn't enough buffer space, reject Midi Buffer.     *
@@ -113,14 +113,14 @@
 	DPF(2, "emu10k1_mpuout_add_buffer()\n");
 
 	if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND)
-		return CTSTATUS_SUCCESS;
+		return 0;
 
 	midihdr->flags |= MIDIBUF_INQUEUE;
 	midihdr->flags &= ~MIDIBUF_DONE;
 
 	if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) {
 		/* Message lost */
-		return CTSTATUS_NOMEMORY;
+		return -1;
 	}
 
 	midiq->next = NULL;
@@ -147,7 +147,7 @@
 
 	spin_unlock_irqrestore(&card_mpuout->lock, flags);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 void emu10k1_mpuout_bh(unsigned long refdata)
@@ -155,7 +155,6 @@
 	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;
 	unsigned long flags;
@@ -166,14 +165,12 @@
 		midiq = card_mpuout->firstmidiq;
 
 		while (cByteSent < 4 && midiq->sizeLeft) {
-			status = emu10k1_mpu_write_data(card, *midiq->midibyte);
-
-			if (status == CTSTATUS_SUCCESS) {
+			if (emu10k1_mpu_write_data(card, *midiq->midibyte) < 0) {
+				DPF(2, "emu10k1_mpuoutDpcCallback error!!\n");
+			} else {
 				++cByteSent;
 				--midiq->sizeLeft;
 				++midiq->midibyte;
-			} else {
-				DPF(2, "emu10k1_mpuoutDpcCallback error!!\n");
 			}
 		}
 
@@ -229,5 +226,5 @@
 
 	tasklet_hi_schedule(&card_mpuout->tasklet);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/cardwi.c linux.18p8/drivers/sound/emu10k1/cardwi.c
--- linux.vanilla/drivers/sound/emu10k1/cardwi.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/cardwi.c	Tue Sep  5 21:50:50 2000
@@ -67,20 +67,9 @@
 
 		break;
 
+	/* these can't be changed from the original values */
 	case WAVERECORD_MIC:
-		wave_fmt->channels = 1;
-		wave_fmt->samplingrate = 0x1F40;
-		wave_fmt->bitsperchannel = 16;
-		break;
-
 	case WAVERECORD_FX:
-		if (wave_fmt->channels > 16)
-			wave_fmt->channels = 16;
-		else if (wave_fmt->channels < 1)
-			wave_fmt->channels = 1;
-
-		wave_fmt->samplingrate = 0xBB80;
-		wave_fmt->bitsperchannel = 16;
 		break;
 
 	default:
@@ -123,13 +112,13 @@
 
 	switch (wiinst->recsrc) {
 	case WAVERECORD_AC97:
-		wiinst_tmp = &card->wavein->ac97;
+		wiinst_tmp = &card->wavein.ac97;
 		break;
 	case WAVERECORD_MIC:
-		wiinst_tmp = &card->wavein->mic;
+		wiinst_tmp = &card->wavein.mic;
 		break;
 	case WAVERECORD_FX:
-		wiinst_tmp = &card->wavein->fx;
+		wiinst_tmp = &card->wavein.fx;
 		break;
 	default:
 		BUG();
@@ -191,13 +180,13 @@
 	spin_lock_irqsave(&card->lock, flags);
 	switch (wave_dev->wiinst->recsrc) {
 	case WAVERECORD_AC97:
-		card->wavein->ac97 = NULL;
+		card->wavein.ac97 = NULL;
 		break;
 	case WAVERECORD_MIC:
-		card->wavein->mic = NULL;
+		card->wavein.mic = NULL;
 		break;
 	case WAVERECORD_FX:
-		card->wavein->fx = NULL;
+		card->wavein.fx = NULL;
 		break;
 	default:
 		BUG();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/cardwi.h linux.18p8/drivers/sound/emu10k1/cardwi.h
--- linux.vanilla/drivers/sound/emu10k1/cardwi.h	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/cardwi.h	Fri Sep 15 15:12:33 2000
@@ -48,7 +48,6 @@
         u32 addrreg;
         u32 idxreg;
         u32 adcctl;
-	u32 fxwc;
 	void *addr;
 	u8 cov;
 	dma_addr_t dma_handle;	
@@ -66,18 +65,8 @@
 	u32 blocks;
 	spinlock_t lock;
 	u8 recsrc;
+	u16 fxwc;
 };
-
-struct emu10k1_wavein 
-{
-	struct wiinst *ac97;
-	struct wiinst *mic;
-	struct wiinst *fx;
-
-	u8 recsrc;
-	u32 fxwc;
-};
-
 
 #define WAVEIN_MAXBUFSIZE         65536
 #define WAVEIN_MINBUFSIZE	  368
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/cardwo.c linux.18p8/drivers/sound/emu10k1/cardwo.c
--- linux.vanilla/drivers/sound/emu10k1/cardwo.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/cardwo.c	Tue Sep  5 21:50:50 2000
@@ -119,66 +119,86 @@
 
 static int get_voice(struct emu10k1_card *card, struct woinst *woinst)
 {
-	struct voice_allocdesc voice_allocdesc;
-
+	struct emu_voice *voice = &woinst->voice;
 	/* Allocate voices here, if no voices available, return error.
 	 * Init voice_allocdesc first.*/
 
-	voice_allocdesc.usage = VOICE_USAGE_PLAYBACK;
+	voice->usage = VOICE_USAGE_PLAYBACK;
 
-	voice_allocdesc.flags = 0;
+	voice->flags = 0;
 
 	if (woinst->format.channels == 2)
-		voice_allocdesc.flags |= VOICE_FLAGS_STEREO;
+		voice->flags |= VOICE_FLAGS_STEREO;
 
 	if (woinst->format.bitsperchannel == 16)
-		voice_allocdesc.flags |= VOICE_FLAGS_16BIT;
+		voice->flags |= VOICE_FLAGS_16BIT;
 
-	if (emu10k1_voice_alloc(card, &woinst->voice, &voice_allocdesc) < 0)
+	if (emu10k1_voice_alloc(card, voice) < 0)
 		return -1;
 
 	/* Calculate pitch */
-	woinst->voice.initial_pitch = (u16) (srToPitch(woinst->format.samplingrate) >> 8);
-	woinst->voice.pitch_target = samplerate_to_linearpitch(woinst->format.samplingrate);
+	voice->initial_pitch = (u16) (srToPitch(woinst->format.samplingrate) >> 8);
+	voice->pitch_target = samplerate_to_linearpitch(woinst->format.samplingrate);
+
+	DPD(2, "Initial pitch --> 0x%x\n", voice->initial_pitch);
+
+	voice->startloop = (woinst->buffer.emupageindex << 12) / woinst->format.bytespersample;
+	voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespersample;
+	voice->start = voice->startloop;
+
+	if (voice->flags & VOICE_FLAGS_STEREO) {
+		voice->params[0].send_a = card->waveout.send_a[1];
+		voice->params[0].send_b = card->waveout.send_b[1];
+		voice->params[0].send_c = card->waveout.send_c[1];
+		voice->params[0].send_d = card->waveout.send_d[1];
+
+		if (woinst->device)
+			voice->params[0].send_routing = 0xd23c;
+		else
+			voice->params[0].send_routing = card->waveout.send_routing[1];
 
-	DPD(2, "Initial pitch --> 0x%x\n", woinst->voice.initial_pitch);
+		voice->params[0].volume_target = 0xffff;
+		voice->params[0].initial_fc = 0xff;
+		voice->params[0].initial_attn = 0x00;
+		voice->params[0].byampl_env_sustain = 0x7f;
+		voice->params[0].byampl_env_decay = 0x7f;
+
+		voice->params[1].send_a = card->waveout.send_a[2];
+		voice->params[1].send_b = card->waveout.send_b[2];
+		voice->params[1].send_c = card->waveout.send_c[2];
+		voice->params[1].send_d = card->waveout.send_d[2];
 
-	woinst->voice.start = (woinst->buffer.emupageindex << 12) / woinst->format.bytespersample;
-	woinst->voice.end = woinst->voice.start + woinst->buffer.size / woinst->format.bytespersample;
-	woinst->voice.startloop = woinst->voice.start;
-	woinst->voice.endloop = woinst->voice.end;
-
-	woinst->voice.params[0].send_a=0x00;
-	woinst->voice.params[0].send_b=0x00;
-	woinst->voice.params[0].send_c=0xff;
-	woinst->voice.params[0].send_d=0x00;
-
-	woinst->voice.params[0].bus_routing= (woinst->device == 1) ? 0xd23c : 0xd01c;
-	woinst->voice.params[0].volume_target=0xffff;
-	woinst->voice.params[0].initial_fc=0xff;
-	woinst->voice.params[0].initial_attn=0x00;
-	woinst->voice.params[0].byampl_env_sustain = 0x7f;
-	woinst->voice.params[0].byampl_env_decay = 0x7f;
-
-	if (woinst->voice.flags & VOICE_FLAGS_STEREO) {
-		woinst->voice.params[1].send_a=0x00;
-		woinst->voice.params[1].send_b=0xff;		
-		woinst->voice.params[1].send_c=0x00;
-		woinst->voice.params[1].send_d=0x00;
-
-		woinst->voice.params[1].bus_routing= (woinst->device == 1) ? 0xd23c : 0xd01c;
-		woinst->voice.params[1].volume_target=0xffff;
-		woinst->voice.params[1].initial_fc=0xff;
-		woinst->voice.params[1].initial_attn=0x00;
-		woinst->voice.params[1].byampl_env_sustain = 0x7f;
-		woinst->voice.params[1].byampl_env_decay = 0x7f;
+		if (woinst->device)
+			voice->params[1].send_routing = 0xd23c;
+		else
+			voice->params[1].send_routing = card->waveout.send_routing[2];
+
+		voice->params[1].volume_target = 0xffff;
+		voice->params[1].initial_fc = 0xff;
+		voice->params[1].initial_attn = 0x00;
+		voice->params[1].byampl_env_sustain = 0x7f;
+		voice->params[1].byampl_env_decay = 0x7f;
 	} else {
-		woinst->voice.params[0].send_b=0xff;
+		voice->params[0].send_a = card->waveout.send_a[0];
+		voice->params[0].send_b = card->waveout.send_b[0];
+		voice->params[0].send_c = card->waveout.send_c[0];
+		voice->params[0].send_d = card->waveout.send_d[0];
+
+		if (woinst->device)
+                        voice->params[0].send_routing = 0xd23c;
+                else
+			voice->params[0].send_routing = card->waveout.send_routing[0];
+
+		voice->params[0].volume_target = 0xffff;
+		voice->params[0].initial_fc = 0xff;
+		voice->params[0].initial_attn = 0x00;
+		voice->params[0].byampl_env_sustain = 0x7f;
+		voice->params[0].byampl_env_decay = 0x7f;
 	}
 
-	DPD(2, "voice: start=0x%x, end=0x%x, startloop=0x%x, endloop=0x%x\n", woinst->voice.start, woinst->voice.end,woinst->voice.startloop, woinst->voice.endloop);
+	DPD(2, "voice: startloop=0x%x, endloop=0x%x\n", voice->startloop, voice->endloop);
 
-	emu10k1_voice_playback_setup(&woinst->voice);
+	emu10k1_voice_playback_setup(voice);
 
 	return 0;
 }
@@ -245,7 +265,8 @@
 
 	DPF(2, "emu10k1_waveout_start()\n");
 	/* Actual start */
-	emu10k1_voice_start(&woinst->voice);
+
+	emu10k1_voice_start(&woinst->voice, woinst->total_played);
 
 	emu10k1_timer_enable(card, &woinst->timer);
 
@@ -351,15 +372,20 @@
 
 	i = str / PAGE_SIZE;
 	j = str % PAGE_SIZE;
-	k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
-	copy_from_user(dst[i] + j, src, k);
-	len -= k;
-	while (len >= PAGE_SIZE) {
-		copy_from_user(dst[++i], src + k, PAGE_SIZE);
-		k += PAGE_SIZE;
-		len -= PAGE_SIZE;
-	}
-	copy_from_user(dst[++i], src + k, len);
+
+	if (len > PAGE_SIZE - j) {
+		k = PAGE_SIZE - j;
+		copy_from_user(dst[i] + j, src, k);
+		len -= k;
+		while (len > PAGE_SIZE) {
+                	copy_from_user(dst[++i], src + k, PAGE_SIZE);
+                	k += PAGE_SIZE;
+                	len -= PAGE_SIZE;
+        	}
+        	copy_from_user(dst[++i], src + k, len);
+
+	} else
+		copy_from_user(dst[i] + j, src, len);
 
 	return;
 }
@@ -370,14 +396,19 @@
 
 	i = str / PAGE_SIZE;
 	j = str % PAGE_SIZE;
-	k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
-	memset(dst[i] + j, src, k);
-	len -= k;
-	while (len >= PAGE_SIZE) {
-		memset(dst[++i], src, PAGE_SIZE);
-		len -= PAGE_SIZE;
-	}
-	memset(dst[++i], src, len);
+
+	if (len > PAGE_SIZE - j) {
+                k = PAGE_SIZE - j;
+                memset(dst[i] + j, src, k);
+                len -= k;
+                while (len > PAGE_SIZE) {
+                        memset(dst[++i], src, PAGE_SIZE);
+                        len -= PAGE_SIZE;
+                }
+                memset(dst[++i], src, len);
+
+        } else
+                memset(dst[i] + j, src, len);
 
 	return;
 }
@@ -463,22 +494,15 @@
 	if (!(woinst->state & WAVE_STATE_STARTED)) {
 		hw_pos = woinst->buffer.hw_pos;
 	} else {
-		u32 samples;
 		/* hw_pos in sample units */
-		emu10k1_voice_getcontrol(&woinst->voice, CCCA_CURRADDR, &hw_pos);
+		hw_pos = sblive_readptr(woinst->voice.card, CCCA_CURRADDR, woinst->voice.num);
 
-		hw_pos -= woinst->voice.start;
+		if(hw_pos < woinst->voice.start)
+			hw_pos += woinst->buffer.size / woinst->format.bytespersample - woinst->voice.start;
+		else
+			hw_pos -= woinst->voice.start;
 
 		hw_pos *= woinst->format.bytespersample;
-
-		/* Refer to voicemgr.c, CA is not started at zero.
-		 * We need to take this into account. */
-		samples = 64 * woinst->format.channels - 4 * woinst->format.bytesperchannel;
-
-		if (hw_pos >= samples)
-			hw_pos -= samples;
-		else
-			hw_pos += woinst->buffer.size - samples;
 	}
 
 	diff = (woinst->buffer.size + hw_pos - woinst->buffer.hw_pos) % woinst->buffer.size;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/cardwo.h linux.18p8/drivers/sound/emu10k1/cardwo.h
--- linux.vanilla/drivers/sound/emu10k1/cardwo.h	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/cardwo.h	Fri Sep 15 15:12:33 2000
@@ -44,7 +44,7 @@
 #define WAVEOUT_DEFAULTFRAGLEN	20 /* Time to play a fragment in ms (latency) */
 #define WAVEOUT_DEFAULTBUFLEN	500 /* Time to play the entire buffer in ms */
 
-#define WAVEOUT_MINFRAGSHIFT	4
+#define WAVEOUT_MINFRAGSHIFT	6
 
 struct waveout_buffer {
 	u16 ossfragshift;
@@ -76,16 +76,6 @@
         u32 blocks;
 	u8 device;
 	spinlock_t lock;
-};
-
-struct emu10k1_waveout
-{
-	u32 globalvol;
-	u32 mute;
-	u32 left;
-	u32 right;
-	u32 globalreverb;
-	u32 globalchorus;
 };
 
 int emu10k1_waveout_open(struct emu10k1_wavedevice *);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/ecard.c linux.18p8/drivers/sound/emu10k1/ecard.c
--- linux.vanilla/drivers/sound/emu10k1/ecard.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/sound/emu10k1/ecard.c	Tue Sep  5 21:50:50 2000
@@ -0,0 +1,155 @@
+/*     
+ **********************************************************************
+ *     ecard.c - E-card initialization code
+ *     Copyright 1999, 2000 Creative Labs, Inc. 
+ * 
+ ********************************************************************** 
+ * 
+ *     Date                 Author          Summary of changes 
+ *     ----                 ------          ------------------ 
+ *     October 20, 1999     Bertrand Lee    base code release 
+ * 
+ ********************************************************************** 
+ * 
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */ 
+
+#include "ecard.h"
+#include "hwaccess.h"
+
+/* Private routines */
+static void ecard_setadcgain(struct emu10k1_card *, struct ecard_state *, u16);
+static void ecard_write(struct emu10k1_card *, u32);
+
+/**************************************************************************
+ * @func Set the gain of the ECARD's CS3310 Trim/gain controller.  The
+ * trim value consists of a 16bit value which is composed of two
+ * 8 bit gain/trim values, one for the left channel and one for the
+ * right channel.  The following table maps from the Gain/Attenuation
+ * value in decibels into the corresponding bit pattern for a single
+ * channel.
+ */
+
+static void ecard_setadcgain(struct emu10k1_card *card, struct ecard_state *ecard, u16 gain)
+{
+	u32 currbit;
+	ecard->adc_gain = gain;
+
+	/* Enable writing to the TRIM registers */
+	ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN);
+
+	/* Do it again to insure that we meet hold time requirements */
+	ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN);
+
+	for (currbit = (1L << 15); currbit; currbit >>= 1) {
+
+		u32 value = ecard->control_bits & ~(EC_TRIM_CSN|EC_TRIM_SDATA);
+
+		if (gain & currbit)
+		      value |= EC_TRIM_SDATA;
+
+		/* Clock the bit */
+		ecard_write(card, value);
+		ecard_write(card, value | EC_TRIM_SCLK);
+		ecard_write(card, value);
+	}
+
+	ecard_write(card, ecard->control_bits);
+}
+
+/**************************************************************************
+ * @func Clock bits into the Ecard's control latch.  The Ecard uses a
+ *  control latch will is loaded bit-serially by toggling the Modem control
+ *  lines from function 2 on the E8010.  This function hides these details
+ *  and presents the illusion that we are actually writing to a distinct
+ *  register.
+ */
+static void ecard_write(struct emu10k1_card *card, u32 value)
+{
+	u16 count;
+	u32 data, hcvalue;
+
+	hcvalue = emu10k1_readfn0(card, HCFG) & ~(HOOKN_BIT|HANDN_BIT|PULSEN_BIT);
+
+	emu10k1_writefn0(card, HCFG, hcvalue);
+
+	for (count = 0 ; count < EC_NUM_CONTROL_BITS; count++) {
+	
+		/* Set up the value */
+		data = ((value & 0x1) ? PULSEN_BIT : 0);
+		value >>= 1;
+
+		emu10k1_writefn0(card, HCFG, hcvalue | data);
+
+		/* Clock the shift register */
+		emu10k1_writefn0(card, HCFG, hcvalue | data | HANDN_BIT);
+		emu10k1_writefn0(card, HCFG, hcvalue | data);
+	}
+
+	/* Latch the bits */
+	emu10k1_writefn0(card, HCFG, hcvalue | HOOKN_BIT);
+	emu10k1_writefn0(card, HCFG, hcvalue);
+}
+
+int __devinit emu10k1_ecard_init(struct emu10k1_card *card)
+{
+	u32 hcvalue;
+	struct ecard_state ecard;
+
+	/* Set up the initial settings */
+	ecard.mux0_setting = EC_DEFAULT_SPDIF0_SEL;
+	ecard.mux1_setting = EC_DEFAULT_SPDIF1_SEL;
+	ecard.mux2_setting = 0;
+	ecard.adc_gain = EC_DEFAULT_ADC_GAIN;
+	ecard.control_bits = EC_RAW_RUN_MODE | 
+                             EC_SPDIF0_SELECT(ecard.mux0_setting) |
+			     EC_SPDIF1_SELECT(ecard.mux1_setting);
+
+
+	/* Step 0: Set the codec type in the hardware control register 
+	 * and enable audio output */
+	hcvalue = emu10k1_readfn0(card, HCFG);
+	emu10k1_writefn0(card, HCFG, hcvalue | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S);
+	emu10k1_readfn0(card, HCFG);
+
+	/* Step 1: Turn off the led and deassert TRIM_CS */
+	ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
+
+	/* Step 2: Calibrate the ADC and DAC */
+	ecard_write(card, EC_DACCAL | EC_LEDN | EC_TRIM_CSN);
+
+	/* Step 3: Wait for awhile; FIXME: Is this correct? */
+
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(HZ);
+
+	/* Step 4: Switch off the DAC and ADC calibration.  Note
+	 * That ADC_CAL is actually an inverted signal, so we assert
+	 * it here to stop calibration.  */
+	ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
+
+	/* Step 4: Switch into run mode */
+	ecard_write(card, ecard.control_bits);
+
+	/* Step 5: Set the analog input gain */
+	ecard_setadcgain(card, &ecard, ecard.adc_gain);
+	
+	return 0;
+}
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/ecard.h linux.18p8/drivers/sound/emu10k1/ecard.h
--- linux.vanilla/drivers/sound/emu10k1/ecard.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/sound/emu10k1/ecard.h	Fri Sep 15 15:12:37 2000
@@ -0,0 +1,113 @@
+/*     
+ **********************************************************************
+ *     ecard.h
+ *     Copyright 1999, 2000 Creative Labs, 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; either version 2 of 
+ *     the License, or (at your option) any later version. 
+ * 
+ *     This program is distributed in the hope that it will be useful, 
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *     GNU General Public License for more details. 
+ * 
+ *     You should have received a copy of the GNU General Public 
+ *     License along with this program; if not, write to the Free 
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 
+ *     USA. 
+ * 
+ ********************************************************************** 
+ */ 
+
+#ifndef _ECARD_H
+#define _ECARD_H
+
+#include "8010.h"
+#include "hwaccess.h"
+#include <linux/init.h>
+
+/* In A1 Silicon, these bits are in the HC register */
+#define HOOKN_BIT   (1L << 12)
+#define HANDN_BIT   (1L << 11)
+#define PULSEN_BIT  (1L << 10)
+
+#define EC_GDI1 (1 << 13)
+#define EC_GDI0 (1 << 14)
+
+#define EC_NUM_CONTROL_BITS 20
+
+#define EC_AC3_DATA_SELN  0x0001L
+#define EC_EE_DATA_SEL    0x0002L
+#define EC_EE_CNTRL_SELN  0x0004L
+#define EC_EECLK          0x0008L
+#define EC_EECS           0x0010L
+#define EC_EESDO          0x0020L
+#define EC_TRIM_CSN	  0x0040L
+#define EC_TRIM_SCLK	  0x0080L
+#define EC_TRIM_SDATA	  0x0100L
+#define EC_TRIM_MUTEN	  0x0200L
+#define EC_ADCCAL	  0x0400L
+#define EC_ADCRSTN	  0x0800L
+#define EC_DACCAL	  0x1000L
+#define EC_DACMUTEN	  0x2000L
+#define EC_LEDN		  0x4000L
+
+#define EC_SPDIF0_SEL_SHIFT	15
+#define EC_SPDIF1_SEL_SHIFT	17	
+#define EC_SPDIF0_SEL_MASK	(0x3L << EC_SPDIF0_SEL_SHIFT)
+#define EC_SPDIF1_SEL_MASK	(0x7L << EC_SPDIF1_SEL_SHIFT)
+#define EC_SPDIF0_SELECT(_x) (((_x) << EC_SPDIF0_SEL_SHIFT) & EC_SPDIF0_SEL_MASK)
+#define EC_SPDIF1_SELECT(_x) (((_x) << EC_SPDIF1_SEL_SHIFT) & EC_SPDIF1_SEL_MASK)
+#define EC_CURRENT_PROM_VERSION 0x01 /* Self-explanatory.  This should
+                                      * be incremented any time the EEPROM's
+                                      * format is changed.  */
+
+#define EC_EEPROM_SIZE	        0x40 /* ECARD EEPROM has 64 16-bit words */
+
+/* Addresses for special values stored in to EEPROM */
+#define EC_PROM_VERSION_ADDR	0x20	/* Address of the current prom version */
+#define EC_BOARDREV0_ADDR	0x21	/* LSW of board rev */
+#define EC_BOARDREV1_ADDR 	0x22	/* MSW of board rev */ 
+
+#define EC_LAST_PROMFILE_ADDR	0x2f
+
+#define EC_SERIALNUM_ADD	0x30	/* First word of serial number.  The number
+                                         * can be up to 30 characters in length
+                                         * and is stored as a NULL-terminated
+                                         * ASCII string.  Any unused bytes must be
+                                         * filled with zeros */
+#define EC_CHECKSUM_ADDR	0x3f    /* Location at which checksum is stored */
+
+
+
+/* Most of this stuff is pretty self-evident.  According to the hardware 
+ * dudes, we need to leave the ADCCAL bit low in order to avoid a DC 
+ * offset problem.  Weird.
+ */
+#define EC_RAW_RUN_MODE	(EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | EC_TRIM_CSN)
+
+
+#define EC_DEFAULT_ADC_GAIN   0xC4C4
+#define EC_DEFAULT_SPDIF0_SEL 0x0
+#define EC_DEFAULT_SPDIF1_SEL 0x4
+
+#define HC_EA 0x01L
+
+/* ECARD state structure.  This structure maintains the state
+ * for various portions of the the ECARD's onboard hardware.
+ */
+struct ecard_state {
+	u32 control_bits;
+	u16 adc_gain;
+	u16 mux0_setting;
+	u16 mux1_setting;
+	u16 mux2_setting;
+};
+
+int emu10k1_ecard_init(struct emu10k1_card *) __devinit;
+
+#endif /* _ECARD_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/emu_wrapper.c linux.18p8/drivers/sound/emu10k1/emu_wrapper.c
--- linux.vanilla/drivers/sound/emu10k1/emu_wrapper.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/emu_wrapper.c	Fri Sep  8 17:05:10 2000
@@ -100,7 +100,7 @@
                 if (!found)
                         count += pci_announce_device(drv, dev);
         }
-#endif        
+#endif
         return count;
 }
 
@@ -119,36 +119,10 @@
                 if (found) {
                         if (drv->remove)
                                 drv->remove(dev);
-                        drvmap[i].dev = NULL;
+                        drvmap[i - 1].dev = NULL;
                 }
         }
-#endif        
-}
-
-unsigned long pci_compat_get_size (struct pci_dev *dev, int n_base)
-{
-        u32 l, sz;
-        int reg = PCI_BASE_ADDRESS_0 + (n_base << 2);
-
-        /* XXX temporarily disable I/O and memory decoding for this device? */
-
-        pci_read_config_dword (dev, reg, &l);
-        if (l == 0xffffffff)
-                return 0;
-
-        pci_write_config_dword (dev, reg, ~0);
-        pci_read_config_dword (dev, reg, &sz);
-        pci_write_config_dword (dev, reg, l);
-
-        if (!sz || sz == 0xffffffff)
-                return 0;
-        if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
-                sz = ~(sz & PCI_BASE_ADDRESS_MEM_MASK);
-        } else {
-                sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff;
-        }
-
-        return sz + 1;
+#endif
 }
 
 int pci_compat_enable_device(struct pci_dev *dev)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/emu_wrapper.h linux.18p8/drivers/sound/emu10k1/emu_wrapper.h
--- linux.vanilla/drivers/sound/emu10k1/emu_wrapper.h	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/emu_wrapper.h	Fri Sep 15 15:12:33 2000
@@ -14,11 +14,6 @@
 #include <linux/tqueue.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 init_MUTEX(a)		*(a) = MUTEX
 
 #define UP_INODE_SEM(a)		up(a)
 #define DOWN_INODE_SEM(a)	down(a)
@@ -44,30 +39,8 @@
 #define __devexit
 #define __devexitdata
 
-/* Not sure what version aliases were introduced in, but certainly in 2.91.66.  */
-#ifdef MODULE
-  #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)
-    #define module_init(x)      int init_module(void) __attribute__((alias(#x)));
-    #define module_exit(x)      void cleanup_module(void) __attribute__((alias(#x)));
-  #else
-    #define module_init(x)      int init_module(void) { return x(); }
-    #define module_exit(x)      void cleanup_module(void) { x(); }
-  #endif
-#else
-  #define module_init(x)
-  #define module_exit(x)
-#endif
-
 #define MODULE_DEVICE_TABLE(foo,bar)
 
-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 pci_dma_supported(dev, mask) 1
 
 #define PCI_ANY_ID (~0)
@@ -88,7 +61,6 @@
 (((dev)->base_address[(bar)] & PCI_BASE_ADDRESS_SPACE) ? \
  ((dev)->base_address[(bar)] & PCI_BASE_ADDRESS_IO_MASK) : \
  ((dev)->base_address[(bar)] & PCI_BASE_ADDRESS_MEM_MASK))
-#define pci_resource_len pci_compat_get_size
 
 struct pci_device_id {
         unsigned int vendor, device;
@@ -111,27 +83,11 @@
 const struct pci_device_id * pci_compat_match_device(const struct pci_device_id *ids, struct pci_dev *dev);
 int pci_compat_register_driver(struct pci_driver *drv);
 void pci_compat_unregister_driver(struct pci_driver *drv);
-unsigned long pci_compat_get_size (struct pci_dev *dev, int n_base);
 int pci_compat_enable_device(struct pci_dev *dev);
 void *compat_request_region (unsigned long start, unsigned long n, const char *name);
 void * pci_compat_get_driver_data (struct pci_dev *dev);
 void pci_compat_set_driver_data (struct pci_dev *dev, void *driver_data);
 
-typedef u32 dma_addr_t;
-
-extern __inline__ int __compat_get_order(unsigned long size)
-{
-        int order;
-
-        size = (size-1) >> (PAGE_SHIFT-1);
-        order = -1;
-        do {
-                size >>= 1;
-                order++;
-        } while (size);
-        return order;
-}
-
 extern __inline__ void *
 pci_alloc_consistent(struct pci_dev *hwdev,
                      size_t size, dma_addr_t *dma_handle) {
@@ -140,7 +96,7 @@
 
         if (hwdev == NULL)
                 gfp |= GFP_DMA;
-        ret = (void *)__get_free_pages(gfp, __compat_get_order(size));
+        ret = (void *)__get_free_pages(gfp, get_order(size));
 
         if (ret != NULL) {
                 memset(ret, 0, size);
@@ -153,7 +109,7 @@
 pci_free_consistent(struct pci_dev *hwdev, size_t size,
                     void *vaddr, dma_addr_t dma_handle)
 {
-        free_pages((unsigned long)vaddr, __compat_get_order(size));
+        free_pages((unsigned long)vaddr, get_order(size));
 }
 
 static inline int pci_module_init(struct pci_driver *drv)
@@ -169,10 +125,5 @@
         
         return -ENODEV;
 }
-
-#define BUG() do { \
-        printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-        __asm__ __volatile__(".byte 0x0f,0x0b"); \
-} while (0)
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/hwaccess.c linux.18p8/drivers/sound/emu10k1/hwaccess.c
--- linux.vanilla/drivers/sound/emu10k1/hwaccess.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/hwaccess.c	Tue Sep  5 21:50:50 2000
@@ -366,7 +366,7 @@
 
 	spin_unlock_irqrestore(&card->lock, flags);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data)
@@ -380,7 +380,7 @@
 
 	spin_unlock_irqrestore(&card->lock, flags);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask)
@@ -399,7 +399,7 @@
 
 	spin_unlock_irqrestore(&card->lock, flags);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /*********************************************************
@@ -415,9 +415,9 @@
 
 	if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
 		outb(data, card->iobase + MUDATA);
-		ret = CTSTATUS_SUCCESS;
+		ret = 0;
 	} else
-		ret = CTSTATUS_BUSY;
+		ret = -1;
 
 	spin_unlock_irqrestore(&card->lock, flags);
 
@@ -433,9 +433,9 @@
 
 	if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
 		*data = inb(card->iobase + MUDATA);
-		ret = CTSTATUS_SUCCESS;
+		ret = 0;
 	} else
-		ret = CTSTATUS_NODATA;
+		ret = -1;
 
 	spin_unlock_irqrestore(&card->lock, flags);
 
@@ -473,12 +473,12 @@
 		spin_unlock_irqrestore(&card->lock, flags);
 
 		if (status == 0xfe)
-			return CTSTATUS_SUCCESS;
+			return 0;
 		else
-			return CTSTATUS_ERROR;
+			return -1;
 	}
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int emu10k1_mpu_acquire(struct emu10k1_card *card)
@@ -486,7 +486,7 @@
 	/* FIXME: This should be a macro */
 	++card->mpuacqcount;
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 int emu10k1_mpu_release(struct emu10k1_card *card)
@@ -494,5 +494,5 @@
 	/* FIXME: this should be a macro */
 	--card->mpuacqcount;
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/hwaccess.h linux.18p8/drivers/sound/emu10k1/hwaccess.h
--- linux.vanilla/drivers/sound/emu10k1/hwaccess.h	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/hwaccess.h	Fri Sep 15 15:12:33 2000
@@ -47,14 +47,6 @@
 #define MAXPAGES	8192 
 #define BUFMAXPAGES     (MAXBUFSIZE / PAGE_SIZE)
 
-enum GlobalErrorCode
-{
-	CTSTATUS_SUCCESS = 0x0000,
-	CTSTATUS_ERROR,
-	CTSTATUS_NOMEMORY,
-	CTSTATUS_INUSE,
-};
-
 #define FLAGS_AVAILABLE     0x0001
 #define FLAGS_READY         0x0002
 
@@ -72,15 +64,36 @@
 #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 ERROR() DPF(1,"error\n");
 #else
 # define DPD(level,x,y...) do { } while (0) /* not debugging: nothing */
 # define DPF(level,x) do { } while (0)
-#define ERROR() do { } while (0)
 #endif /* EMU10K1_DEBUG */
 
+#define ERROR() DPF(1,"error\n")
+
 /* DATA STRUCTURES */
 
+struct emu10k1_waveout
+{
+	u16 send_routing[3];
+
+	u8 send_a[3];
+	u8 send_b[3];
+	u8 send_c[3];
+	u8 send_d[3];
+};
+
+struct emu10k1_wavein
+{
+        struct wiinst *ac97;
+        struct wiinst *mic;
+        struct wiinst *fx;
+
+        u8 recsrc;
+        u32 fxwc;
+};
+
+
 struct emu10k1_card 
 {
 	struct list_head list;
@@ -104,13 +117,13 @@
 	unsigned short		model;
 	unsigned int irq; 
 
-	unsigned long	audio1_num;
-	unsigned long	audio2_num;
-	unsigned long	mixer_num;
-	unsigned long	midi_num;
+	int	audio_num;
+	int	audio1_num;
+	int	mixer_num;
+	int	midi_num;
 
-	struct emu10k1_waveout	*waveout;
-	struct emu10k1_wavein	*wavein;
+	struct emu10k1_waveout	waveout;
+	struct emu10k1_wavein	wavein;
 	struct emu10k1_mpuout	*mpuout;
 	struct emu10k1_mpuin	*mpuin;
 
@@ -126,6 +139,8 @@
 	u32	    has_toslink;	       // TOSLink detection
 
 	u8 chiprev;                    /* Chip revision                */
+
+	int isaps;
 };
 
 int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *);
@@ -146,10 +161,6 @@
 extern struct sblive_pcm_volume_rec sblive_pcm_volume[];
 extern u16 pcm_last_mixer;
 #endif
-
-
-#define ENABLE 			0xffffffff
-#define DISABLE 		0x00000000
 
 #define TIMEOUT 		    16384
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/main.c linux.18p8/drivers/sound/emu10k1/main.c
--- linux.vanilla/drivers/sound/emu10k1/main.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/main.c	Mon Sep 11 17:07:42 2000
@@ -43,6 +43,9 @@
  *	    moved bh's to tasklets, moved to the new PCI driver initialization style.
  *	0.6 Make use of pci_alloc_consistent, improve compatibility layer for 2.2 kernels,
  *	    code reorganization and cleanup.
+ *      0.7 Support for the Emu-APS. Bug fixes for voice cache setup, mmaped sound + poll().
+ *	    Support for setting external TRAM size.
+ *	
  **********************************************************************
  */
 
@@ -61,8 +64,9 @@
 #include "cardmo.h"
 #include "cardmi.h"
 #include "recmgr.h"
+#include "ecard.h"
 
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
 
 /* FIXME: is this right? */
 /* does the card support 32 bit bus master?*/
@@ -76,6 +80,8 @@
 #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
 #endif
 
+#define EMU_APS_SUBID	0x40011102
+ 
 enum {
 	EMU10K1 = 0,
 };
@@ -103,32 +109,38 @@
 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)
+static void __devinit audio_init(struct emu10k1_card *card)
 {
-	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 -1;
-	}
-	memset(card->waveout, 0, sizeof(struct emu10k1_waveout));
-
-	/* 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 -1;
-	}
-	memset(card->wavein, 0, sizeof(struct emu10k1_wavein));
+	/* Assign default playback voice parameters */
+	/* mono voice */
+	card->waveout.send_a[0] = 0x00;
+	card->waveout.send_b[0] = 0xff;
+	card->waveout.send_c[0] = 0xff;
+	card->waveout.send_d[0] = 0x00;
+	card->waveout.send_routing[0] = 0xd01c;
+
+	/* stereo voice */
+	card->waveout.send_a[1] = 0x00;
+        card->waveout.send_b[1] = 0x00;
+        card->waveout.send_c[1] = 0xff;
+        card->waveout.send_d[1] = 0x00;
+        card->waveout.send_routing[1] = 0xd01c;
+
+	card->waveout.send_a[2] = 0x00;
+        card->waveout.send_b[2] = 0xff;
+        card->waveout.send_c[2] = 0x00;
+        card->waveout.send_d[2] = 0x00;
+        card->waveout.send_routing[2] = 0xd01c;
+
+	/* Assign default recording parameters */
+	if(card->isaps)
+		card->wavein.recsrc = WAVERECORD_FX;
+	else
+		card->wavein.recsrc = WAVERECORD_AC97;
 
-	card->wavein->recsrc = WAVERECORD_AC97;
+	card->wavein.fxwc = 0x0003;
 
-	return 0;
+	return;
 }
 
 static void __devinit mixer_init(struct emu10k1_card *card)
@@ -160,46 +172,49 @@
 		94, 95
 	};
 
-	/* Reset */
-	sblive_writeac97(card, AC97_RESET, 0);
-
-#if 0
-	/* Check status word */
-	{
-		u16 reg;
-
-		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);
+	for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) {
+		card->digmix[count] = 0x80000000;
+		sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0);
 	}
-#endif
 
-	/* Set default recording source to mic in */
-	sblive_writeac97(card, AC97_RECORDSELECT, 0);
+	card->modcnt = 0;       // Should this be here or in open() ?
 
-	/* Set default AC97 "PCM" volume to acceptable max */
-	//sblive_writeac97(card, AC97_PCMOUTVOLUME, 0);
-	//sblive_writeac97(card, AC97_LINE2, 0);
+	if (!card->isaps) {
 
-	/* Set default volumes for all mixer channels */
+		for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) {
+			card->digmix[initdig[count]] = 0x7fffffff;
+			sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff);
+		}
 
-	for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) {
-		card->digmix[count] = 0x80000000;
-		sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0);
-	}
+		/* Reset */
+		sblive_writeac97(card, AC97_RESET, 0);
+
+#if 0
+		/* Check status word */
+		{
+			u16 reg;
+
+			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
+
+		/* Set default recording source to mic in */
+		sblive_writeac97(card, AC97_RECORDSELECT, 0);
 
-	for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) {
-		card->digmix[initdig[count]] = 0x7fffffff;
-		sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff);
+		/* 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(initvol) / sizeof(initvol[0]); count++) {
 		emu10k1_mixer_wrch(card, initvol[count].mixch, initvol[count].vol);
 	}
 
-	card->modcnt = 0;	// Should this be here or in open() ?
-
 	return;
 }
 
@@ -236,7 +251,7 @@
 	spin_lock_init(&card->mpuin->lock);
 
 	/* Reset the MPU port */
-	if (emu10k1_mpu_reset(card) != CTSTATUS_SUCCESS) {
+	if (emu10k1_mpu_reset(card) < 0) {
 		ERROR();
 		return -1;
 	}
@@ -280,7 +295,10 @@
 
 static void __devinit fx_init(struct emu10k1_card *card)
 {
-	int i, j, k, l;
+	int i, j, k;
+#ifdef TONE_CONTROL
+	int l;
+#endif	
 	u32 pc = 0;
 
 	for (i = 0; i < 512; i++)
@@ -309,6 +327,7 @@
 			OP(0, 0x102, 0x102, 0x11a + k, 0x16 + j);
 			OP(0, 0x102, 0x102, 0x11c + k, 0x18 + j);
 			OP(0, 0x102, 0x102, 0x11e + k, 0x1a + j);
+#ifdef TONE_CONTROL
 			OP(0, 0x102, 0x102, 0x120 + k, 0x1c + j);
 
 			k = 0x1a0 + i * 8 + j * 4;
@@ -327,10 +346,13 @@
 			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? */
+			if ((i == 0) && !card->isaps)
+				OP(4, 0x20 + (i * 2) + j, 0x40, l + 2, 0x50);	/* FIXME: Is this really needed? */
 			else
 				OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40);
+#else
+			OP(0, 0x20 + (i * 2) + j, 0x102, 0x120 + k, 0x1c + j);
+#endif
 		}
 	}
 	sblive_writeptr(card, DBG, 0, 0);
@@ -482,7 +504,7 @@
 	sblive_writeac97(card, AC97_PCMOUTVOLUME, 0);
 
 	if(card->model == 0x20 || card->model == 0xc400 ||
-	  (card->model == 0x21 && card->chiprev <= 3))
+	  (card->model == 0x21 && card->chiprev < 6))
 	        emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE  | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE);
 	else
 		emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE  | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE);
@@ -520,13 +542,6 @@
 	return 0;
 }
 
-static void __devinit 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);
@@ -596,6 +611,7 @@
 static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
 {
 	struct emu10k1_card *card;
+	u32 subsysvid;
 
 	if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "emu10k1: out of memory\n");
@@ -644,18 +660,21 @@
 		card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase,
 		card->iobase + card->length - 1, card->irq);
 
+	pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
+	card->isaps = (subsysvid == EMU_APS_SUBID);
+
 	spin_lock_init(&card->lock);
 	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) {
+	if ((card->audio_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) {
+	if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) {
 		printk(KERN_ERR "emu10k1: cannot register second audio device!\n");
 		goto err_dev1;
 	}
@@ -675,26 +694,22 @@
 		goto err_emu10k1_init;
 	}
 
-	if (audio_init(card) < 0) {
-		printk(KERN_ERR "emu10k1: cannot initialize audio!\n");
-		goto err_audio_init;
-	}
-
 	if (midi_init(card) < 0) {
 		printk(KERN_ERR "emu10k1: cannot initialize midi!\n");
 		goto err_midi_init;
 	}
 
+	audio_init(card);
 	mixer_init(card);
 
+	if (card->isaps)
+		emu10k1_ecard_init(card);
+
 	list_add(&card->list, &emu10k1_devs);
 
 	return 0;
 
       err_midi_init:
-	audio_exit(card);
-
-      err_audio_init:
 	emu10k1_exit(card);
 
       err_emu10k1_init:
@@ -704,10 +719,10 @@
 	unregister_sound_mixer(card->mixer_num);
 
       err_dev2:
-	unregister_sound_dsp(card->audio2_num);
+	unregister_sound_dsp(card->audio1_num);
 
       err_dev1:
-	unregister_sound_dsp(card->audio1_num);
+	unregister_sound_dsp(card->audio_num);
 
       err_dev0:
 	free_irq(card->irq, card);
@@ -724,13 +739,14 @@
 	struct emu10k1_card *card = PCI_GET_DRIVER_DATA(pci_dev);
 
 	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);
+	unregister_sound_dsp(card->audio_num);
 
 	free_irq(card->irq, card);
 	release_region(card->iobase, card->length);
@@ -772,6 +788,6 @@
 #ifndef MODULE
 int __init init_emu10k1(void)
 {
-	return emu10k1_init_module();
+        return emu10k1_init_module();
 }
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/midi.c linux.18p8/drivers/sound/emu10k1/midi.c
--- linux.vanilla/drivers/sound/emu10k1/midi.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/midi.c	Tue Sep  5 21:50:50 2000
@@ -33,6 +33,9 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/malloc.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 
 #include "hwaccess.h"
@@ -40,7 +43,7 @@
 #include "cardmi.h"
 #include "midi.h"
 
-static spinlock_t midi_spinlock = SPIN_LOCK_UNLOCKED;
+static spinlock_t midi_spinlock __attribute((unused)) = SPIN_LOCK_UNLOCKED;
 
 static void init_midi_hdr(struct midi_hdr *midihdr)
 {
@@ -63,20 +66,20 @@
 	if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) {
 		ERROR();
 		kfree(midihdr);
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
-	if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) != CTSTATUS_SUCCESS) {
+	if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) < 0) {
 		ERROR();
 		kfree(midihdr->data);
 		kfree(midihdr);
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	*midihdrptr = midihdr;
 	list_add_tail(&midihdr->list, &midi_dev->mid_hdrs);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 static int emu10k1_midi_open(struct inode *inode, struct file *file)
@@ -142,8 +145,7 @@
 
 		dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
 
-		if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo)
-		    != CTSTATUS_SUCCESS) {
+		if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) < 0) {
 			ERROR();
 			kfree(midi_dev);
 			MOD_DEC_USE_COUNT;
@@ -151,13 +153,13 @@
 		}
 
 		/* Add two buffers to receive sysex buffer */
-		if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) {
+		if (midiin_add_buffer(midi_dev, &midihdr1) < 0) {
 			kfree(midi_dev);
 			MOD_DEC_USE_COUNT;
 			return -ENODEV;
 		}
 
-		if (midiin_add_buffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) {
+		if (midiin_add_buffer(midi_dev, &midihdr2) < 0) {
 			list_del(&midihdr1->list);
 			kfree(midihdr1->data);
 			kfree(midihdr1);
@@ -172,8 +174,7 @@
 
 		dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
 
-		if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo)
-		    != CTSTATUS_SUCCESS) {
+		if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) {
 			ERROR();
 			kfree(midi_dev);
 			MOD_DEC_USE_COUNT;
@@ -193,8 +194,9 @@
 static int emu10k1_midi_release(struct inode *inode, struct file *file)
 {
 	struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
-	struct emu10k1_card *card = midi_dev->card;
+	struct emu10k1_card *card;
 
+	card = midi_dev->card;
 	DPF(2, "emu10k1_midi_release()\n");
 
 	if (file->f_mode & FMODE_WRITE) {
@@ -259,8 +261,7 @@
 		return -EFAULT;
 
 	if (midi_dev->mistate == MIDIIN_STATE_STOPPED) {
-		if (emu10k1_mpuin_start(midi_dev->card)
-		    != CTSTATUS_SUCCESS) {
+		if (emu10k1_mpuin_start(midi_dev->card) < 0) {
 			ERROR();
 			return -EINVAL;
 		}
@@ -355,7 +356,7 @@
 
 	spin_lock_irqsave(&midi_spinlock, flags);
 
-	if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) != CTSTATUS_SUCCESS) {
+	if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) < 0) {
 		ERROR();
 		kfree(midihdr->data);
 		kfree(midihdr);
@@ -429,19 +430,19 @@
 		break;
 
 	default:		/* Unknown message */
-		return CTSTATUS_ERROR;
+		return -1;
 	}
 
 	spin_unlock_irqrestore(&midi_spinlock, flags);
 
-	return CTSTATUS_SUCCESS;
+	return 0;
 }
 
 /* MIDI file operations */
 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,
+	read:		emu10k1_midi_read,
+	write:		emu10k1_midi_write,
+	poll:		emu10k1_midi_poll,
+	open:		emu10k1_midi_open,
+	release:	emu10k1_midi_release,
 };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/mixer.c linux.18p8/drivers/sound/emu10k1/mixer.c
--- linux.vanilla/drivers/sound/emu10k1/mixer.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/mixer.c	Mon Sep 11 17:07:42 2000
@@ -35,10 +35,13 @@
 
 #define __NO_VERSION__		/* Kernel version only defined once */
 #include <linux/module.h>
+#include <linux/version.h>
+#include <linux/bitops.h>
 #include <asm/uaccess.h>
 
 #include "hwaccess.h"
 #include "8010.h"
+#include "recmgr.h"
 
 #define AC97_PESSIMISTIC
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -49,32 +52,13 @@
 #define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31)
 #define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15)
 
+#define DM_MUTE 0x80000000
+
 #ifdef PRIVATE_PCM_VOLUME
 struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS];
 u16 pcm_last_mixer = 0x6464;
 #endif
 
-/* --------------------------------------------------------------------- */
-
-/*
- * hweightN: returns the hamming weight (i.e. the number
- * of bits set) of a N-bit word
- */
-
-#ifdef hweight32
-#undef hweight32
-#endif
-
-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[] = {
 	SOUND_MASK_MIC,
@@ -85,10 +69,10 @@
 	SOUND_MASK_VOLUME,
 	SOUND_MASK_OGAIN,	/* Used to be PHONEOUT */
 	SOUND_MASK_PHONEIN,
+#ifdef TONE_CONTROL
 	SOUND_MASK_TREBLE,
 	SOUND_MASK_BASS,
-	SOUND_MASK_MONITOR,
-	SOUND_MASK_PCM,
+#endif
 };
 
 static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = {
@@ -135,12 +119,25 @@
 	int nL, nR;
 
 	switch (ch) {
+	case SOUND_MIXER_PCM:
+	case SOUND_MIXER_VOLUME:
+#ifdef TONE_CONTROL
+	case SOUND_MIXER_TREBLE:
+        case SOUND_MIXER_BASS:
+#endif
+                return put_user(0x0000, (int *) arg);
+	default:
+		break;
+	}
+
+	if(card->isaps)
+		return -EINVAL;
+
+	switch (ch) {
 	case SOUND_MIXER_LINE:
 	case SOUND_MIXER_CD:
 	case SOUND_MIXER_VIDEO:
 	case SOUND_MIXER_LINE1:
-	case SOUND_MIXER_PCM:
-	case SOUND_MIXER_VOLUME:
 		sblive_readac97(card, volreg[ch], &reg);
 		nL = ((~(reg >> 8) & 0x1f) * 100) / 32;
 		nR = (~(reg & 0x1f) * 100) / 32;
@@ -166,9 +163,6 @@
 		nR = (~(reg & 0x1f) * 100) / 16;
 		return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
 
-	case SOUND_MIXER_TREBLE:
-	case SOUND_MIXER_BASS:
-		return put_user(0x0000, (int *) arg);
 	default:
 		return -EINVAL;
 	}
@@ -205,6 +199,8 @@
 	[SOUND_MIXER_DIGITAL2] = 19
 };
 
+#ifdef TONE_CONTROL
+
 static const u32 bass_table[41][5] = {
 	{ 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
 	{ 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
@@ -317,6 +313,8 @@
 	}
 }
 
+#endif
+
 static const u32 db_table[101] = {
 	0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
 	0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
@@ -341,6 +339,29 @@
 	0x7fffffff,
 };
 
+static void aps_update_digital(struct emu10k1_card *card)
+{
+	int i, l1, r1, l2, r2;
+	
+	i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]];
+	l1 = (i & 0xff);
+	r1 = ((i >> 8) & 0xff);
+
+	i = card->arrwVol[volidx[SOUND_MIXER_PCM]];
+	l2 = (i & 0xff);
+	r2 = ((i >> 8) & 0xff);
+	
+	for (i = 0; i < 108; i++) {
+		if (card->digmix[i] != DM_MUTE) {
+			if ((i % 18 >= 0) && (i % 18 < 4))
+				card->digmix[i] = ((i & 1) ? ((u64) db_table[r1] * (u64) db_table[r2]) : ((u64) db_table[l1] * (u64) db_table[l2])) >> 31;
+			else
+				card->digmix[i] = (i & 1) ? db_table[r1] : db_table[l1];
+			sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]);
+		}
+	}
+}
+
 static void update_digital(struct emu10k1_card *card)
 {
 	int i, k, l1, r1, l2, r2, l3, r3, l4, r4;
@@ -378,7 +399,7 @@
 	}
 
 	for (i = 0; i < 36; i++) {
-		if (card->digmix[i] != 0x80000000) {
+		if (card->digmix[i] != DM_MUTE) {
 			if (((i >= 0) && (i < 4)) || ((i >= 18) && (i < 22)))
 				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) || (i == 24) || (i == 25))
@@ -391,7 +412,7 @@
 	}
 
 	for (i = 72; i < 90; i++) {
-		if (card->digmix[i] != 0x80000000) {
+		if (card->digmix[i] != DM_MUTE) {
 			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))
@@ -406,15 +427,15 @@
 	for (i = 36; i <= 90; i += 18) {
 		if (i != 72) {
 			for (k = 0; k < 4; k++)
-				if (card->digmix[i + k] != 0x80000000) {
+				if (card->digmix[i + k] != DM_MUTE) {
 					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) {
+			if (card->digmix[i + 6] != DM_MUTE) {
 				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) {
+			if (card->digmix[i + 7] != DM_MUTE) {
 				card->digmix[i + 7] = db_table[r4];
 				sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]);
 			}
@@ -506,10 +527,11 @@
 
 	switch (ch) {
 	case SOUND_MIXER_VOLUME:
-	case SOUND_MIXER_DIGITAL1:
-	case SOUND_MIXER_LINE3:
-		DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
-		update_digital(card);
+		DPF(4, "SOUND_MIXER_VOLUME:\n");
+		if (card->isaps)
+			aps_update_digital(card);
+		else
+			update_digital(card);
 		return 0;
 	case SOUND_MIXER_PCM:
 		DPF(4, "SOUND_MIXER_PCM\n");
@@ -517,6 +539,34 @@
 		if (update_pcm_attn(card, l1, r1))
 			return 0;
 #endif
+		if (card->isaps)
+			aps_update_digital(card);
+		else
+			update_digital(card);
+		return 0;
+#ifdef TONE_CONTROL
+	case SOUND_MIXER_TREBLE:
+                DPF(4, "SOUND_MIXER_TREBLE:\n");
+                set_treble(card, l1, r1);
+                return 0;
+
+        case SOUND_MIXER_BASS:
+                DPF(4, "SOUND_MIXER_BASS:\n");
+                set_bass(card, l1, r1);
+		return 0;
+#endif
+	default:
+		break;
+	}
+
+
+	if (card->isaps)
+		return -EINVAL;
+
+	switch (ch) {
+	case SOUND_MIXER_DIGITAL1:
+	case SOUND_MIXER_LINE3:
+		DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
 		update_digital(card);
 		return 0;
 	case SOUND_MIXER_DIGITAL2:
@@ -573,16 +623,6 @@
 		sblive_writeac97(card, volreg[ch], wval);
 		return 0;
 
-	case SOUND_MIXER_TREBLE:
-		DPF(4, "SOUND_MIXER_TREBLE:\n");
-		set_treble(card, l1, r1);
-		return 0;
-
-	case SOUND_MIXER_BASS:
-		DPF(4, "SOUND_MIXER_BASS:\n");
-		set_bass(card, l1, r1);
-		return 0;
-
 	default:
 		DPF(2, "Got unknown SOUND_MIXER ioctl\n");
 		return -EINVAL;
@@ -598,6 +638,10 @@
 /* Mixer file operations */
 
 /* FIXME: Do we need spinlocks in here? */
+/* WARNING! not all the ioctl's are supported by the emu-APS
+   (anything AC97 related). As a general rule keep the AC97 related ioctls
+   separate from the rest. This will make it easier to rewrite the mixer
+   using the kernel AC97 interface. */ 
 static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	static const char id[] = "SBLive";
@@ -659,11 +703,10 @@
 			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]);
+			sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & DM_MUTE) ? 0 : card->digmix[i]);
 		return 0;
 
 		break;
-#ifdef EMU10K1_DEBUG
 	case SOUND_MIXER_PRIVATE3: {
 			struct mixer_private_ioctl ctl;
 
@@ -671,18 +714,28 @@
 				return -EFAULT;
 
 			switch (ctl.cmd) {
+#ifdef EMU10K1_DEBUG
 			case CMD_WRITEFN0:
-				if(ctl.val[0] >= 0x7f)
-					return -EINVAL;
-
 				emu10k1_writefn0(card, ctl.val[0], ctl.val[1]);
 				return 0;
 				break;
 
-			case CMD_READFN0:
-				if(ctl.val[0] >= 0x7f)
+			case CMD_WRITEPTR:
+				if(ctl.val[1] >= 0x40)
+					return -EINVAL;
+
+				if(ctl.val[0] > 0xff)
 					return -EINVAL;
 
+				if((ctl.val[0] & 0x7ff) > 0x3f)
+					ctl.val[1] = 0x00;
+
+				sblive_writeptr(card, ctl.val[0], ctl.val[1], ctl.val[2]);
+
+				return 0;
+				break;
+#endif
+			case CMD_READFN0:
 				ctl.val[2] = emu10k1_readfn0(card, ctl.val[0]);
 
 				if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
@@ -691,32 +744,68 @@
 				return 0;
 				break;
 
-			case CMD_WRITEPTR:
-				if(ctl.val[1] < 0x00 || ctl.val[1] >= 0x40)
+			case CMD_READPTR:
+				if(ctl.val[1] >= 0x40)
 					return -EINVAL;
 
-				if(ctl.val[0] >= 0x100)
+				if((ctl.val[0] & 0x7ff) > 0xff)
 					return -EINVAL;
 
-				if(ctl.val[0] >= 0x40)
+				if((ctl.val[0] & 0x7ff) > 0x3f)
 					ctl.val[1] = 0x00;
 
-				sblive_writeptr(card, ctl.val[0], ctl.val[1], ctl.val[2]);
+				ctl.val[2] = sblive_readptr(card, ctl.val[0], ctl.val[1]);
+
+				if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+					return -EFAULT;
 
 				return 0;
 				break;
 
-			case CMD_READPTR:
-				if(ctl.val[1] < 0x00 || ctl.val[1] >= 0x40)
+			case CMD_SETRECSRC:
+				switch(ctl.val[0]){
+				case WAVERECORD_AC97:
+					if(card->isaps)
+						return -EINVAL;
+					card->wavein.recsrc = WAVERECORD_AC97;
+					break;
+				case WAVERECORD_MIC:	
+					card->wavein.recsrc = WAVERECORD_MIC;
+					break;
+				case WAVERECORD_FX:
+					card->wavein.recsrc = WAVERECORD_FX;
+					card->wavein.fxwc = ctl.val[1] & 0xffff;
+					if(!card->wavein.fxwc)
+						return -EINVAL;
+					break;
+				default:
 					return -EINVAL;
+				}
+				return 0;
+				break;
 
-				if(ctl.val[0] >= 0x100)
-					return -EINVAL;
+			case CMD_GETRECSRC:
+				ctl.val[0] = card->wavein.recsrc;
+				ctl.val[1] = card->wavein.fxwc;
+				if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
+					return -EFAULT;
 
-				if(ctl.val[0] > 0x40)
-					ctl.val[1] = 0x00;
+				return 0;
+				break;
 
-				ctl.val[2] = sblive_readptr(card, ctl.val[0], ctl.val[1]);
+			case CMD_GETVOICEPARAM:
+
+				ctl.val[0] = card->waveout.send_routing[0];
+				ctl.val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 |
+				             card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24;
+
+				ctl.val[2] = card->waveout.send_routing[1]; 
+				ctl.val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 |
+					     card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24;
+
+				ctl.val[4] = card->waveout.send_routing[2]; 
+				ctl.val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 |
+					     card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24;
 
 				if (copy_to_user((void *) arg, &ctl, sizeof(struct mixer_private_ioctl)))
 					return -EFAULT;
@@ -724,13 +813,35 @@
 				return 0;
 				break;
 
+			case CMD_SETVOICEPARAM:
+				card->waveout.send_routing[0] = ctl.val[0] & 0xffff;
+				card->waveout.send_a[0] = ctl.val[1] & 0xff;
+				card->waveout.send_b[0] = (ctl.val[1] >> 8) & 0xff;
+				card->waveout.send_c[0] = (ctl.val[1] >> 16) & 0xff;
+				card->waveout.send_d[0] = (ctl.val[1] >> 24) & 0xff;
+
+				card->waveout.send_routing[1] = ctl.val[2] & 0xffff;
+				card->waveout.send_a[1] = ctl.val[3] & 0xff;
+				card->waveout.send_b[1] = (ctl.val[3] >> 8) & 0xff;
+				card->waveout.send_c[1] = (ctl.val[3] >> 16) & 0xff;
+				card->waveout.send_d[1] = (ctl.val[3] >> 24) & 0xff;
+
+				card->waveout.send_routing[2] = ctl.val[4] & 0xffff;
+				card->waveout.send_a[2] = ctl.val[5] & 0xff;
+				card->waveout.send_b[2] = (ctl.val[5] >> 8) & 0xff;
+				card->waveout.send_c[2] = (ctl.val[5] >> 16) & 0xff;
+				card->waveout.send_d[2] = (ctl.val[5] >> 24) & 0xff;
+
+				return 0;
+				break;
+
 			default:
 				return -EINVAL;
 				break;
 			}
 		}
 		break;
-#endif
+
 	case SOUND_MIXER_PRIVATE4:{
 			u32 size;
 			int size_reg = 0;
@@ -797,57 +908,107 @@
 
 	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(card, AC97_RECORDSELECT, &reg);
-			return put_user(recsrc[reg & 7], (int *) arg);
-
-		case SOUND_MIXER_DEVMASK:	/* Arg contains a bit for each supported device */
-			DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
+			case SOUND_MIXER_DEVMASK:       /* Arg contains a bit for each supported device */
+                        DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
+			if (card->isaps)
+#ifdef TONE_CONTROL
+				return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+						SOUND_MASK_BASS | SOUND_MASK_TREBLE,
+						(int *) arg); 
+#else
+				return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME,
+						(int *) arg); 
+#endif
+		
+#ifdef TONE_CONTROL
 			return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+                                        SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+                                        SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+                                        SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
+                                        SOUND_MASK_BASS | SOUND_MASK_TREBLE |
+                                        SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
+                                        SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | 
+                                        SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
+#else
+			return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
+                                        SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
+                                        SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+                                        SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
+                                        SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
+                                        SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | 
+                                        SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
+#endif
+
+			case SOUND_MIXER_RECMASK:       /* Arg contains a bit for each supported recording source */
+				DPF(2, "SOUND_MIXER_READ_RECMASK\n");
+				if (card->isaps)
+					return put_user(0, (int *) arg);
+
+				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);
+
+			case SOUND_MIXER_STEREODEVS:    /* Mixer channels supporting stereo */
+				DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
+
+				if (card->isaps)
+#ifdef TONE_CONTROL
+					return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME |
+                                        		SOUND_MASK_BASS | SOUND_MASK_TREBLE,
+                                        		(int *) arg);
+#else
+					return put_user(SOUND_MASK_PCM | SOUND_MASK_VOLUME,
+                                         		(int *) arg);
+#endif
+
+#ifdef TONE_CONTROL
+				return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
 					SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
 					SOUND_MASK_PCM | SOUND_MASK_VOLUME |
-					SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
 					SOUND_MASK_BASS | SOUND_MASK_TREBLE |
-					SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
-					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 | 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_RECLEV | SOUND_MASK_LINE3 |
+					SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
+					SOUND_MASK_LINE2, (int *) arg);
+#else
+				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 |
 					SOUND_MASK_RECLEV | SOUND_MASK_LINE3 |
-					SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | 
+					SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
 					SOUND_MASK_LINE2, (int *) arg);
+#endif
 
-		case SOUND_MIXER_CAPS:
-			DPF(2, "SOUND_MIXER_READ_CAPS\n");
-			return put_user(SOUND_CAP_EXCL_INPUT, (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);
-					}
-				}
-			}
+                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:
+			break;
+		}
+
+		switch (_IOC_NR(cmd)) {
+		case SOUND_MIXER_RECSRC:	/* Arg contains a bit for each recording source */
+			DPF(2, "SOUND_MIXER_READ_RECSRC\n");
+			if (card->isaps)
+				return put_user(0, (int *) arg);
+
+			sblive_readac97(card, AC97_RECORDSELECT, &reg);
+			return put_user(recsrc[reg & 7], (int *) arg);
+
+		default:
 			i = _IOC_NR(cmd);
 			DPD(4, "SOUND_MIXER_READ(%d)\n", i);
 			if (i >= SOUND_MIXER_NRDEVICES)
@@ -862,6 +1023,7 @@
 #endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
 		}
 	}
+
 	/* End of _IOC_READ */
 	if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
 		return -EINVAL;
@@ -873,7 +1035,12 @@
 	case SOUND_MIXER_RECSRC:	/* Arg contains a bit for each recording source */
 		DPF(2, "SOUND_MIXER_WRITE_RECSRC\n");
 
-		get_user_ret(val, (int *) arg, -EFAULT);
+		if (card->isaps)
+			return -EINVAL;
+
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+
 		i = hweight32(val);
 		if (i == 0)
 			return 0;	/* val = mixer_recmask(s); */
@@ -897,7 +1064,9 @@
 
 		if (i >= SOUND_MIXER_NRDEVICES)
 			return -EINVAL;
-		get_user_ret(val, (int *) arg, -EFAULT);
+		if (get_user(val, (int *) arg))
+			return -EFAULT;
+
 		if (emu10k1_mixer_wrch(card, i, val))
 			return -EINVAL;
 
@@ -936,14 +1105,14 @@
 
 static int emu10k1_mixer_release(struct inode *inode, struct file *file)
 {
-	DPF(3, "emu10k1_mixer_release()\n");
+	DPF(4, "emu10k1_mixer_release()\n");
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 struct file_operations emu10k1_mixer_fops = {
-	llseek:emu10k1_mixer_llseek,
-	ioctl:emu10k1_mixer_ioctl,
-	open:emu10k1_mixer_open,
-	release:emu10k1_mixer_release,
+	llseek:		emu10k1_mixer_llseek,
+	ioctl:		emu10k1_mixer_ioctl,
+	open:		emu10k1_mixer_open,
+	release:	emu10k1_mixer_release,
 };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/recmgr.c linux.18p8/drivers/sound/emu10k1/recmgr.c
--- linux.vanilla/drivers/sound/emu10k1/recmgr.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/recmgr.c	Tue Sep  5 21:50:50 2000
@@ -36,9 +36,6 @@
 {
 	DPF(2, "emu10k1_start_record()\n");
 
-	if(buffer->fxwc)
-		sblive_writeptr(card, FXWC, 0, buffer->fxwc);
-
 	sblive_writeptr(card, buffer->sizereg, 0, buffer->sizeregval);
 
 	if (buffer->adcctl)
@@ -109,8 +106,6 @@
 		if (wiinst->format.channels == 2)
 			buffer->adcctl |= ADCCR_RCHANENABLE;
 
-			buffer->fxwc = 0;
-
 		break;
 
 	case WAVERECORD_MIC:
@@ -119,7 +114,6 @@
 		buffer->addrreg = MICBA;
 		buffer->idxreg = MICIDX_IDX;
 		buffer->adcctl = 0;
-		buffer->fxwc = 0;
 		break;
 
 	case WAVERECORD_FX:
@@ -128,7 +122,8 @@
 		buffer->addrreg = FXBA;
 		buffer->idxreg = FXIDX_IDX;
 		buffer->adcctl = 0;
-		buffer->fxwc = 0x0001;
+
+		sblive_writeptr(card, FXWC, 0, wiinst->fxwc);
 		break;
 	default:
 		BUG();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/voicemgr.c linux.18p8/drivers/sound/emu10k1/voicemgr.c
--- linux.vanilla/drivers/sound/emu10k1/voicemgr.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/voicemgr.c	Tue Sep  5 21:50:50 2000
@@ -32,7 +32,7 @@
 #include "voicemgr.h"
 #include "8010.h"
 
-int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice, struct voice_allocdesc *voiceallocdesc)
+int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice)
 {
 	u8 *voicetable = card->voicetable;
 	int i;
@@ -42,17 +42,17 @@
 
 	spin_lock_irqsave(&card->lock, flags);
 
-	if (voiceallocdesc->flags & VOICE_FLAGS_STEREO) {
+	if (voice->flags & VOICE_FLAGS_STEREO) {
 		for (i = 0; i < NUM_G; i += 2)
 			if ((voicetable[i] == VOICE_USAGE_FREE) && (voicetable[i + 1] == VOICE_USAGE_FREE)) {
-				voicetable[i] = voiceallocdesc->usage;
-				voicetable[i + 1] = voiceallocdesc->usage;
+				voicetable[i] = voice->usage;
+				voicetable[i + 1] = voice->usage;
 				break;
 			}
 	} else {
 		for (i = 0; i < NUM_G; i++)
 			if (voicetable[i] == VOICE_USAGE_FREE) {
-				voicetable[i] = voiceallocdesc->usage;
+				voicetable[i] = voice->usage;
 				break;
 			}
 	}
@@ -63,8 +63,6 @@
 		return -1;
 
 	voice->card = card;
-	voice->flags = voiceallocdesc->flags;
-	voice->usage = voiceallocdesc->usage;
 	voice->num = i;
 
 #ifdef PRIVATE_PCM_VOLUME
@@ -99,7 +97,6 @@
 {
 	struct emu10k1_card *card = voice->card;
 	int i;
-	u32 cra, sample;
 	unsigned long flags;
 
 	DPF(2, "emu10k1_voice_free()\n");
@@ -122,9 +119,7 @@
 #endif
 
 	for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
-		int cra1;
-
-		DPD(2, " voice freed -> %d\n", voice->num + i);
+		DPD(2, " voice released -> %d\n", voice->num + i);
 
 		sblive_writeptr_tag(card, voice->num + i, DCYSUSV, 0, 
 							VTFT, 0x0000ffff,
@@ -132,15 +127,6 @@
 							CVCF, 0x0000ffff,
 							CPF, 0,
 							TAGLIST_END);
-
-		sample = (voice->flags & VOICE_FLAGS_16BIT) ? 0 : 0x80808080;
-		cra = sblive_readptr(card, CCR, voice->num) & CCR_READADDRESS_MASK;
-		cra1 = (cra >> 18) & 0xf;
-
-		sblive_writeptr_tag(card, voice->num + i, CCR, cra,
-							CD0 + cra1, sample,
-							CD0 + ((cra1 + 0x1) & 0xf), sample,
-							TAGLIST_END);
 	}
 
 	voice->usage = VOICE_USAGE_FREE;
@@ -157,91 +143,48 @@
 	return;
 }
 
-/*       Sets up a voices for Wave Playback */
-
 void emu10k1_voice_playback_setup(struct emu_voice *voice)
 {
 	struct emu10k1_card *card = voice->card;
-	u32 sample, cra = 0, start = 0;
+	u32 start;
 	int i;
 
 	DPF(2, "emu10k1_voice_playback_setup()\n");
 
-	for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
-		sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].bus_routing << 16);
-
-		/* Stop CA */
-		/* Assumption that PT is alreadt 0 so no harm overwriting */
-		sblive_writeptr(card, PTRX, voice->num + i, (voice->params[i].send_a << 8) | voice->params[i].send_b);
-
-		if (i == 0) {
-			if (voice->flags & VOICE_FLAGS_STEREO) {
-				/* Set stereo bit */
-				cra = 64;
-				sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
-				sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
-			} else {
-				cra = 32;
-				sblive_writeptr(card, CPF, voice->num, 0);
-			}
-
-			if (voice->flags & VOICE_FLAGS_16BIT)
-				sample = 0;
-			else {
-				cra = cra * 2;
-				sample = 0x80808080;
-			}
-			cra -= 4;
+	if (voice->flags & VOICE_FLAGS_STEREO) {
+		/* Set stereo bit */
+		start = 28;
+		sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
+		sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
+	} else {
+		start = 30;
+		sblive_writeptr(card, CPF, voice->num, 0);
+	}
 
-			if (voice->flags & VOICE_FLAGS_STEREO) {
-				/* CCR_READADDRESS_MASK */
-				sblive_writeptr(card, CCR, voice->num, 0x3c << 16);
-				sblive_writeptr_tag(card, voice->num + 1, CCR, cra << 16, CDE, sample, CDF, sample, TAGLIST_END);
-				start = voice->start + cra / 2;
-			} else {
-				sblive_writeptr_tag(card, voice->num, CCR, 0x1c << 16,	/* FIXME: Is 0x1c correct? */
-						    CDE, sample, CDF, sample, TAGLIST_END);
-				start = voice->start + cra;
-			}
+	if(!(voice->flags & VOICE_FLAGS_16BIT))
+		start *= 2;
 
-			if (start > voice->endloop) {
-				start -= voice->endloop;
+	voice->start += start;
 
-				if (voice->flags & VOICE_FLAGS_STEREO)
-					cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9);
-				else
-					cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9);
-
-				start += voice->startloop;
-
-				if (start >= voice->endloop)
-					start = voice->endloop - 1;
-			} else if (voice->flags & VOICE_FLAGS_STEREO)
-				cra = (cra << 25) | (0x3c << 16);
-			else
-				cra = (cra << 25) | (0x1c << 16);
+	for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
+		sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16);
 
-			start |= CCCA_INTERPROM_0;
-		}
+		/* Stop CA */
+		/* Assumption that PT is already 0 so no harm overwriting */
+		sblive_writeptr(card, PTRX, voice->num + i, (voice->params[i].send_a << 8) | voice->params[i].send_b);
 
-		/* CSL, ST, CA */
 		sblive_writeptr_tag(card, voice->num + i,
+				/* CSL, ST, CA */
 				    DSL, voice->endloop | (voice->params[i].send_d << 24),
 				    PSST, voice->startloop | (voice->params[i].send_c << 24),
-				    CCCA, start | ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
+				    CCCA, (voice->start) | CCCA_INTERPROM_0 | ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
 				    /* Clear filter delay memory */
 				    Z1, 0,
 				    Z2, 0,
 				    /* Invalidate maps */
 				    MAPA, MAP_PTI_MASK | (card->silentpage.dma_handle * 2),
-				    MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2), TAGLIST_END);
-
-		/* Fill cache */
-		if (i == 0)
-			sblive_writeptr(card, CCR, voice->num, cra);
-
-		/* modulation envelope */
-		sblive_writeptr_tag(card, voice->num + i,
+				    MAPB, MAP_PTI_MASK | (card->silentpage.dma_handle * 2),
+				/* modulation envelope */
 				    CVCF, 0x0000ffff,
 				    VTFT, 0x0000ffff,
 				    ATKHLDM, 0,
@@ -252,12 +195,12 @@
 				    TREMFRQ, 0,
 				    FM2FRQ2, 0,
 				    ENVVAL, 0x8000,
-				    /* volume envelope */
+				/* volume envelope */
 				    ATKHLDV, 0x7f7f,
 				    ENVVOL, 0x8000,
-				    /* filter envelope */
+				/* filter envelope */
 				    PEFE_FILTERAMOUNT, 0x7f,
-				    /* pitch envelope */
+				/* pitch envelope */
 				    PEFE_PITCHAMOUNT, 0, TAGLIST_END);
 
 #ifdef PRIVATE_PCM_VOLUME
@@ -286,13 +229,49 @@
 	return;
 }
 
-void emu10k1_voice_start(struct emu_voice *voice)
+void emu10k1_voice_start(struct emu_voice *voice, int set)
 {
 	struct emu10k1_card *card = voice->card;
 	int i;
 
 	DPF(2, "emu10k1_voice_start()\n");
 
+	if (!set) {
+		u32 cra, ccis, cs, sample;
+		if (voice->flags & VOICE_FLAGS_STEREO) {
+			cra = 64;
+			ccis = 28;
+			cs = 4;
+		} else {
+			cra = 64;
+			ccis = 30;
+			cs = 2;
+		}
+
+		if(voice->flags & VOICE_FLAGS_16BIT) {
+			sample = 0x00000000;
+		} else {
+			sample = 0x80808080;		
+			ccis *= 2;
+		}
+
+		for(i = 0; i < cs; i++)
+	                sblive_writeptr(card, CD0 + i, voice->num, sample);
+
+		/* Reset cache */
+		sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, 0);
+		if (voice->flags & VOICE_FLAGS_STEREO)
+			sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num + 1, 0);
+
+		sblive_writeptr(card, CCR_READADDRESS, voice->num, cra);
+
+		if (voice->flags & VOICE_FLAGS_STEREO)
+			sblive_writeptr(card, CCR_READADDRESS, voice->num + 1, cra);
+
+		/* Fill cache */
+		sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, ccis);
+	}
+
 	for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
 		sblive_writeptr_tag(card, voice->num + i,
 				    IFATN, (voice->params[i].initial_fc << 8) | voice->params[i].initial_attn,
@@ -301,18 +280,7 @@
 				    DCYSUSV, (voice->params[i].byampl_env_sustain << 8) | voice->params[i].byampl_env_decay,
 				    TAGLIST_END);
 
-		/* 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 == VOICE_USAGE_MIDI)
-			emu10k1_clear_stop_on_loop(card, voice->num + i);
-		else {
-			if (voice->startloop > voice->end)
-				emu10k1_set_stop_on_loop(card, voice->num + i);
-			else
-				emu10k1_clear_stop_on_loop(card, voice->num + i);
-		}
+		emu10k1_clear_stop_on_loop(card, voice->num + i);
 
 		sblive_writeptr(card, PTRX_PITCHTARGET, voice->num + i, voice->pitch_target);
 
@@ -333,32 +301,16 @@
 	DPF(2, "emu10k1_voice_stop()\n");
 
 	for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
-		sblive_writeptr_tag(card, voice->num + i, IFATN, 0xffff,
-				    VTFT, 0x0000ffff,
-				    PTRX_PITCHTARGET, 0,
-				    IP, 0,
-				    TAGLIST_END);
+		sblive_writeptr_tag(card, voice->num + i,
+					PTRX_PITCHTARGET, 0,
+					CPF_CURRENTPITCH, 0,
+					IFATN, 0xffff,
+					VTFT, 0x0000ffff,
+					CVCF, 0x0000ffff,
+					IP, 0,
+					TAGLIST_END);
 	}
 
 	return;
 }
 
-void emu10k1_voice_setcontrol(struct emu_voice *voice, struct voice_cntlset *setting, u32 numparam)
-{
-	struct emu10k1_card *card = voice->card;
-	int count;
-
-	for (count = 0; count < numparam; count++)
-		sblive_writeptr(card, setting[count].paramID, voice->num, setting[count].value);
-
-	return;
-}
-
-void emu10k1_voice_getcontrol(struct emu_voice *voice, u32 controlid, u32 * value)
-{
-	struct emu10k1_card *card = voice->card;
-
-	*value = sblive_readptr(card, controlid, voice->num);
-
-	return;
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/voicemgr.h linux.18p8/drivers/sound/emu10k1/voicemgr.h
--- linux.vanilla/drivers/sound/emu10k1/voicemgr.h	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/emu10k1/voicemgr.h	Fri Sep 15 15:12:33 2000
@@ -47,7 +47,7 @@
 {
 	/* FX bus amount send */
 
-	u32 bus_routing;
+	u32 send_routing;
 
 	u32 send_a;
 	u32 send_b;
@@ -64,11 +64,6 @@
 	u32 byampl_env_decay;
 };
 
-struct voice_allocdesc
-{
-	u8 usage;			/* playback, Midi */
-	u8 flags;			/* stereo/mono rec/playback 8/16 bit*/
-};
 
 struct emu_voice
 {
@@ -77,10 +72,9 @@
 	u8 num;			/* Voice ID */
 	u8 flags;		/* Stereo/mono, 8/16 bit */
 
-	u32 start;
         u32 startloop;
         u32 endloop;
-        u32 end;
+	u32 start;
 
 	u32 initial_pitch;
 	u32 pitch_target;
@@ -88,18 +82,10 @@
 	struct voice_param params[2];
 };
 
-struct voice_cntlset
-{
-	u32 paramID;
-	u32 value;
-};
-
-int emu10k1_voice_alloc(struct emu10k1_card *, struct emu_voice *, struct voice_allocdesc *);
+int emu10k1_voice_alloc(struct emu10k1_card *, struct emu_voice *);
 void emu10k1_voice_free(struct emu_voice *);
 void emu10k1_voice_playback_setup(struct emu_voice *);
-void emu10k1_voice_start(struct emu_voice *);
+void emu10k1_voice_start(struct emu_voice *, int);
 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 */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/es1370.c linux.18p8/drivers/sound/es1370.c
--- linux.vanilla/drivers/sound/es1370.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/es1370.c	Tue Sep  5 22:21:01 2000
@@ -164,21 +164,9 @@
 
 #ifdef MODULE
 #define __exit
-#define module_exit(x) void cleanup_module(void) { x(); }
-#define module_init(x) int init_module(void) { return x(); }
 #else
 #define __exit __attribute__ ((unused, __section__ (".text.init")))
-#define module_exit(x) /* nothing */
-#define module_init(x) /* nothing */
 #endif
-
-#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL
-#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL}
-#define wait_queue_head_t struct wait_queue *
-#define init_waitqueue_head(w) *(w) = 0
-#define init_MUTEX(m) *(m) = MUTEX
-#define __set_current_state(x) do { current->state = (x); } while (0)
-#define set_current_state(x) __set_current_state(x)
 
 /* --------------------------------------------------------------------- */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/es1371.c linux.18p8/drivers/sound/es1371.c
--- linux.vanilla/drivers/sound/es1371.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/es1371.c	Tue Sep  5 22:21:01 2000
@@ -132,21 +132,9 @@
 
 #ifdef MODULE
 #define __exit
-#define module_exit(x) void cleanup_module(void) { x(); }
-#define module_init(x) int init_module(void) { return x(); }
 #else
 #define __exit __attribute__ ((unused, __section__ (".text.init")))
-#define module_exit(x) /* nothing */
-#define module_init(x) /* nothing */
 #endif
-
-#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL
-#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL}
-#define wait_queue_head_t struct wait_queue *
-#define init_waitqueue_head(w) *(w) = 0
-#define init_MUTEX(m) *(m) = MUTEX
-#define __set_current_state(x) do { current->state = (x); } while (0)
-#define set_current_state(x) __set_current_state(x)
 
 /* --------------------------------------------------------------------- */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/esssolo1.c linux.18p8/drivers/sound/esssolo1.c
--- linux.vanilla/drivers/sound/esssolo1.c	Sat Sep  9 18:42:43 2000
+++ linux.18p8/drivers/sound/esssolo1.c	Tue Sep  5 22:21:01 2000
@@ -133,21 +133,10 @@
 #if LINUX_VERSION_CODE < 0x02030d
 #ifdef MODULE
 #define __exit
-#define module_exit(x) void cleanup_module(void) { x(); }
-#define module_init(x) int init_module(void) { return x(); }
 #else
 #define __exit __attribute__ ((unused, __section__ (".text.init")))
-#define module_exit(x) /* nothing */
-#define module_init(x) /* nothing */
 #endif
 
-#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL
-#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL}
-#define wait_queue_head_t struct wait_queue *
-#define init_waitqueue_head(w) *(w) = 0
-#define init_MUTEX(m) *(m) = MUTEX
-#define __set_current_state(x) do { current->state = (x); } while (0)
-#define set_current_state(x) __set_current_state(x)
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -229,7 +218,7 @@
 
 /* --------------------------------------------------------------------- */
 
-struct solo1_state *devs = NULL;
+static struct solo1_state *devs = NULL;
 
 /* --------------------------------------------------------------------- */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/maestro.c linux.18p8/drivers/sound/maestro.c
--- linux.vanilla/drivers/sound/maestro.c	Sat Sep  9 18:42:44 2000
+++ linux.18p8/drivers/sound/maestro.c	Fri Sep  1 22:12:09 2000
@@ -210,11 +210,8 @@
 #include <linux/version.h>
 #include <linux/module.h>
 
-#define DECLARE_WAITQUEUE(QUEUE,INIT) struct wait_queue QUEUE = {INIT, NULL}
-#define wait_queue_head_t struct wait_queue *
 #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)
 #define SILLY_INIT_SEM(SEM) SEM=MUTEX;
-#define init_waitqueue_head init_waitqueue
 #define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC)
 #define SILLY_OFFSET(VMA) ((VMA)->vm_offset)
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/msnd_pinnacle.c linux.18p8/drivers/sound/msnd_pinnacle.c
--- linux.vanilla/drivers/sound/msnd_pinnacle.c	Fri Apr 21 12:46:35 2000
+++ linux.18p8/drivers/sound/msnd_pinnacle.c	Fri Sep  1 13:19:00 2000
@@ -50,7 +50,9 @@
 #include "sound_config.h"
 #include "sound_firmware.h"
 #ifdef MSND_CLASSIC
+# ifndef __alpha__
 #  define SLOWIO
+# endif
 #endif
 #include "msnd.h"
 #ifdef MSND_CLASSIC
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/softoss.c linux.18p8/drivers/sound/softoss.c
--- linux.vanilla/drivers/sound/softoss.c	Fri Apr 21 12:46:36 2000
+++ linux.18p8/drivers/sound/softoss.c	Thu Aug 31 15:22:53 2000
@@ -1113,7 +1113,10 @@
 		return -ENOMEM;
 	}
 	if(copy_from_user(&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs))
+	{
+		vfree(patch);
 		return -EFAULT;
+	}
 
 	if (patch->mode & WAVE_ROM)
 	{
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/sonicvibes.c linux.18p8/drivers/sound/sonicvibes.c
--- linux.vanilla/drivers/sound/sonicvibes.c	Fri Apr 21 12:46:36 2000
+++ linux.18p8/drivers/sound/sonicvibes.c	Mon Sep 11 17:49:08 2000
@@ -115,22 +115,10 @@
 
 #ifdef MODULE
 #define __exit
-#define module_exit(x) void cleanup_module(void) { x(); }
-#define module_init(x) int init_module(void) { return x(); }
 #else
 #define __exit __attribute__ ((unused, __section__ (".text.init")))
-#define module_exit(x) /* nothing */
-#define module_init(x) /* nothing */
 #endif
 
-#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL
-#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL}
-#define wait_queue_head_t struct wait_queue *
-#define init_waitqueue_head(w) *(w) = 0
-#define init_MUTEX(m) *(m) = MUTEX
-#define __set_current_state(x) do { current->state = (x); } while (0)
-#define set_current_state(x) __set_current_state(x)
-
 /* --------------------------------------------------------------------- */
 
 #ifndef PCI_VENDOR_ID_S3
@@ -536,7 +524,7 @@
 static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate)
 {
 	unsigned long flags;
-	unsigned char r, m, n;
+	unsigned char r=0, m=0, n=0;
 	unsigned xm, xn, xr, xd, metric = ~0U;
 	/* the warnings about m and n used uninitialized are bogus and may safely be ignored */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/sound_core.c linux.18p8/drivers/sound/sound_core.c
--- linux.vanilla/drivers/sound/sound_core.c	Sat Sep  9 18:42:45 2000
+++ linux.18p8/drivers/sound/sound_core.c	Mon Sep 11 17:13:45 2000
@@ -88,6 +88,8 @@
 #ifdef CONFIG_SOUND_EMU10K1
 extern int init_emu10k1(void);
 #endif
+extern int cs4281_probe(void);
+
 
 /*
  *	Low level list operator. Scan the ordered list, find a hole and
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/trident.c linux.18p8/drivers/sound/trident.c
--- linux.vanilla/drivers/sound/trident.c	Sat Sep  9 18:42:45 2000
+++ linux.18p8/drivers/sound/trident.c	Thu Aug 31 14:47:51 2000
@@ -2892,7 +2892,7 @@
 	if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
 		/* edited by HMSEO for GT sound */
 #ifdef CONFIG_ALPHA_NAUTILUS
-		ac97_data = trident_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL);
+		u16 ac97_data = trident_ac97_get (card->ac97_codec[0], AC97_POWER_CONTROL);
 		trident_ac97_set (card->ac97_codec[0], AC97_POWER_CONTROL,
 				  ac97_data | ALI_EAPD_POWER_DOWN);
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/uart401.c linux.18p8/drivers/sound/uart401.c
--- linux.vanilla/drivers/sound/uart401.c	Fri Apr 21 12:46:36 2000
+++ linux.18p8/drivers/sound/uart401.c	Thu Aug 31 14:55:00 2000
@@ -317,8 +317,8 @@
 	{
 		printk(KERN_WARNING "uart401: Failed to allocate memory\n");
 		kfree(midi_devs[devc->my_dev]);
-		kfree(devc);
 		sound_unload_mididev(devc->my_dev);
+		kfree(devc);
 		devc=NULL;
 		return;
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/telephony/ixj.c linux.18p8/drivers/telephony/ixj.c
--- linux.vanilla/drivers/telephony/ixj.c	Sat Sep  9 18:42:45 2000
+++ linux.18p8/drivers/telephony/ixj.c	Thu Aug 31 15:24:51 2000
@@ -4473,14 +4473,21 @@
 	if (lcp == NULL)
 		return -ENOMEM;
 	if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE)))
+	{
+		kfree(lcp);
 		return -EFAULT;
+	}
 	lcep = kmalloc(sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used, GFP_KERNEL);
 	if (lcep == NULL) {
 		kfree(lcp);
 		return -ENOMEM;
 	}
 	if (copy_from_user(lcep, lcp->ce, sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used))
+	{
+		kfree(lcep);
+		kfree(lcp);
 		return -EFAULT;
+	}
 	if (j->cadence_t) {
 		kfree(j->cadence_t->ce);
 		kfree(j->cadence_t);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/CREDITS linux.18p8/drivers/usb/CREDITS
--- linux.vanilla/drivers/usb/CREDITS	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/CREDITS	Thu Jan  1 01:00:00 1970
@@ -1,154 +0,0 @@
-Credits for the Simple Linux USB Driver:
-
-The following people have contributed to this code (in alphabetical
-order by last name).  I'm sure this list should be longer, its
-difficult to maintain, add yourself with a patch if desired.
-
-  Alan Cox <alan@lxorguk.ukuu.org.uk>
-  Johannes Erdfelt <jerdfelt@sventech.com>
-  ham <ham@unsuave.com>
-  Bradley M Keryan <keryan@andrew.cmu.edu>
-  Vojtech Pavlik <vojtech@twilight.ucw.cz>
-  Gregory P. Smith <greg@electricrain.com>
-  Linus Torvalds <torvalds@transmeta.com>
-  Roman Weissgaerber <weissg@vienna.at>
-  <Kazuki.Yasumatsu@fujixerox.co.jp>
-
-Special thanks to:
-
-  Inaky Perez Gonzalez <inaky@peloncho.fis.ucm.es> for starting the
-  Linux USB driver effort and writing much of the larger uusbd driver.
-  Much has been learned from that effort.
-
-  The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
-  and offering suggestions and sharing implementation experiences.
-
-Additional thanks to the following companies and people for donations
-of hardware, support, time and development (this is from the original
-THANKS file in Inaky's driver):
-
-        The following corporations have helped us in the development
-of Linux USB / UUSBD:
-
-        - USAR Systems provided us with one of their excellent USB
-          Evaluation Kits. It allows us to test the Linux-USB driver
-          for compilance with the latest USB specification. USAR
-          Systems recognized the importance of an up-to-date open
-          Operating System and supports this project with
-          Hardware. Thanks!.
-
-        - Thanks to Intel Corporation for their precious help.
-
-        - We teamed up with Cherry to make Linux the first OS with
-          built-in USB support. Cherry is one of the biggest keyboard
-          makers in the world.
-
-        - CMD Technology, Inc. sponsored us kindly donating a CSA-6700
-          PCI-to-USB Controller Board to test the OHCI implementation.
-
-        - Due to their support to us, Keytronic can be sure that they
-          will sell keyboards to some of the 3 million (at least)
-          Linux users.
-
-        - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
-          It was almost imposible to get a PC backplate USB connector
-          for the motherboard here at Europe (mine, home-made, was
-          quite lowsy :). Now I know where to adquire nice USB stuff!
-
-        - Genius Germany donated a USB mouse to test the mouse boot
-          protocol. They've also donated a F-23 digital joystick and a
-          NetMouse Pro. Thanks! 
-
-        - AVM GmbH Berlin is supporting the development of the Linux
-          USB driver for the AVM ISDN Controller B1 USB. AVM is a
-          leading manufacturer for active and passive ISDN Controllers
-          and CAPI 2.0-based software. The active design of the AVM B1
-          is open for all OS platforms, including Linux.
-
-        - Thanks to Y-E Data, Inc. for donating their FlashBuster-U
-          USB Floppy Disk Drive, so we could test the bulk transfer
-          code.
-
-        - Many thanks to Logitech for contributing a three axis USB
-          mouse. 
-
-          Logitech designs, manufactures and markets
-          Human Interface Devices, having a long history and
-          experience in making devices such as keyboards, mice,
-          trackballs, cameras, loudspeakers and control devices for
-          gaming and professional use.
-
-          Being a recognized vendor and seller for all these devices,
-          they have donated USB mice, a joystick and a scanner, as a
-          way to acknowledge the importance of Linux and to allow
-          Logitech customers to enjoy support in their favorite
-          operating systems and all Linux users to use Logitech and
-          other USB hardware.
-
-          Logitech is official sponsor of the Linux Conference on
-          Feb. 11th 1999 in Vienna, where we'll will present the
-          current state of the Linux USB effort.
-
-        - CATC has provided means to uncover dark corners of the UHCI
-          inner workings with a USB Inspector.
-
-        - Thanks to Entrega for providing PCI to USB cards, hubs and
-          converter products for development. 
-
-
-        And thanks go to (hey! in no particular order :)
-
-        - Oren Tirosh <orenti@hishome.net>, for standing so patiently
-          all my doubts'bout USB and giving lots of cool ideas.
-
-        - Jochen Karrer <karrer@wpfd25.physik.uni-wuerzburg.de>, for
-          pointing out mortal bugs and giving advice.
-
-        - Edmund Humemberger <ed@atnet.at>, for it's great work on
-          public relationships and general management stuff for the
-          Linux-USB effort.
-
-        - Alberto Menegazzi <flash@flash.iol.it> is starting the
-          documentation for the UUSBD. Go for it!
-
-        - Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
-          introductory documents (compiting with Alberto's :).
-
-        - Christian Groessler <cpg@aladdin.de>, for it's help on those
-          itchy bits ... :)
-
-        - Paul MacKerras for polishing OHCI and pushing me harder for
-          the iMac support, giving improvements and enhancements.
-
-        - Fernando Herrera <fherrera@eurielec.etsit.upm.es> has taken
-          charge of composing, maintaining and feeding the
-          long-awaited, unique and marvelous UUSBD FAQ! Tadaaaa!!!
-
-        - Rasca Gmelch <thron@gmx.de> has revived the raw driver and
-          pointed bugs, as well as started the uusbd-utils package.
-
-        - Peter Dettori <dettori@ozy.dec.com> is unconvering bugs like
-          crazy, as well as making cool suggestions, great :)
-
-        - All the Free Software and Linux community, the FSF & the GNU
-          project, the MIT X consortium, the TeX people ... everyone!
-          You know who you are!
-
-        - Big thanks to Richard Stallman for creating Emacs!
-
-        - The people at the linux-usb mailing list, for reading so
-          many messages :) Ok, no more kidding; for all your advices!
-
-        - All the people at the USB Implementors Forum for their
-          help and assistance.
-
-        - Nathan Myers <ncm@cantrip.org>, for his advice! (hope you
-          liked Cibeles' party).
-
-        - Linus Torvalds, for starting, developing and managing Linux.
-
-        - Mike Smith, Craig Keithley, Thierry Giron and Janet Schank
-          for convincing me USB Standard hubs are not that standard
-          and that's good to allow for vendor specific quirks on the
-          standard hub driver.
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/Config.in linux.18p8/drivers/usb/Config.in
--- linux.vanilla/drivers/usb/Config.in	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/Config.in	Fri Sep 15 12:43:51 2000
@@ -1,30 +1,98 @@
 #
 # USB device configuration
 #
-# NOTE NOTE NOTE! This is still considered extremely experimental.
-# Right now hubs, mice and keyboards work - at least with UHCI.
-# But that may be more a lucky coincidence than anything else..
-#
-# This was all developed modularly, but I've been lazy in cleaning
-# it up, so right now they are all bools. 
-#
 mainmenu_option next_comment
-comment 'USB drivers - not for the faint of heart'
+comment 'USB support'
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB
-  if [ ! "$CONFIG_USB" = "n" ]; then
-    bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
-    bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
-    bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD
-    if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then
-       bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
-    fi
+tristate 'Support for USB' CONFIG_USB
+if [ ! "$CONFIG_USB" = "n" ]; then
+   bool '  USB verbose debug messages' CONFIG_USB_DEBUG
 
-    bool 'USB mouse support' CONFIG_USB_MOUSE
-    bool 'USB keyboard support' CONFIG_USB_KBD
-    bool 'USB audio parsing support' CONFIG_USB_AUDIO
-  fi
+comment 'Miscellaneous USB options'
+   bool '  Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool '  Enforce USB bandwidth allocation (EXPERIMENTAL)' CONFIG_USB_BANDWIDTH
+   else
+      define_bool CONFIG_USB_BANDWIDTH n
+   fi
+
+comment 'USB Controllers'
+   if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
+      dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+   fi
+   if [ "$CONFIG_USB_UHCI" != "y" ]; then
+      dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
+   fi
+   dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
+
+comment 'USB Devices'
+   dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+   dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
+   dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
+   dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
+   dep_tristate '  USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
+   if [ "$CONFIG_USB_SERIAL" != "n" ]; then
+      bool '    USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC $CONFIG_USB_SERIAL
+      dep_tristate '    USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+      if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+         dep_tristate '    USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL
+         dep_tristate '    USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL
+         dep_tristate '    USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL
+         dep_tristate '    USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL
+         if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then
+            bool '      USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28
+            bool '      USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X
+            bool '      USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
+            bool '      USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
+            bool '      USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
+         fi
+         dep_tristate '    USB Digi International AccelePort USB Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
+         dep_tristate '    USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL
+      fi
+      bool '    USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
+   fi
+   dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+   dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
+   dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+	   dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB
+      dep_tristate '  USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
+      if [ "$CONFIG_USB_STORAGE" != "n" ]; then
+         bool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
+      fi
+   fi
+#   dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
+   dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      dep_tristate '  PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET
+      dep_tristate '  USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET
+      dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB
+      dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_SCSI
+      dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
+   fi
+   if [ "$CONFIG_NET" = "y" ]; then
+      dep_tristate '  Kawasaki USB-ethernet controller' CONFIG_USB_KAWETH $CONFIG_USB
+   fi
+
+comment 'USB HID'
+   dep_tristate '  USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB
+   if [ "$CONFIG_USB_HID" != "y" ]; then
+      dep_tristate '  USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB
+      dep_tristate '  USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB
+   fi
+   dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB
+   dep_tristate '  Logitech WingMan Force joystick support' CONFIG_USB_WMFORCE $CONFIG_USB
+   if [ "$CONFIG_VT" = "y" ]; then
+      dep_tristate '  Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB 
+   fi
+   dep_tristate '  Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB
+   if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
+      int '   Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
+      int '   Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
+   fi
+   dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB
+   dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB
 fi
 
 endmenu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/Makefile linux.18p8/drivers/usb/Makefile
--- linux.vanilla/drivers/usb/Makefile	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/Makefile	Tue Sep 12 12:52:02 2000
@@ -1,88 +1,123 @@
 #
-# Makefile for the kernel usb device drivers.
+# Makefile for the kernel USB device drivers.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-# This isn't actually supported yet. Don't try to use it.
 
-SUB_DIRS     :=
-MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS)
-
-L_TARGET := usb.a
-M_OBJS   :=
-L_OBJS   :=
-LX_OBJS  :=
-USBX_OBJS := usb.o hub.o usb-debug.o
+# Subdirs.
 
-ifeq ($(CONFIG_USB_MOUSE),y)
-  USBX_OBJS += mouse.o
-endif
+SUB_DIRS	:=
+MOD_SUB_DIRS	:= $(SUB_DIRS)
+MOD_IN_SUB_DIRS	:= $(SUB_DIRS)
+ALL_SUB_DIRS	:= $(SUB_DIRS) serial
 
-ifeq ($(CONFIG_USB_KBD),y)
-  USBX_OBJS += keyboard.o keymap.o
-endif
+# The target object and module list name.
 
-ifeq ($(CONFIG_USB_AUDIO),y)
-  USBX_OBJS += audio.o
-endif
+O_TARGET	:= usbdrv.o
+M_OBJS		:=
+O_OBJS		:=
+MOD_LIST_NAME	:= USB_MODULES
 
-ifeq ($(CONFIG_USB), y)
-  L_OBJS += $(USBX_OBJS)
-endif
+# Objects that export symbols.
 
-ifeq ($(CONFIG_USB_UHCI),y)
-  ifeq ($(CONFIG_USB), y)
-    L_OBJS += uhci.o uhci-debug.o
-  else
-    ifeq ($(CONFIG_USB),m)
-      M_OBJS += usb-uhci.o
-      MIX_OBJS += $(USBX_OBJS)
-    endif
-  endif
-endif
+export-objs		:= usb.o input.o
 
-ifeq ($(CONFIG_USB_OHCI),y)
-  ifeq ($(CONFIG_USB), y)
-    L_OBJS += ohci.o ohci-debug.o
-  else
-    ifeq ($(CONFIG_USB),m)
-      USBO_OBJS += ohci.o ohci-debug.o
-      M_OBJS += usb-ohci.o
-      MIX_OBJS += $(USBX_OBJS)
-    endif
-  endif
+# Multipart objects.
+
+list-multi		:= usbcore.o
+usbcore-objs		:= usb.o usb-debug.o usb-core.o hub.o
+
+# Optional parts of multipart objects.
+
+ifeq ($(CONFIG_USB_DEVICEFS),y)
+	usbcore-objs	+= devio.o inode.o drivers.o devices.o
 endif
 
-ifeq ($(CONFIG_USB_OHCI_HCD),y)
-  ifeq ($(CONFIG_USB), y)
-    L_OBJS += ohci-hcd.o ohci-root-hub.o
-  else
-    ifeq ($(CONFIG_USB),m)
-      USBO_OBJS += ohci-hcd.o ohci-root-hub.o
-      M_OBJS += usb-ohci-hcd.o
-      MIX_OBJS += $(USBX_OBJS)
-    endif
-  endif
+# Object file lists.
+
+obj-y	:=
+obj-m	:=
+obj-n	:=
+obj-	:=
+
+# Object files in subdirectories
+
+ifeq ($(CONFIG_USB_SERIAL),y)
+	SUB_DIRS += serial
+	obj-y += serial/usb-serial.o
+else
+	ifeq ($(CONFIG_USB_SERIAL),m)
+		MOD_IN_SUB_DIRS += serial
+	endif
 endif
-include $(TOPDIR)/Rules.make
 
-keymap.o: keymap.c
 
-keymap.c: maps/serial.map maps/usb.map maps/fixup.map
-	./mkmap > $@
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_USB)		+= usbcore.o
+obj-$(CONFIG_USB_UHCI)		+= usb-uhci.o
+obj-$(CONFIG_USB_UHCI_ALT)	+= uhci.o
+obj-$(CONFIG_USB_OHCI)		+= usb-ohci.o
+
+obj-$(CONFIG_USB_MOUSE)		+= usbmouse.o input.o
+obj-$(CONFIG_USB_HID)		+= hid.o input.o
+obj-$(CONFIG_USB_KBD)		+= usbkbd.o input.o
+obj-$(CONFIG_USB_WACOM)		+= wacom.o input.o
+obj-$(CONFIG_USB_WMFORCE)	+= wmforce.o input.o
+obj-$(CONFIG_INPUT_KEYBDEV)	+= keybdev.o input.o
+obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev.o input.o
+obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o input.o
+obj-$(CONFIG_INPUT_EVDEV)	+= evdev.o input.o
+
+obj-$(CONFIG_USB_SCANNER)	+= scanner.o
+obj-$(CONFIG_USB_ACM)		+= acm.o
+obj-$(CONFIG_USB_PRINTER)	+= printer.o
+obj-$(CONFIG_USB_AUDIO)		+= audio.o
+obj-$(CONFIG_USB_IBMCAM)	+= ibmcam.o
+obj-$(CONFIG_USB_DC2XX)		+= dc2xx.o
+obj-$(CONFIG_USB_MDC800)	+= mdc800.o
+obj-$(CONFIG_USB_STORAGE)	+= usb-storage.o
+obj-$(CONFIG_USB_USS720)	+= uss720.o
+obj-$(CONFIG_USB_DABUSB)	+= dabusb.o
+obj-$(CONFIG_USB_PLUSB)		+= plusb.o
+obj-$(CONFIG_USB_OV511)		+= ov511.o
+obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
+obj-$(CONFIG_USB_RIO500)	+= rio500.o
+obj-$(CONFIG_USB_DSBR)		+= dsbr100.o
+obj-$(CONFIG_USB_MICROTEK)	+= microtek.o
+obj-$(CONFIG_USB_KAWETH)	+= kaweth.o
+obj-$(CONFIG_USB_BLUETOOTH)	+= bluetooth.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Take multi-part drivers out of obj-y and put components in.
+
+obj-y		:= $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-y)))
+OX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-y)))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
 
-usb-uhci.o: uhci.o uhci-debug.o $(USBX_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@  uhci.o uhci-debug.o $(USBX_OBJS)
+# Link rules for multi-part drivers.
 
-usb-ohci.o: ohci.o ohci-debug.o $(USBX_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o $(USBX_OBJS)
+usbcore.o: $(usbcore-objs)
+	$(LD) -r -o $@ $(usbcore-objs)
 
-usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
-       
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/README.kbd linux.18p8/drivers/usb/README.kbd
--- linux.vanilla/drivers/usb/README.kbd	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/README.kbd	Thu Jan  1 01:00:00 1970
@@ -1,65 +0,0 @@
-This is a simple USB keyboard driver written from Linus'
-USB driver (started with Greg's usb-0.03b.tar.gz source
-tree)
-
-It works fine with my BTC keyboard but I'm still investigating
-trouble with my MS keyboard (trouble starts with an inability
-to set into boot protocol mode, though, this very well could
-be all due to crappy hardware).
-
-Anyway, I would appreciate you taking a look if you have
-any USB keyboards lying around.  Oh also, I'm doing this on
-UHCI so sorry if it breaks with OHCI.
-
--ham
-
-
-
-Keyboard patch
---------------
-
-Instead of using the multiple keyboard patch and then running into all
-of the kernel version problems that the current Linux-USB project has
-had, I'm just mapping the USB keycodes to the standard AT-101 keycodes
-and sending them directly to "handle_scancode".
-
-This may or may not be considered a hack.  Anyway it is effective, and
-I think safe, and allows USB keyboards to coexist with a serial
-keyboard (oh yeah, one side effect is that you can for example hold
-down the control key on the serial keyboard and press "a" on the USB
-keyboard and you get Control-a like with Windows USB) and works
-fine for console and X.
-
-You do need to make a *tiny* patch the kernel source tree so that the
-function "handle_scancode" is exported from keyboard.c though.
-
-  $ cd /usr/src/linux
-  $ patch -p0 < kbd.patch
-
-And, of course, then, you need to rebuild and install the kernel.
-
-** [Vojtech]: Alternately, just 'insmod kbd-stub', if you don't want
-to use the keyboard and are too lazy to patch the kernel.
-
-Keyboard map
-------------
-
-I'm including a stupid utility "mkmap" which generates the USB->serial
-keymap.  It takes in maps/serial.map (the current serial keymap,
-generated by "dumpkeys"), maps/usb.map (the USB keymap), and
-maps/fixup.map (fixes for e0 keys and misc.) and spits out keymap.c
-Anyway, it is not beautiful but should serve its purpose for the
-moment.
-
-Other changes
--------------
-uhci.c:
-  * added a context value to the irq callback function
-    (this is exactly like the "dev_id" field to request_irq)
-  * played with uhci_reset_port to get better hot-plug results
-    (eg. do a wait_ms(200) before calling uhci_reset_port)
-usb.c:
-  * disconnect all devices after uhci-control thread is killed
-  * skip over the HID descriptor
-  * disconnect the high-level driver in usb_disconnect
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/README.ohci linux.18p8/drivers/usb/README.ohci
--- linux.vanilla/drivers/usb/README.ohci	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/README.ohci	Thu Jan  1 01:00:00 1970
@@ -1,26 +0,0 @@
-May 09, 1999 16:25:58
-
-Cool, things are working "well" now.  (I'm not getting oops's from the
-OHCI code anyways.. ;).  I can attach a usb hub and mouse in any
-possible arrangement of the two and they get configured properly.
-
-You can see that the mouse Interrupt transfers are occuring and being
-acknowledged because /proc/interrupts usb-ohci goes up accordingly with
-mouse movements/events.  That means the TD at least returns some data
-and requeues itself.
-
-Device attach/detach from the root hub is not working well.  Currently
-every interrupt checks for root hub status changes and frame number
-overflow interrupts are enabled.  This means you shouldn't have to
-wait more than 32-33 seconds for the change to occur, less if there is
-other activity.  (due to checking in the WDH caused interrupts)
-My OHCI controller [SiS 5598 motherboard] doesn't seem to play well
-with the RHSC interrupt so it has been disabled.  The ohci_timer
-should be polling but it not currently working, I haven't had time to
-look into that problem.
-
-However, when I tried telling X to use /dev/psaux for the mouse my
-machine locked up...
-
-- greg@electricrain.com
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/README.ohci_hcd linux.18p8/drivers/usb/README.ohci_hcd
--- linux.vanilla/drivers/usb/README.ohci_hcd	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/README.ohci_hcd	Thu Jan  1 01:00:00 1970
@@ -1,112 +0,0 @@
-
-The OHCI HCD layer is a simple but nearly complete implementation of what the
-USB people would call a HCD  for the OHCI. 
- (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
-It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
-The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. 
-
-- Roman Weissgaerber <weissg@vienna.at>
-
-
- * v2.1 1999/05/09 ep_addr correction, code cleanup
- * v0.2.0 1999/05/04 
- * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
- * virtual root hub is now an option, 
- * memory allocation based on kmalloc and kfree now, simple Bus error handling, 
- * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
- * 
- * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
- * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
- * 
- * v0.1.0 1999/04/27 initial release
- 
-to remove the module try:
-killall root-hub
-:
-rmmod usb-ohci-hcd
-
-Features:
-- virtual root hub, all basic hub descriptors and commands (state: complete) 
-  this is an option now (v0.2.0)
-  #define  CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
-  default is without. 
-  (at the moment: the Virtual Root Hub option is not recommended)
-  
-  files: ohci-root-hub.c, ohci-root-hub.h 
- 
-
-- Endpoint Descriptor (ED) handling more static approach 
- (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
- as long as the function (device) is alive or another configuration is choosen.
- In the HCD layer the EDs has to be allocated manually either by calling a subroutine
- or by sending a USB root hub vendor specific command to the virtual root hub.
- At the alternate linux usb stack EDs will be added (allocated) at their first use.
- 
- files: ohci-hcd.c ohci-hcd.h
- routines:   (do not use for drivers, use the top layer alternate usb commands instead)
- 
- int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, 
-            int interval, int load, f_handler handler, int ep_size, int speed)
-       adds an endpoint, (if the endpoint already exists some parameters will be updated)
-       
- int usb_ohci_rm_ep(struct  usb_ohci_ed *ed, struct ohci * ohci) 
-       removes an endpoint and all pending TDs of that EP
-       
-  usb_ohci_rm_function( struct ohci * ohci, union ep_addr_ ep_addr)
-       removes all Endpoints of a function (device)
-
-- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
-  The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
-  to take care of buffer allocation.
-  files: ohci-hcd.c ohci-hcd.h 
-
-  There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
-  
-  int ohci_trans_req(struct ohci * ohci, int ep_addr, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
-  
-  CTRL: ctrl, ctrl_len ... cmd buffer 
-        data, data_len ... data buffer (in or out)
-  INT, BULK:  ctrl = NULL, ctrl_len=0,
-  		data, data_len ... data buffer (in or out)
-  ISO: tbd
-
-  There is no buffer reinsertion done by the internal HCD function. 
-  (The interface layer does this for a INT-pipe on request.)
-  If you want a transfer then you have to 
-  provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
-  you can send as many as you like. They should come back by the callback f_handler in
-  the same order (for each endpoint, not globally) If an error occurs all
-  queued transfers of an endpoint will return unsent. They will be marked with an error status.
-  
-  e.g double-buffering for int transfers:
-
-   	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
-  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
-  	
-  and when a data0 packet returns by the callback f_handler requeue it:
-  	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
-  and when a data1 packet returns by the callback f_handler requeue it:
-  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
-  	
-  lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
-  The alternate usb uses them for dev_id and usb_device_irq handler.
-
-
-- Done list handling: returns the requests (callback f_handler in ED) and does 
-  some error handling, root-hub request dequeuing
-  (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
-
-ep_addr union or int  is for addressing devices&endpoints: 
-__u8 ep_addr.bep.ep ... bit 3..0  endpoint address
-						bit 4     0
-						bit 6,5  type: eg. 10 CTRL, 11 BULK, 01 INT, 00 ISO
-						bit 7	direction 1 IN, 0 OUT
-
-__u8 ep_addr.bep.fa ... bit 6..0  function address
-						bit 7	  0
-
-(__u8 ep_addr.bep.hc ... host controller nr) not used
-(__u8 ep_addr.bep.host ... host nr) not used
-
-
-  
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/acm.c linux.18p8/drivers/usb/acm.c
--- linux.vanilla/drivers/usb/acm.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/acm.c	Fri Sep  1 22:16:20 2000
@@ -0,0 +1,692 @@
+/*
+ * acm.c  Version 0.16
+ *
+ * Copyright (c) 1999 Armin Fuerst	<fuerst@in.tum.de>
+ * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
+ * Copyright (c) 1999 Johannes Erdfelt	<jerdfelt@valinux.com>
+ * Copyright (c) 2000 Vojtech Pavlik	<vojtech@suse.cz>
+ *
+ * USB Abstract Control Model driver for USB modems and ISDN adapters
+ *
+ * Sponsored by SuSE
+ *
+ * ChangeLog:
+ *	v0.9  - thorough cleaning, URBification, almost a rewrite
+ *	v0.10 - some more cleanups
+ *	v0.11 - fixed flow control, read error doesn't stop reads
+ *	v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
+ *	v0.13 - added termios, added hangup
+ *	v0.14 - sized down struct acm
+ *	v0.15 - fixed flow control again - characters could be lost
+ *	v0.16 - added code for modems with swapped data and control interfaces
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+//#define DEBUG
+#include <linux/usb.h>
+#include <linux/devfs_fs_kernel.h>
+
+/*
+ * CMSPAR, some architectures can't have space and mark parity.
+ */
+
+#ifndef CMSPAR
+#define CMSPAR			0
+#endif
+
+/*
+ * Major and minor numbers.
+ */
+
+#define ACM_TTY_MAJOR		166
+#define ACM_TTY_MINORS		32
+
+/*
+ * Requests.
+ */
+
+#define USB_RT_ACM		(USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+
+#define ACM_REQ_COMMAND		0x00
+#define ACM_REQ_RESPONSE	0x01
+#define ACM_REQ_SET_FEATURE	0x02
+#define ACM_REQ_GET_FEATURE	0x03
+#define ACM_REQ_CLEAR_FEATURE	0x04
+
+#define ACM_REQ_SET_LINE	0x20
+#define ACM_REQ_GET_LINE	0x21
+#define ACM_REQ_SET_CONTROL	0x22
+#define ACM_REQ_SEND_BREAK	0x23
+
+/*
+ * IRQs.
+ */
+
+#define ACM_IRQ_NETWORK		0x00
+#define ACM_IRQ_LINE_STATE	0x20
+
+/*
+ * Output control lines.
+ */
+
+#define ACM_CTRL_DTR		0x01
+#define ACM_CTRL_RTS		0x02
+
+/*
+ * Input control lines and line errors.
+ */
+
+#define ACM_CTRL_DCD		0x01
+#define ACM_CTRL_DSR		0x02
+#define ACM_CTRL_BRK		0x04
+#define ACM_CTRL_RI		0x08
+
+#define ACM_CTRL_FRAMING	0x10
+#define ACM_CTRL_PARITY		0x20
+#define ACM_CTRL_OVERRUN	0x40
+
+/*
+ * Line speed and caracter encoding.
+ */
+
+struct acm_line {
+	__u32 speed;
+	__u8 stopbits;
+	__u8 parity;
+	__u8 databits;
+} __attribute__ ((packed));
+
+/*
+ * Internal driver structures.
+ */
+
+struct acm {
+	struct usb_device *dev;				/* the coresponding usb device */
+	struct usb_interface *iface;			/* the interfaces - +0 control +1 data */
+	struct tty_struct *tty;				/* the coresponding tty */
+	struct urb ctrlurb, readurb, writeurb;		/* urbs */
+	struct acm_line line;				/* line coding (bits, stop, parity) */
+	struct tq_struct tqueue;			/* task queue for line discipline waking up */
+	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */
+	unsigned int ctrlout;				/* output control lines (DTR, RTS) */
+	unsigned int writesize;				/* max packet size for the output bulk endpoint */
+	unsigned int used;				/* someone has this acm's device open */
+	unsigned int minor;				/* acm minor number */
+	unsigned char throttle;				/* throttled by tty layer */
+	unsigned char clocal;				/* termios CLOCAL */
+};
+
+static struct usb_driver acm_driver;
+static struct tty_driver acm_tty_driver;
+static struct acm *acm_table[ACM_TTY_MINORS] = { NULL, /* .... */ };
+
+#define ACM_READY(acm)	(acm && acm->dev && acm->used)
+
+/*
+ * Functions for ACM control messages.
+ */
+
+static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
+{
+	int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
+		request, USB_RT_ACM, value, acm->iface[0].altsetting[0].bInterfaceNumber, buf, len, HZ * 5);
+	dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
+	return retval < 0 ? retval : 0;
+}
+
+#define acm_set_control(acm, control)	acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)
+#define acm_set_line(acm, line)		acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, line, sizeof(struct acm_line))
+#define acm_send_break(acm, ms)		acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0)
+
+/*
+ * Interrupt handler for various ACM control events
+ */
+
+static void acm_ctrl_irq(struct urb *urb)
+{
+	struct acm *acm = urb->context;
+	devrequest *dr = urb->transfer_buffer;
+	unsigned char *data = (unsigned char *)(dr + 1);
+	int newctrl;
+
+	if (!ACM_READY(acm)) return;
+
+	if (urb->status < 0) {
+		dbg("nonzero ctrl irq status received: %d", urb->status);
+		return;
+	}
+
+	switch (dr->request) {
+
+		case ACM_IRQ_NETWORK:
+	
+			dbg("%s network", data[0] ? "connected to" : "disconnected from");
+			return;
+
+		case ACM_IRQ_LINE_STATE:
+
+			newctrl = le16_to_cpup((__u16 *) data);
+
+#if 0
+			/* Please someone tell me how to do this properly to kill pppd and not kill minicom */
+			if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
+				dbg("calling hangup");
+				tty_hangup(acm->tty);
+			}
+#endif
+
+			acm->ctrlin = newctrl;
+
+			dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
+				acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',	acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
+				acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',	acm->ctrlin & ACM_CTRL_RI  ? '+' : '-',
+				acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',	acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
+				acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
+
+			return;
+
+		default:
+			dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",
+				dr->request, dr->index, dr->length, data[0], data[1]);
+			return;
+	}
+}
+
+static void acm_read_bulk(struct urb *urb)
+{
+	struct acm *acm = urb->context;
+	struct tty_struct *tty = acm->tty;
+	unsigned char *data = urb->transfer_buffer;
+	int i = 0;
+
+	if (!ACM_READY(acm)) return;
+
+	if (urb->status)
+		dbg("nonzero read bulk status received: %d", urb->status);
+
+	if (!urb->status & !acm->throttle)  {
+		for (i = 0; i < urb->actual_length && !acm->throttle; i++)
+			tty_insert_flip_char(tty, data[i], 0);
+		tty_flip_buffer_push(tty);
+	}
+
+	if (acm->throttle) {
+		memmove(data, data + i, urb->actual_length - i);
+		urb->actual_length -= i;
+		return;
+	}
+
+	urb->actual_length = 0;
+
+	if (usb_submit_urb(urb))
+		dbg("failed resubmitting read urb");
+}
+
+static void acm_write_bulk(struct urb *urb)
+{
+	struct acm *acm = (struct acm *)urb->context;
+
+	if (!ACM_READY(acm)) return;
+
+	if (urb->status)
+		dbg("nonzero write bulk status received: %d", urb->status);
+
+	queue_task(&acm->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+static void acm_softint(void *private)
+{
+	struct acm *acm = private;
+	struct tty_struct *tty = acm->tty;
+
+ 	if (!ACM_READY(acm)) return;
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+}
+
+/*
+ * TTY handlers
+ */
+
+static int acm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	struct acm *acm = acm_table[MINOR(tty->device)];
+
+	if (!acm || !acm->dev) return -EINVAL;
+
+	tty->driver_data = acm;
+	acm->tty = tty;
+
+	MOD_INC_USE_COUNT;
+
+	if (acm->used++) return 0;
+
+	if (usb_submit_urb(&acm->ctrlurb))
+		dbg("usb_submit_urb(ctrl irq) failed");
+
+	if (usb_submit_urb(&acm->readurb))
+		dbg("usb_submit_urb(read bulk) failed");
+
+	acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
+
+	return 0;
+}
+
+static void acm_tty_close(struct tty_struct *tty, struct file *filp)
+{
+	struct acm *acm = tty->driver_data;
+
+	if (!acm || !acm->used) return;
+
+	if (!--acm->used) {
+		if (acm->dev) {
+			acm_set_control(acm, acm->ctrlout = 0);
+			usb_unlink_urb(&acm->ctrlurb);
+			usb_unlink_urb(&acm->writeurb);
+			usb_unlink_urb(&acm->readurb);
+		} else {
+			tty_unregister_devfs(&acm_tty_driver, acm->minor);
+			acm_table[acm->minor] = NULL;
+			kfree(acm);
+		}
+	}
+	MOD_DEC_USE_COUNT;
+}
+
+static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
+{
+	struct acm *acm = tty->driver_data;
+
+	if (!ACM_READY(acm)) return -EINVAL;
+	if (acm->writeurb.status == -EINPROGRESS) return 0;
+	if (!count) return 0;
+
+	count = (count > acm->writesize) ? acm->writesize : count;
+
+	if (from_user)
+		copy_from_user(acm->writeurb.transfer_buffer, buf, count);
+	else
+		memcpy(acm->writeurb.transfer_buffer, buf, count);
+
+	acm->writeurb.transfer_buffer_length = count;
+
+	if (usb_submit_urb(&acm->writeurb))
+		dbg("usb_submit_urb(write bulk) failed");
+
+	return count;
+}
+
+static int acm_tty_write_room(struct tty_struct *tty)
+{
+	struct acm *acm = tty->driver_data;
+	if (!ACM_READY(acm)) return -EINVAL;
+	return acm->writeurb.status == -EINPROGRESS ? 0 : acm->writesize;
+}
+
+static int acm_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct acm *acm = tty->driver_data;
+	if (!ACM_READY(acm)) return -EINVAL;
+	return acm->writeurb.status == -EINPROGRESS ? acm->writeurb.transfer_buffer_length : 0;
+}
+
+static void acm_tty_throttle(struct tty_struct *tty)
+{
+	struct acm *acm = tty->driver_data;
+	if (!ACM_READY(acm)) return;
+	acm->throttle = 1;
+}
+
+static void acm_tty_unthrottle(struct tty_struct *tty)
+{
+	struct acm *acm = tty->driver_data;
+	if (!ACM_READY(acm)) return;
+	acm->throttle = 0;
+	if (acm->readurb.status != -EINPROGRESS)
+		acm_read_bulk(&acm->readurb);
+}
+
+static void acm_tty_break_ctl(struct tty_struct *tty, int state)
+{
+	struct acm *acm = tty->driver_data;
+	if (!ACM_READY(acm)) return;
+	if (acm_send_break(acm, state ? 0xffff : 0))
+		dbg("send break failed");
+}
+
+static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct acm *acm = tty->driver_data;
+	unsigned int retval, mask, newctrl;
+
+	if (!ACM_READY(acm)) return -EINVAL;
+
+	switch (cmd) {
+
+		case TIOCMGET:
+
+			return put_user((acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
+				(acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
+				(acm->ctrlin  & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
+				(acm->ctrlin  & ACM_CTRL_RI  ? TIOCM_RI  : 0) |
+				(acm->ctrlin  & ACM_CTRL_DCD ? TIOCM_CD  : 0) |
+				 TIOCM_CTS, (unsigned long *) arg);
+
+		case TIOCMSET:
+		case TIOCMBIS:
+		case TIOCMBIC:
+
+			if ((retval = get_user(mask, (unsigned long *) arg))) return retval;
+
+			newctrl = acm->ctrlout;
+			mask = (mask & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (mask & TIOCM_RTS ? ACM_CTRL_RTS : 0);
+
+			switch (cmd) {
+				case TIOCMSET: newctrl  =  mask; break;
+				case TIOCMBIS: newctrl |=  mask; break;
+				case TIOCMBIC: newctrl &= ~mask; break;
+			}
+	
+			if (acm->ctrlout == newctrl) return 0; 
+			return acm_set_control(acm, acm->ctrlout = newctrl);
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+static __u32 acm_tty_speed[] = { 
+	0, 50, 75, 110, 134, 150, 200, 300, 600,
+	1200, 1800, 2400, 4800, 9600, 19200, 38400,
+	57600, 115200, 230400, 460800, 500000, 576000,
+	921600, 1000000, 1152000, 1500000, 2000000,
+	2500000, 3000000, 3500000, 4000000
+};
+
+static __u8 acm_tty_size[] = {
+	5, 6, 7, 8
+};
+
+static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old)
+{
+	struct acm *acm = tty->driver_data;
+	struct termios *termios = tty->termios;
+	struct acm_line newline;
+	int newctrl = acm->ctrlout;
+
+	if (!ACM_READY(acm)) return;
+
+	newline.speed = cpu_to_le32p(acm_tty_speed +
+		(termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
+	newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;
+	newline.parity = termios->c_cflag & PARENB ?
+		(termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
+	newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
+
+	acm->clocal = termios->c_cflag & CLOCAL;
+	
+	if (!newline.speed) {
+		newline.speed = acm->line.speed;
+		newctrl &= ~ACM_CTRL_DTR;
+	} else  newctrl |=  ACM_CTRL_DTR;
+
+	if (newctrl != acm->ctrlout)
+		acm_set_control(acm, acm->ctrlout = newctrl);
+
+	if (memcmp(&acm->line, &newline, sizeof(struct acm_line))) {
+		memcpy(&acm->line, &newline, sizeof(struct acm_line));
+		dbg("set line: %d %d %d %d", newline.speed, newline.stopbits, newline.parity, newline.databits);
+		acm_set_line(acm, &acm->line);
+	}
+}
+
+/*
+ * USB probe and disconnect routines.
+ */
+
+static void *acm_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct acm *acm;
+	struct usb_config_descriptor *cfacm;
+	struct usb_interface_descriptor *ifcom, *ifdata;
+	struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
+	int readsize, ctrlsize, minor, i;
+	unsigned char *buf;
+
+	if (dev->descriptor.bDeviceClass != 2 || dev->descriptor.bDeviceSubClass != 0
+		|| dev->descriptor.bDeviceProtocol != 0) return NULL;
+
+	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+
+		cfacm = dev->config + i;
+
+		dbg("probing config %d", cfacm->bConfigurationValue);
+
+		if (cfacm->bNumInterfaces != 2 || 
+		    usb_interface_claimed(cfacm->interface + 0) ||
+		    usb_interface_claimed(cfacm->interface + 1))
+			continue;
+
+		ifcom = cfacm->interface[0].altsetting + 0;
+		ifdata = cfacm->interface[1].altsetting + 0;
+
+		if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) {
+			ifcom = cfacm->interface[1].altsetting + 0;
+			ifdata = cfacm->interface[0].altsetting + 0;
+			if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
+				continue;
+		}
+
+		if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
+		    ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
+			continue;
+
+		epctrl = ifcom->endpoint + 0;
+		epread = ifdata->endpoint + 0;
+		epwrite = ifdata->endpoint + 1;
+
+		if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
+		   (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
+		   ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
+			continue;
+
+		if ((epread->bEndpointAddress & 0x80) != 0x80) {
+			epread = ifdata->endpoint + 1;
+			epwrite = ifdata->endpoint + 0;
+		}
+
+		usb_set_configuration(dev, cfacm->bConfigurationValue);
+
+		for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
+		if (acm_table[minor]) {
+			err("no more free acm devices");
+			return NULL;
+		}
+
+		if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
+			err("out of memory");
+			return NULL;
+		}
+		memset(acm, 0, sizeof(struct acm));
+
+		ctrlsize = epctrl->wMaxPacketSize;
+		readsize = epread->wMaxPacketSize;
+		acm->writesize = epwrite->wMaxPacketSize;
+		acm->iface = cfacm->interface;
+		acm->minor = minor;
+		acm->dev = dev;
+
+		acm->tqueue.routine = acm_softint;
+		acm->tqueue.data = acm;
+
+		if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
+			err("out of memory");
+			kfree(acm);
+			return NULL;
+		}
+
+		FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
+			buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+
+		FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+			buf += ctrlsize, readsize, acm_read_bulk, acm);
+
+		FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+			buf += readsize, acm->writesize, acm_write_bulk, acm);
+	
+		printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+
+		acm_set_control(acm, acm->ctrlout);
+
+		acm->line.speed = cpu_to_le32(9600);
+		acm->line.databits = 8;
+		acm_set_line(acm, &acm->line);
+
+		usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
+		usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+
+		tty_register_devfs(&acm_tty_driver, 0, minor);
+		return acm_table[minor] = acm;
+	}
+
+	return NULL;
+}
+
+static void acm_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct acm *acm = ptr;
+
+	if (!acm || !acm->dev) {
+		dbg("disconnect on nonexisting interface");
+		return;
+	}
+
+	acm->dev = NULL;
+
+	usb_unlink_urb(&acm->ctrlurb);
+	usb_unlink_urb(&acm->readurb);
+	usb_unlink_urb(&acm->writeurb);
+
+	kfree(acm->ctrlurb.transfer_buffer);
+
+	usb_driver_release_interface(&acm_driver, acm->iface + 0);
+	usb_driver_release_interface(&acm_driver, acm->iface + 1);
+
+	if (!acm->used) {
+		tty_unregister_devfs(&acm_tty_driver, acm->minor);
+		acm_table[acm->minor] = NULL;
+		kfree(acm);
+		return;
+	}
+
+	if (acm->tty)
+		tty_hangup(acm->tty);
+}
+
+/*
+ * USB driver structure.
+ */
+
+static struct usb_driver acm_driver = {
+	name:		"acm",
+	probe:		acm_probe,
+	disconnect:	acm_disconnect
+};
+
+/*
+ * TTY driver structures.
+ */
+
+static int acm_tty_refcount;
+
+static struct tty_struct *acm_tty_table[ACM_TTY_MINORS];
+static struct termios *acm_tty_termios[ACM_TTY_MINORS];
+static struct termios *acm_tty_termios_locked[ACM_TTY_MINORS];
+
+static struct tty_driver acm_tty_driver = {
+	magic:			TTY_DRIVER_MAGIC,
+	driver_name:		"acm",
+	name:			"usb/acm/%d",
+	major:			ACM_TTY_MAJOR,
+	minor_start:		0,
+	num:			ACM_TTY_MINORS,
+	type:			TTY_DRIVER_TYPE_SERIAL,
+	subtype:		SERIAL_TYPE_NORMAL,
+	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+	refcount:		&acm_tty_refcount,
+
+	table:			acm_tty_table,
+	termios:		acm_tty_termios,
+	termios_locked:		acm_tty_termios_locked,
+
+	open:			acm_tty_open,
+	close:			acm_tty_close,
+	write:			acm_tty_write,
+	write_room:		acm_tty_write_room,
+	ioctl:			acm_tty_ioctl,
+	throttle:		acm_tty_throttle,
+	unthrottle:		acm_tty_unthrottle,
+	chars_in_buffer:	acm_tty_chars_in_buffer,
+	break_ctl:		acm_tty_break_ctl,
+	set_termios:		acm_tty_set_termios
+};
+
+/*
+ * Init / exit.
+ */
+
+static int __init acm_init(void)
+{
+	acm_tty_driver.init_termios =		tty_std_termios;
+	acm_tty_driver.init_termios.c_cflag =	B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+	if (tty_register_driver(&acm_tty_driver))
+		return -1;
+
+	if (usb_register(&acm_driver) < 0) {
+		tty_unregister_driver(&acm_tty_driver);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void __exit acm_exit(void)
+{
+	usb_deregister(&acm_driver);
+	tty_unregister_driver(&acm_tty_driver);
+}
+
+module_init(acm_init);
+module_exit(acm_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/audio.c linux.18p8/drivers/usb/audio.c
--- linux.vanilla/drivers/usb/audio.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/audio.c	Fri Sep  1 13:55:29 2000
@@ -1,126 +1,3717 @@
+/*****************************************************************************/
+
+/*
+ *	audio.c  --  USB Audio Class driver
+ *
+ *	Copyright (C) 1999, 2000
+ *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
+ *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *
+ * 1999-09-07:  Alan Cox
+ *		Parsing Audio descriptor patch
+ * 1999-09-08:  Thomas Sailer
+ *		Added OSS compatible data io functions; both parts of the
+ *		driver remain to be glued together
+ * 1999-09-10:  Thomas Sailer
+ *		Beautified the driver. Added sample format conversions.
+ *		Still not properly glued with the parsing code.
+ *		The parsing code seems to have its problems btw,
+ *		Since it parses all available configs but doesn't
+ *		store which iface/altsetting belongs to which config.
+ * 1999-09-20:  Thomas Sailer
+ *		Threw out Alan's parsing code and implemented my own one.
+ *		You cannot reasonnably linearly parse audio descriptors,
+ *		especially the AudioClass descriptors have to be considered
+ *		pointer lists. Mixer parsing untested, due to lack of device.
+ *		First stab at synch pipe implementation, the Dallas USB DAC
+ *		wants to use an Asynch out pipe. usb_audio_state now basically
+ *		only contains lists of mixer and wave devices. We can therefore
+ *		now have multiple mixer/wave devices per USB device.
+ * 1999-10-28:  Thomas Sailer
+ *		Converted to URB API. Fixed a taskstate/wakeup semantics mistake
+ *		that made the driver consume all available CPU cycles.
+ *		Now runs stable on UHCI-Acher/Fliegl/Sailer.
+ * 1999-10-31:  Thomas Sailer
+ *		Audio can now be unloaded if it is not in use by any mixer
+ *		or dsp client (formerly you had to disconnect the audio devices
+ *		from the USB port)
+ *		Finally, about three months after ordering, my "Maxxtro SPK222"
+ *		speakers arrived, isn't disdata a great mail order company 8-)
+ *		Parse class specific endpoint descriptor of the audiostreaming
+ *		interfaces and take the endpoint attributes from there.
+ *		Unbelievably, the Philips USB DAC has a sampling rate range
+ *		of over a decade, yet does not support the sampling rate control!
+ *		No wonder it sounds so bad, has very audible sampling rate
+ *		conversion distortion. Don't try to listen to it using
+ *		decent headphones!
+ *		"Let's make things better" -> but please Philips start with your
+ *		own stuff!!!!
+ * 1999-11-02:  Thomas Sailer
+ *		It takes the Philips boxes several seconds to acquire synchronisation
+ *		that means they won't play short sounds. Should probably maintain
+ *		the ISO datastream even if there's nothing to play.
+ *		Fix counting the total_bytes counter, RealPlayer G2 depends on it.
+ * 1999-12-20:  Thomas Sailer
+ *		Fix bad bug in conversion to per interface probing.
+ *		disconnect was called multiple times for the audio device,
+ *		leading to a premature freeing of the audio structures
+ * 2000-05-13:  Thomas Sailer
+ *		I don't remember who changed the find_format routine,
+ *              but the change was completely broken for the Dallas
+ *              chip. Anyway taking sampling rate into account in find_format
+ *              is bad and should not be done unless there are devices with
+ *              completely broken audio descriptors. Unless someone shows
+ *              me such a descriptor, I will not allow find_format to
+ *              take the sampling rate into account.
+ *              Also, the former find_format made:
+ *              - mpg123 play mono instead of stereo
+ *              - sox completely fail for wav's with sample rates < 44.1kHz
+ *                  for the Dallas chip.
+ *              Also fix a rather long standing problem with applications that
+ *              use "small" writes producing no sound at all.
+ * 2000-05-15:  Thomas Sailer
+ *		My fears came true, the Philips camera indeed has pretty stupid
+ *              audio descriptors.
+ * 2000-05-17:  Thomas Sailer
+ *		Nemsoft spotted my stupid last minute change, thanks
+ * 2000-05-19:  Thomas Sailer
+ *		Fixed FEATURE_UNIT thinkos found thanks to the KC Technology
+ *              Xtend device. Basically the driver treated FEATURE_UNIT's sourced
+ *              by mono terminals as stereo.
+ * 2000-05-20:  Thomas Sailer
+ *		SELECTOR support (and thus selecting record channels from the mixer).
+ *              Somewhat peculiar due to OSS interface limitations. Only works
+ *              for channels where a "slider" is already in front of it (i.e.
+ *              a MIXER unit or a FEATURE unit with volume capability).
+ *
+ */
+
+/*
+ * Strategy:
+ *
+ * Alan Cox and Thomas Sailer are starting to dig at opposite ends and
+ * are hoping to meet in the middle, just like tunnel diggers :)
+ * Alan tackles the descriptor parsing, Thomas the actual data IO and the
+ * OSS compatible interface.
+ *
+ * Data IO implementation issues
+ *
+ * A mmap'able ring buffer per direction is implemented, because
+ * almost every OSS app expects it. It is however impractical to
+ * transmit/receive USB data directly into and out of the ring buffer,
+ * due to alignment and synchronisation issues. Instead, the ring buffer
+ * feeds a constant time delay line that handles the USB issues.
+ *
+ * Now we first try to find an alternate setting that exactly matches
+ * the sample format requested by the user. If we find one, we do not
+ * need to perform any sample rate conversions. If there is no matching
+ * altsetting, we choose the closest one and perform sample format
+ * conversions. We never do sample rate conversion; these are too
+ * expensive to be performed in the kernel.
+ *
+ * Current status:
+ * - Pretty stable on UHCI-Acher/Fliegl/Sailer
+ * - Does not work on OHCI due to lack of OHCI driver supporting URB's
+ *
+ * Generally: Due to the brokenness of the Audio Class spec
+ * it seems generally impossible to write a generic Audio Class driver,
+ * so a reasonable driver should implement the features that are actually
+ * used.
+ *
+ * Parsing implementation issues
+ *
+ * One cannot reasonably parse the AudioClass descriptors linearly.
+ * Therefore the current implementation features routines to look
+ * for a specific descriptor in the descriptor list.
+ *
+ * How does the parsing work? First, all interfaces are searched
+ * for an AudioControl class interface. If found, the config descriptor
+ * that belongs to the current configuration is fetched from the device.
+ * Then the HEADER descriptor is fetched. It contains a list of
+ * all AudioStreaming and MIDIStreaming devices. This list is then walked,
+ * and all AudioStreaming interfaces are classified into input and output
+ * interfaces (according to the endpoint0 direction in altsetting1) (MIDIStreaming
+ * is currently not supported). The input & output list is then used
+ * to group inputs and outputs together and issued pairwise to the
+ * AudioStreaming class parser. Finally, all OUTPUT_TERMINAL descriptors
+ * are walked and issued to the mixer construction routine.
+ *
+ * The AudioStreaming parser simply enumerates all altsettings belonging
+ * to the specified interface. It looks for AS_GENERAL and FORMAT_TYPE
+ * class specific descriptors to extract the sample format/sample rate
+ * data. Only sample format types PCM and PCM8 are supported right now, and
+ * only FORMAT_TYPE_I is handled. The isochronous data endpoint needs to
+ * be the first endpoint of the interface, and the optional synchronisation
+ * isochronous endpoint the second one.
+ *
+ * Mixer construction works as follows: The various TERMINAL and UNIT
+ * descriptors span a tree from the root (OUTPUT_TERMINAL) through the
+ * intermediate nodes (UNITs) to the leaves (INPUT_TERMINAL). We walk
+ * that tree in a depth first manner. FEATURE_UNITs may contribute volume,
+ * bass and treble sliders to the mixer, MIXER_UNITs volume sliders.
+ * The terminal type encoded in the INPUT_TERMINALs feeds a heuristic
+ * to determine "meaningful" OSS slider numbers, however we will see
+ * how well this works in practice. Other features are not used at the
+ * moment, they seem less often used. Also, it seems difficult at least
+ * to construct recording source switches from SELECTOR_UNITs, but
+ * since there are not many USB ADC's available, we leave that for later.
+ */
+
+/*****************************************************************************/
+
+#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
-#include "usb.h"
+#include <linux/module.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/wrapper.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/usb.h>
 
-static int usb_audio_probe(struct usb_device *dev);
-static void usb_audio_disconnect(struct usb_device *dev);
-static LIST_HEAD(usb_audio_list);
+#include "audio.h"
 
-struct usb_audio
-{
-	struct usb_device *dev;
+#define AUDIO_DEBUG 1
+
+#define SND_DEV_DSP16   5 
+
+#define dprintk(x)
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Linked list of all audio devices...
+ */
+static struct list_head audiodevs = LIST_HEAD_INIT(audiodevs);
+static DECLARE_MUTEX(open_sem);
+
+/*
+ * wait queue for processes wanting to open an USB audio device
+ */
+static DECLARE_WAIT_QUEUE_HEAD(open_wait);
+
+
+#define MAXFORMATS        MAX_ALT
+#define DMABUFSHIFT       17  /* 128k worth of DMA buffer */
+#define NRSGBUF           (1U<<(DMABUFSHIFT-PAGE_SHIFT))
+
+/*
+ * This influences:
+ * - Latency
+ * - Interrupt rate
+ * - Synchronisation behaviour
+ * Don't touch this if you don't understand all of the above.
+ */
+#define DESCFRAMES  5
+#define SYNCFRAMES  DESCFRAMES
+
+#define MIXFLG_STEREOIN   1
+#define MIXFLG_STEREOOUT  2
+
+struct mixerchannel {
+	__u16 value;
+	__u16 osschannel;  /* number of the OSS channel */
+	__s16 minval, maxval;
+	__u16 slctunitid;
+	__u8 unitid;
+	__u8 selector;
+	__u8 chnum;
+	__u8 flags;
+};
+
+struct audioformat {
+	unsigned int format;
+	unsigned int sratelo;
+	unsigned int sratehi;
+	unsigned char altsetting;
+	unsigned char attributes;
+};
+
+struct dmabuf {
+	/* buffer data format */
+	unsigned int format;
+	unsigned int srate;
+	/* physical buffer */
+	unsigned char *sgbuf[NRSGBUF];
+	unsigned bufsize;
+	unsigned numfrag;
+	unsigned fragshift;
+	unsigned wrptr, rdptr;
+	unsigned total_bytes;
+	int count;
+	unsigned error; /* over/underrun */
+	wait_queue_head_t wait;
+	/* redundant, but makes calculations easier */
+	unsigned fragsize;
+	unsigned dmasize;
+	/* OSS stuff */
+	unsigned mapped:1;
+	unsigned ready:1;
+	unsigned ossfragshift;
+	int ossmaxfrags;
+	unsigned subdivision;
+};
+
+struct usb_audio_state;
+
+#define FLG_URB0RUNNING   1
+#define FLG_URB1RUNNING   2
+#define FLG_SYNC0RUNNING  4
+#define FLG_SYNC1RUNNING  8
+#define FLG_RUNNING      16
+#define FLG_CONNECTED    32
+
+struct my_data_urb {
+	urb_t urb;
+	iso_packet_descriptor_t isoframe[DESCFRAMES];
+};
+
+struct my_sync_urb {
+	urb_t urb;
+	iso_packet_descriptor_t isoframe[SYNCFRAMES];
+};
+
+
+struct usb_audiodev {
+	struct list_head list;
+	struct usb_audio_state *state;
+	
+	/* soundcore stuff */
+	int dev_audio;
+
+	/* wave stuff */
+	mode_t open_mode;
+	spinlock_t lock;         /* DMA buffer access spinlock */
+
+	struct usbin {
+		int interface;           /* Interface number, -1 means not used */
+		unsigned int format;     /* USB data format */
+		unsigned int datapipe;   /* the data input pipe */
+		unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but adaptive IN mode */
+		unsigned int syncinterval;  /* P for adaptive IN mode, 0 otherwise */
+		unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+		unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
+		unsigned int phase;      /* phase accumulator */
+		unsigned int flags;      /* see FLG_ defines */
+		
+		struct my_data_urb durb[2];  /* ISO descriptors for the data endpoint */
+		struct my_sync_urb surb[2];  /* ISO sync pipe descriptor if needed */
+		
+		struct dmabuf dma;
+	} usbin;
+
+	struct usbout {
+		int interface;           /* Interface number, -1 means not used */
+		unsigned int format;     /* USB data format */
+		unsigned int datapipe;   /* the data input pipe */
+		unsigned int syncpipe;   /* the synchronisation pipe - 0 for anything but asynchronous OUT mode */
+		unsigned int syncinterval;  /* P for asynchronous OUT mode, 0 otherwise */
+		unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+		unsigned int freqm;      /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+		unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
+		unsigned int phase;      /* phase accumulator */
+		unsigned int flags;      /* see FLG_ defines */
+
+		struct my_data_urb durb[2];  /* ISO descriptors for the data endpoint */
+		struct my_sync_urb surb[2];  /* ISO sync pipe descriptor if needed */
+		
+		struct dmabuf dma;
+	} usbout;
+
+
+	unsigned int numfmtin, numfmtout;
+	struct audioformat fmtin[MAXFORMATS];
+	struct audioformat fmtout[MAXFORMATS];
+};  
+
+struct usb_mixerdev {
 	struct list_head list;
+	struct usb_audio_state *state;
+
+	/* soundcore stuff */
+	int dev_mixer;
+
+	unsigned char iface;  /* interface number of the AudioControl interface */
+
+	/* USB format descriptions */
+	unsigned int numch, modcnt;
+
+	/* mixch is last and gets allocated dynamically */
+	struct mixerchannel ch[0];
 };
 
-static struct usb_driver usb_audio_driver =
-{
-	"audio",
-	usb_audio_probe,
-	usb_audio_disconnect,
-	{NULL, NULL}
+struct usb_audio_state {
+	struct list_head audiodev;
+
+	/* USB device */
+	struct usb_device *usbdev;
+
+	struct list_head audiolist;
+	struct list_head mixerlist;
+
+	unsigned count;  /* usage counter; NOTE: the usb stack is also considered a user */
 };
 
+/* private audio format extensions */
+#define AFMT_STEREO        0x80000000
+#define AFMT_ISSTEREO(x)   ((x) & AFMT_STEREO)
+#define AFMT_IS16BIT(x)    ((x) & (AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE))
+#define AFMT_ISUNSIGNED(x) ((x) & (AFMT_U8|AFMT_U16_LE|AFMT_U16_BE))
+#define AFMT_BYTESSHIFT(x) ((AFMT_ISSTEREO(x) ? 1 : 0) + (AFMT_IS16BIT(x) ? 1 : 0))
+#define AFMT_BYTES(x)      (1<<AFMT_BYTESSHFIT(x))
+
+/* --------------------------------------------------------------------- */
 
-static int usb_audio_irq(int state, void *buffer, void *dev_id)
+extern inline unsigned ld2(unsigned int x)
 {
-	struct usb_audio *aud = (struct usb_audio*) dev_id;
-	return 1;
+	unsigned r = 0;
+	
+	if (x >= 0x10000) {
+		x >>= 16;
+		r += 16;
+	}
+	if (x >= 0x100) {
+		x >>= 8;
+		r += 8;
+	}
+	if (x >= 0x10) {
+		x >>= 4;
+		r += 4;
+	}
+	if (x >= 4) {
+		x >>= 2;
+		r += 2;
+	}
+	if (x >= 2)
+		r++;
+	return r;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * OSS compatible ring buffer management. The ring buffer may be mmap'ed into
+ * an application address space.
+ *
+ * I first used the rvmalloc stuff copied from bttv. Alan Cox did not like it, so
+ * we now use an array of pointers to a single page each. This saves us the
+ * kernel page table manipulations, but we have to do a page table alike mechanism
+ * (though only one indirection) in software.
+ */
+
+static void dmabuf_release(struct dmabuf *db)
+{
+	unsigned int nr;
+	void *p;
+
+	for(nr = 0; nr < NRSGBUF; nr++) {
+		if (!(p = db->sgbuf[nr]))
+			continue;
+		mem_map_unreserve(MAP_NR(p));
+		free_page((unsigned long)p);
+		db->sgbuf[nr] = NULL;
+	}
+	db->mapped = db->ready = 0;
 }
 
-static int usb_audio_probe(struct usb_device *dev)
+static int dmabuf_init(struct dmabuf *db)
 {
-	struct usb_interface_descriptor *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_audio *aud;
+	unsigned int nr, bytepersec, bufs;
+	void *p;
 
-	int i;
-	int na=0;
-	
-	interface = &dev->config[0].interface[0];
+	/* initialize some fields */
+	db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;
+	/* calculate required buffer size */
+	bytepersec = db->srate << AFMT_BYTESSHIFT(db->format);
+	bufs = 1U << DMABUFSHIFT;
+	if (db->ossfragshift) {
+		if ((1000 << db->ossfragshift) < bytepersec)
+			db->fragshift = ld2(bytepersec/1000);
+		else
+			db->fragshift = db->ossfragshift;
+	} else {
+		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+		if (db->fragshift < 3)
+			db->fragshift = 3;
+	}
+	db->numfrag = bufs >> db->fragshift;
+	while (db->numfrag < 4 && db->fragshift > 3) {
+		db->fragshift--;
+		db->numfrag = bufs >> db->fragshift;
+	}
+	db->fragsize = 1 << db->fragshift;
+	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+		db->numfrag = db->ossmaxfrags;
+	db->dmasize = db->numfrag << db->fragshift;
+	for(nr = 0; nr < NRSGBUF; nr++) {
+		if (!db->sgbuf[nr]) {
+			p = (void *)get_free_page(GFP_KERNEL);
+			if (!p)
+				return -ENOMEM;
+			db->sgbuf[nr] = p;
+			mem_map_reserve(MAP_NR(p));
+		}
+		memset(db->sgbuf[nr], AFMT_ISUNSIGNED(db->format) ? 0x80 : 0, PAGE_SIZE);
+		if ((nr << PAGE_SHIFT) >= db->dmasize)
+			break;
+	}
+	db->bufsize = nr << PAGE_SHIFT;
+	db->ready = 1;
+	dprintk((KERN_DEBUG "dmabuf_init: bytepersec %d bufs %d ossfragshift %d ossmaxfrags %d "
+	       "fragshift %d fragsize %d numfrag %d dmasize %d bufsize %d fmt 0x%x\n",
+	       bytepersec, bufs, db->ossfragshift, db->ossmaxfrags, db->fragshift, db->fragsize,
+	       db->numfrag, db->dmasize, db->bufsize, db->format));
+	return 0;
+}
+
+static int dmabuf_mmap(struct dmabuf *db, unsigned long start, unsigned long size, pgprot_t prot)
+{
+	unsigned int nr;
+
+	if (!db->ready || db->mapped || (start | size) & (PAGE_SIZE-1) || size > db->bufsize)
+		return -EINVAL;
+	size >>= PAGE_SHIFT;
+	for(nr = 0; nr < size; nr++)
+		if (!db->sgbuf[nr])
+			return -EINVAL;
+	db->mapped = 1;
+	for(nr = 0; nr < size; nr++) {
+		if (remap_page_range(start, virt_to_phys(db->sgbuf[nr]), PAGE_SIZE, prot))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+	}
+	return 0;
+}
+
+static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size)
+{
+	unsigned int pgrem, rem;
+
+	db->total_bytes += size;
+	for (;;) {
+		if (size <= 0)
+			return;
+		pgrem = ((~db->wrptr) & (PAGE_SIZE-1)) + 1;
+		if (pgrem > size)
+			pgrem = size;
+		rem = db->dmasize - db->wrptr;
+		if (pgrem > rem)
+			pgrem = rem;
+		memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem);
+		size -= pgrem;
+		(char *)buffer += pgrem;
+		db->wrptr += pgrem;
+		if (db->wrptr >= db->dmasize)
+			db->wrptr = 0;
+	}
+}
+
+static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size)
+{
+	unsigned int pgrem, rem;
+
+	db->total_bytes += size;
+	for (;;) {
+		if (size <= 0)
+			return;
+		pgrem = ((~db->rdptr) & (PAGE_SIZE-1)) + 1;
+		if (pgrem > size)
+			pgrem = size;
+		rem = db->dmasize - db->rdptr;
+		if (pgrem > rem)
+			pgrem = rem;
+		memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem);
+		size -= pgrem;
+		(char *)buffer += pgrem;
+		db->rdptr += pgrem;
+		if (db->rdptr >= db->dmasize)
+			db->rdptr = 0;
+	}
+}
+
+static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *buffer, unsigned int size)
+{
+	unsigned int pgrem, rem;
+
+	if (!db->ready || db->mapped)
+		return -EINVAL;
+	for (;;) {
+		if (size <= 0)
+			return 0;
+		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
+		if (pgrem > size)
+			pgrem = size;
+		rem = db->dmasize - ptr;
+		if (pgrem > rem)
+			pgrem = rem;
+		copy_from_user_ret((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem, -EFAULT);
+		size -= pgrem;
+		(char *)buffer += pgrem;
+		ptr += pgrem;
+		if (ptr >= db->dmasize)
+			ptr = 0;
+	}
+}
+
+static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *buffer, unsigned int size)
+{
+	unsigned int pgrem, rem;
+
+	if (!db->ready || db->mapped)
+		return -EINVAL;
+	for (;;) {
+		if (size <= 0)
+			return 0;
+		pgrem = ((~ptr) & (PAGE_SIZE-1)) + 1;
+		if (pgrem > size)
+			pgrem = size;
+		rem = db->dmasize - ptr;
+		if (pgrem > rem)
+			pgrem = rem;
+		copy_to_user_ret(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem, -EFAULT);
+		size -= pgrem;
+		(char *)buffer += pgrem;
+		ptr += pgrem;
+		if (ptr >= db->dmasize)
+			ptr = 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * USB I/O code. We do sample format conversion if necessary
+ */
+
+static void usbin_stop(struct usb_audiodev *as)
+{
+	struct usbin *u = &as->usbin;
+	unsigned long flags;
+	unsigned int i, notkilled = 1;
+
+	spin_lock_irqsave(&as->lock, flags);
+	u->flags &= ~FLG_RUNNING;
+	i = u->flags;
+	spin_unlock_irqrestore(&as->lock, flags);
+	while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
+		set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+		spin_lock_irqsave(&as->lock, flags);
+		i = u->flags;
+		spin_unlock_irqrestore(&as->lock, flags);
+		if (notkilled && signal_pending(current)) {
+			if (i & FLG_URB0RUNNING)
+				usb_unlink_urb(&u->durb[0].urb);
+			if (i & FLG_URB1RUNNING)
+				usb_unlink_urb(&u->durb[1].urb);
+			if (i & FLG_SYNC0RUNNING)
+				usb_unlink_urb(&u->surb[0].urb);
+			if (i & FLG_SYNC1RUNNING)
+				usb_unlink_urb(&u->surb[1].urb);
+			notkilled = 0;
+		}
+	}
+	set_current_state(TASK_RUNNING);
+	if (u->durb[0].urb.transfer_buffer)
+		kfree(u->durb[0].urb.transfer_buffer);
+	if (u->durb[1].urb.transfer_buffer)
+		kfree(u->durb[1].urb.transfer_buffer);
+	if (u->surb[0].urb.transfer_buffer)
+		kfree(u->surb[0].urb.transfer_buffer);
+	if (u->surb[1].urb.transfer_buffer)
+		kfree(u->surb[1].urb.transfer_buffer);
+	u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = 
+		u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
+}
+
+static inline void usbin_release(struct usb_audiodev *as)
+{
+	usbin_stop(as);
+}
+
+static void usbin_disc(struct usb_audiodev *as)
+{
+	struct usbin *u = &as->usbin;
+
+	unsigned long flags;
+
+	spin_lock_irqsave(&as->lock, flags);
+	u->flags &= ~(FLG_RUNNING | FLG_CONNECTED);
+	spin_unlock_irqrestore(&as->lock, flags);
+	usbin_stop(as);
+}
+
+static void conversion(const void *ibuf, unsigned int ifmt, void *obuf, unsigned int ofmt, void *tmp, unsigned int scnt)
+{
+	unsigned int cnt, i;
+	__s16 *sp, *sp2, s;
+	unsigned char *bp;
 
-	for(i=0;i<dev->config[0].bNumInterfaces;i++)
-	{
-		int x;
+	cnt = scnt;
+	if (AFMT_ISSTEREO(ifmt))
+		cnt <<= 1;
+	sp = ((__s16 *)tmp) + cnt;
+	switch (ifmt & ~AFMT_STEREO) {
+	case AFMT_U8:
+		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
+			bp--;
+			sp--;
+			*sp = (*bp ^ 0x80) << 8;
+		}
+		break;
+			
+	case AFMT_S8:
+		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
+			bp--;
+			sp--;
+			*sp = *bp << 8;
+		}
+		break;
 		
-		endpoint = &interface->endpoint[i];
+	case AFMT_U16_LE:
+		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
+			bp -= 2;
+			sp--;
+			*sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
+		}
+		break;
+
+	case AFMT_U16_BE:
+		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
+			bp -= 2;
+			sp--;
+			*sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
+		}
+		break;
+
+	case AFMT_S16_LE:
+		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
+			bp -= 2;
+			sp--;
+			*sp = bp[0] | (bp[1] << 8);
+		}
+		break;
+
+	case AFMT_S16_BE:
+		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
+			bp -= 2;
+			sp--;
+			*sp = bp[1] | (bp[0] << 8);
+		}
+		break;
+	}
+	if (!AFMT_ISSTEREO(ifmt) && AFMT_ISSTEREO(ofmt)) {
+		/* expand from mono to stereo */
+		for (sp = ((__s16 *)tmp)+scnt, sp2 = ((__s16 *)tmp)+2*scnt, i = 0; i < scnt; i++) {
+			sp--;
+			sp2 -= 2;
+			sp2[0] = sp2[1] = sp[0];
+		}
+	}
+	if (AFMT_ISSTEREO(ifmt) && !AFMT_ISSTEREO(ofmt)) {
+		/* contract from stereo to mono */
+		for (sp = sp2 = ((__s16 *)tmp), i = 0; i < scnt; i++, sp++, sp2 += 2)
+			sp[0] = (sp2[0] + sp2[1]) >> 1;
+	}
+	cnt = scnt;
+	if (AFMT_ISSTEREO(ofmt))
+		cnt <<= 1;
+	sp = ((__s16 *)tmp);
+	bp = ((unsigned char *)obuf);
+	switch (ofmt & ~AFMT_STEREO) {
+	case AFMT_U8:
+		for (i = 0; i < cnt; i++, sp++, bp++)
+			*bp = (*sp >> 8) ^ 0x80;
+		break;
+
+	case AFMT_S8:
+		for (i = 0; i < cnt; i++, sp++, bp++)
+			*bp = *sp >> 8;
+		break;
+
+	case AFMT_U16_LE:
+		for (i = 0; i < cnt; i++, sp++, bp += 2) {
+			s = *sp;
+			bp[0] = s;
+			bp[1] = (s >> 8) ^ 0x80;
+		}
+		break;
+
+	case AFMT_U16_BE:
+		for (i = 0; i < cnt; i++, sp++, bp += 2) {
+			s = *sp;
+			bp[1] = s;
+			bp[0] = (s >> 8) ^ 0x80;
+		}
+		break;
 
-		if(interface->bInterfaceClass != 1) 
-	        	continue;
+	case AFMT_S16_LE:
+		for (i = 0; i < cnt; i++, sp++, bp += 2) {
+			s = *sp;
+			bp[0] = s;
+			bp[1] = s >> 8;
+		}
+		break;
 
-		printk(KERN_INFO "USB audio device detected.\n");
+	case AFMT_S16_BE:
+		for (i = 0; i < cnt; i++, sp++, bp += 2) {
+			s = *sp;
+			bp[1] = s;
+			bp[0] = s >> 8;
+		}
+		break;
+	}
 	
-		switch(interface->bInterfaceSubClass)
-		{
-			case 0x01:
-				printk(KERN_INFO "audio: Control device.\n");
-				break;
-			case 0x02:
-				printk(KERN_INFO "audio: streaming.\n");
-				break;
-			case 0x03:
-				printk(KERN_INFO "audio: nonstreaming.\n");
-				break;
+}
+
+static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
+{
+	union {
+		__s16 s[64];
+		unsigned char b[0];
+	} tmp;
+	unsigned int scnt, maxs, ufmtsh, dfmtsh;
+
+	ufmtsh = AFMT_BYTESSHIFT(u->format);
+	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
+	while (samples > 0) {
+		scnt = samples;
+		if (scnt > maxs)
+			scnt = maxs;
+		conversion(buffer, u->format, tmp.b, u->dma.format, tmp.b, scnt);
+		dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh);
+		buffer += scnt << ufmtsh;
+		samples -= scnt;
+	}
+}		
+
+static int usbin_prepare_desc(struct usbin *u, purb_t urb)
+{
+	unsigned int i, maxsize, offs;
+
+	maxsize = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
+	//printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format);
+	for (i = offs = 0; i < DESCFRAMES; i++, offs += maxsize) {
+		urb->iso_frame_desc[i].length = maxsize;
+		urb->iso_frame_desc[i].offset = offs;
+	}
+	return 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ * convert sample format on the fly if necessary
+ */
+static int usbin_retire_desc(struct usbin *u, purb_t urb)
+{
+	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
+	unsigned char *cp;
+
+	ufmtsh = AFMT_BYTESSHIFT(u->format);
+	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	for (i = 0; i < DESCFRAMES; i++) {
+		cp = ((unsigned char *)urb->transfer_buffer) + urb->iso_frame_desc[i].offset;
+		if (urb->iso_frame_desc[i].status) {
+			dprintk((KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
+			continue;
+		}
+		scnt = urb->iso_frame_desc[i].actual_length >> ufmtsh;
+		if (!scnt)
+			continue;
+		cnt = scnt << dfmtsh;
+		if (!u->dma.mapped) {
+			dmafree = u->dma.dmasize - u->dma.count;
+			if (cnt > dmafree) {
+				scnt = dmafree >> dfmtsh;
+				cnt = scnt << dfmtsh;
+				err++;
+			}
 		}
-		na++;
+		u->dma.count += cnt;
+		if (u->format == u->dma.format) {
+			/* we do not need format conversion */
+			dmabuf_copyin(&u->dma, cp, cnt);
+		} else {
+			/* we need sampling format conversion */
+			usbin_convert(u, cp, scnt);
+		}
+	}
+	if (err)
+		u->dma.error++;
+	if (u->dma.count >= (signed)u->dma.fragsize)
+		wake_up(&u->dma.wait);
+	return err ? -1 : 0;
+}
+
+static void usbin_completed(struct urb *urb)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
+	struct usbin *u = &as->usbin;
+	unsigned long flags;
+	unsigned int mask;
+	int suret = USB_ST_NOERROR;
+
+#if 0
+	printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
+#endif
+	if (urb == &u->durb[0].urb)
+		mask = FLG_URB0RUNNING;
+	else if (urb == &u->durb[1].urb)
+		mask = FLG_URB1RUNNING;
+	else {
+		mask = 0;
+		printk(KERN_ERR "usbin_completed: panic: unknown URB\n");
 	}
+	spin_lock_irqsave(&as->lock, flags);
+	if (!usbin_retire_desc(u, urb) &&
+	    u->flags & FLG_RUNNING &&
+	    !usbin_prepare_desc(u, urb) && 
+	    (suret = usb_submit_urb(urb)) == USB_ST_NOERROR) {
+		u->flags |= mask;
+	} else {
+		u->flags &= ~(mask | FLG_RUNNING);
+		wake_up(&u->dma.wait);
+		printk(KERN_DEBUG "usbin_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret);
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
+}
+
+/*
+ * we output sync data
+ */
+static int usbin_sync_prepare_desc(struct usbin *u, purb_t urb)
+{
+	unsigned char *cp = urb->transfer_buffer;
+	unsigned int i, offs;
 	
-	if(na==0)
-		return -1;
+	for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3, cp += 3) {
+		urb->iso_frame_desc[i].length = 3;
+		urb->iso_frame_desc[i].offset = offs;
+		cp[0] = u->freqn;
+		cp[1] = u->freqn >> 8;
+		cp[2] = u->freqn >> 16;
+	}
+	return 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ */
+static int usbin_sync_retire_desc(struct usbin *u, purb_t urb)
+{
+	unsigned int i;
+	
+	for (i = 0; i < SYNCFRAMES; i++)
+		if (urb->iso_frame_desc[0].status)
+			dprintk((KERN_DEBUG "usbin_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
+	return 0;
+}
 
-	aud = kmalloc(sizeof(struct usb_audio), GFP_KERNEL);
-	if(aud)
-	{
-        	memset(aud, 0, sizeof(*aud));
-        	aud->dev = dev;
-        	dev->private = aud;
+static void usbin_sync_completed(struct urb *urb)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
+	struct usbin *u = &as->usbin;
+	unsigned long flags;
+	unsigned int mask;
+	int suret = USB_ST_NOERROR;
 
-		endpoint = &interface->endpoint[0];
+#if 0
+	printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
+#endif
+	if (urb == &u->surb[0].urb)
+		mask = FLG_SYNC0RUNNING;
+	else if (urb == &u->surb[1].urb)
+		mask = FLG_SYNC1RUNNING;
+	else {
+		mask = 0;
+		printk(KERN_ERR "usbin_sync_completed: panic: unknown URB\n");
+	}
+	spin_lock_irqsave(&as->lock, flags);
+	if (!usbin_sync_retire_desc(u, urb) &&
+	    u->flags & FLG_RUNNING &&
+	    !usbin_sync_prepare_desc(u, urb) && 
+	    (suret = usb_submit_urb(urb)) == USB_ST_NOERROR) {
+		u->flags |= mask;
+	} else {
+		u->flags &= ~(mask | FLG_RUNNING);
+		wake_up(&u->dma.wait);
+		dprintk((KERN_DEBUG "usbin_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
+}
 
-//        	usb_set_configuration(dev, dev->config[0].bConfigurationValue);
-//        	usb_set_protocol(dev, 0);
-//        	usb_set_idle(dev, 0, 0);
-        
-        	usb_request_irq(dev,
-                        usb_rcvctrlpipe(dev, endpoint->bEndpointAddress),
-                        usb_audio_irq,
-                        endpoint->bInterval,
-                        aud);
+static int usbin_start(struct usb_audiodev *as)
+{
+	struct usb_device *dev = as->state->usbdev;
+	struct usbin *u = &as->usbin;
+	purb_t urb;
+	unsigned long flags;
+	unsigned int maxsze, bufsz;
 
-		list_add(&aud->list, &usb_audio_list);
+#if 0
+	printk(KERN_DEBUG "usbin_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
+	       dev->devnum, u->format, u->dma.format, u->dma.srate);
+#endif
+	/* allocate USB storage if not already done */
+	spin_lock_irqsave(&as->lock, flags);
+	if (!(u->flags & FLG_CONNECTED)) {
+		spin_unlock_irqrestore(&as->lock, flags);
+		return -EIO;
+	}
+	if (!(u->flags & FLG_RUNNING)) {
+		spin_unlock_irqrestore(&as->lock, flags);
+		u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
+		u->freqmax = u->freqn + (u->freqn >> 2);
+		u->phase = 0;
+		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
+		bufsz = DESCFRAMES * maxsze;
+		if (u->durb[0].urb.transfer_buffer)
+			kfree(u->durb[0].urb.transfer_buffer);
+		u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[0].urb.transfer_buffer_length = bufsz;
+		if (u->durb[1].urb.transfer_buffer)
+			kfree(u->durb[1].urb.transfer_buffer);
+		u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[1].urb.transfer_buffer_length = bufsz;
+		if (u->syncpipe) {
+			if (u->surb[0].urb.transfer_buffer)
+				kfree(u->surb[0].urb.transfer_buffer);
+			u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[1].urb.transfer_buffer)
+				kfree(u->surb[1].urb.transfer_buffer);
+			u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
+		}
+		if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer || 
+		    (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
+			return 0;
+		}
+		spin_lock_irqsave(&as->lock, flags);
+	}
+	if (u->dma.count >= u->dma.dmasize && !u->dma.mapped)
+		return 0;
+	u->flags |= FLG_RUNNING;
+	if (!(u->flags & FLG_URB0RUNNING)) {
+		urb = &u->durb[0].urb;
+		urb->dev = dev;
+		urb->pipe = u->datapipe;
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->number_of_packets = DESCFRAMES;
+		urb->context = as;
+		urb->complete = usbin_completed;
+		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb))
+			u->flags |= FLG_URB0RUNNING;
+		else
+			u->flags &= ~FLG_RUNNING;
+	}
+	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
+		urb = &u->durb[1].urb;
+		urb->dev = dev;
+		urb->pipe = u->datapipe;
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->number_of_packets = DESCFRAMES;
+		urb->context = as;
+		urb->complete = usbin_completed;
+		if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb))
+			u->flags |= FLG_URB1RUNNING;
+		else
+			u->flags &= ~FLG_RUNNING;
+	}
+	if (u->syncpipe) {
+		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
+			urb = &u->surb[0].urb;
+			urb->dev = dev;
+			urb->pipe = u->syncpipe;
+			urb->transfer_flags = USB_ISO_ASAP;
+			urb->number_of_packets = SYNCFRAMES;
+			urb->context = as;
+			urb->complete = usbin_sync_completed;
+			/* stride: u->syncinterval */
+			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb))
+				u->flags |= FLG_SYNC0RUNNING;
+			else
+				u->flags &= ~FLG_RUNNING;
+		}
+		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
+			urb = &u->surb[1].urb;
+			urb->dev = dev;
+			urb->pipe = u->syncpipe;
+			urb->transfer_flags = USB_ISO_ASAP;
+			urb->number_of_packets = SYNCFRAMES;
+			urb->context = as;
+			urb->complete = usbin_sync_completed;
+			/* stride: u->syncinterval */
+			if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb))
+				u->flags |= FLG_SYNC1RUNNING;
+			else
+				u->flags &= ~FLG_RUNNING;
+		}
 	}
+	spin_unlock_irqrestore(&as->lock, flags);
 	return 0;
 }
 
-static void usb_audio_disconnect(struct usb_device *dev)
+static void usbout_stop(struct usb_audiodev *as)
 {
-	struct usb_audio *aud = (struct usb_audio*) dev->private;
-	if(aud)
-	{
-        	dev->private = NULL;
-        	list_del(&aud->list);
-        	kfree(aud);
+	struct usbout *u = &as->usbout;
+	unsigned long flags;
+	unsigned int i, notkilled = 1;
+
+	spin_lock_irqsave(&as->lock, flags);
+	u->flags &= ~FLG_RUNNING;
+	i = u->flags;
+	spin_unlock_irqrestore(&as->lock, flags);
+	while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
+		set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+		spin_lock_irqsave(&as->lock, flags);
+		i = u->flags;
+		spin_unlock_irqrestore(&as->lock, flags);
+		if (notkilled && signal_pending(current)) {
+			if (i & FLG_URB0RUNNING)
+				usb_unlink_urb(&u->durb[0].urb);
+			if (i & FLG_URB1RUNNING)
+				usb_unlink_urb(&u->durb[1].urb);
+			if (i & FLG_SYNC0RUNNING)
+				usb_unlink_urb(&u->surb[0].urb);
+			if (i & FLG_SYNC1RUNNING)
+				usb_unlink_urb(&u->surb[1].urb);
+			notkilled = 0;
+		}
 	}
-	printk(KERN_INFO "USB audio driver removed.\n");
+	set_current_state(TASK_RUNNING);
+	if (u->durb[0].urb.transfer_buffer)
+		kfree(u->durb[0].urb.transfer_buffer);
+	if (u->durb[1].urb.transfer_buffer)
+		kfree(u->durb[1].urb.transfer_buffer);
+	if (u->surb[0].urb.transfer_buffer)
+		kfree(u->surb[0].urb.transfer_buffer);
+	if (u->surb[1].urb.transfer_buffer)
+		kfree(u->surb[1].urb.transfer_buffer);
+	u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = 
+		u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
 }
 
-int usb_audio_init(void)
+static inline void usbout_release(struct usb_audiodev *as)
 {
-	usb_register(&usb_audio_driver);
+	usbout_stop(as);
+}
+
+static void usbout_disc(struct usb_audiodev *as)
+{
+	struct usbout *u = &as->usbout;
+	unsigned long flags;
+
+	spin_lock_irqsave(&as->lock, flags);
+	u->flags &= ~(FLG_RUNNING | FLG_CONNECTED);
+	spin_unlock_irqrestore(&as->lock, flags);
+	usbout_stop(as);
+}
+
+static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples)
+{
+	union {
+		__s16 s[64];
+		unsigned char b[0];
+	} tmp;
+	unsigned int scnt, maxs, ufmtsh, dfmtsh;
+
+	ufmtsh = AFMT_BYTESSHIFT(u->format);
+	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
+	while (samples > 0) {
+		scnt = samples;
+		if (scnt > maxs)
+			scnt = maxs;
+		dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh);
+		conversion(tmp.b, u->dma.format, buffer, u->format, tmp.b, scnt);
+		buffer += scnt << ufmtsh;
+		samples -= scnt;
+	}
+}		
+
+static int usbout_prepare_desc(struct usbout *u, purb_t urb)
+{
+	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
+	unsigned char *cp = urb->transfer_buffer;
+
+	ufmtsh = AFMT_BYTESSHIFT(u->format);
+	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
+	for (i = offs = 0; i < DESCFRAMES; i++) {
+		urb->iso_frame_desc[i].offset = offs;
+		u->phase = (u->phase & 0x3fff) + u->freqm;
+		scnt = u->phase >> 14;
+		if (!scnt) {
+			urb->iso_frame_desc[i].length = 0;
+			continue;
+		}
+		cnt = scnt << dfmtsh;
+		if (!u->dma.mapped) {
+			if (cnt > u->dma.count) {
+				scnt = u->dma.count >> dfmtsh;
+				cnt = scnt << dfmtsh;
+				err++;
+			}
+			u->dma.count -= cnt;
+		} else
+			u->dma.count += cnt;
+		if (u->format == u->dma.format) {
+			/* we do not need format conversion */
+			dmabuf_copyout(&u->dma, cp, cnt);
+		} else {
+			/* we need sampling format conversion */
+			usbout_convert(u, cp, scnt);
+		}
+		cnt = scnt << ufmtsh;
+		urb->iso_frame_desc[i].length = cnt;
+		offs += cnt;
+		cp += cnt;
+	}
+	if (err)
+		u->dma.error++;
+	if (u->dma.mapped) {
+		if (u->dma.count >= (signed)u->dma.fragsize)
+			wake_up(&u->dma.wait);
+	} else {
+		if ((signed)u->dma.dmasize >= u->dma.count + (signed)u->dma.fragsize)
+			wake_up(&u->dma.wait);
+	}
+	return err ? -1 : 0;
+}
+
+/*
+ * return value: 0 if descriptor should be restarted, -1 otherwise
+ */
+static int usbout_retire_desc(struct usbout *u, purb_t urb)
+{
+	unsigned int i;
+
+	for (i = 0; i < DESCFRAMES; i++) {
+		if (urb->iso_frame_desc[i].status) {
+			dprintk((KERN_DEBUG "usbout_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
+			continue;
+		}
+	}
+	return 0;
+}
+
+static void usbout_completed(struct urb *urb)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
+	struct usbout *u = &as->usbout;
+	unsigned long flags;
+	unsigned int mask;
+	int suret = USB_ST_NOERROR;
+
+#if 0
+	printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
+#endif
+	if (urb == &u->durb[0].urb)
+		mask = FLG_URB0RUNNING;
+	else if (urb == &u->durb[1].urb)
+		mask = FLG_URB1RUNNING;
+	else {
+		mask = 0;
+		printk(KERN_ERR "usbout_completed: panic: unknown URB\n");
+	}
+	spin_lock_irqsave(&as->lock, flags);
+	if (!usbout_retire_desc(u, urb) &&
+	    u->flags & FLG_RUNNING &&
+	    !usbout_prepare_desc(u, urb) && 
+	    (suret = usb_submit_urb(urb)) == USB_ST_NOERROR) {
+		u->flags |= mask;
+	} else {
+		u->flags &= ~(mask | FLG_RUNNING);
+		wake_up(&u->dma.wait);
+		dprintk((KERN_DEBUG "usbout_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
+}
+
+static int usbout_sync_prepare_desc(struct usbout *u, purb_t urb)
+{
+	unsigned int i, offs;
+
+	for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3) {
+		urb->iso_frame_desc[i].length = 3;
+		urb->iso_frame_desc[i].offset = offs;
+	}
 	return 0;
 }
 
 /*
- *	Support functions for parsing
+ * return value: 0 if descriptor should be restarted, -1 otherwise
  */
- 
-void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data)
+static int usbout_sync_retire_desc(struct usbout *u, purb_t urb)
+{
+	unsigned char *cp = urb->transfer_buffer;
+	unsigned int f, i;
+
+	for (i = 0; i < SYNCFRAMES; i++, cp += 3) {
+		if (urb->iso_frame_desc[i].status) {
+			dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
+			continue;
+		}
+		if (urb->iso_frame_desc[i].actual_length < 3) {
+			dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u length %d\n", i, urb->iso_frame_desc[i].actual_length));
+			continue;
+		}
+		f = cp[0] | (cp[1] << 8) | (cp[2] << 16);
+		if (abs(f - u->freqn) > (u->freqn >> 3) || f > u->freqmax) {
+			printk(KERN_WARNING "usbout_sync_retire_desc: requested frequency %u (nominal %u) out of range!\n", f, u->freqn);
+			continue;
+		}
+		u->freqm = f;
+	}
+	return 0;
+}
+
+static void usbout_sync_completed(struct urb *urb)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
+	struct usbout *u = &as->usbout;
+	unsigned long flags;
+	unsigned int mask;
+	int suret = USB_ST_NOERROR;
+
+#if 0
+	printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
+#endif
+	if (urb == &u->surb[0].urb)
+		mask = FLG_SYNC0RUNNING;
+	else if (urb == &u->surb[1].urb)
+		mask = FLG_SYNC1RUNNING;
+	else {
+		mask = 0;
+		printk(KERN_ERR "usbout_sync_completed: panic: unknown URB\n");
+	}
+	spin_lock_irqsave(&as->lock, flags);
+	if (!usbout_sync_retire_desc(u, urb) &&
+	    u->flags & FLG_RUNNING &&
+	    !usbout_sync_prepare_desc(u, urb) && 
+	    (suret = usb_submit_urb(urb)) == USB_ST_NOERROR) {
+		u->flags |= mask;
+	} else {
+		u->flags &= ~(mask | FLG_RUNNING);
+		wake_up(&u->dma.wait);
+		dprintk((KERN_DEBUG "usbout_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
+}
+
+static int usbout_start(struct usb_audiodev *as)
+{
+	struct usb_device *dev = as->state->usbdev;
+	struct usbout *u = &as->usbout;
+	purb_t urb;
+	unsigned long flags;
+	unsigned int maxsze, bufsz;
+
+#if 0
+	printk(KERN_DEBUG "usbout_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
+	       dev->devnum, u->format, u->dma.format, u->dma.srate);
+#endif
+	/* allocate USB storage if not already done */
+	spin_lock_irqsave(&as->lock, flags);
+	if (!(u->flags & FLG_CONNECTED)) {
+		spin_unlock_irqrestore(&as->lock, flags);
+		return -EIO;
+	}
+	if (!(u->flags & FLG_RUNNING)) {
+		spin_unlock_irqrestore(&as->lock, flags);
+		u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
+		u->freqmax = u->freqn + (u->freqn >> 2);
+		u->phase = 0;
+		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
+		bufsz = DESCFRAMES * maxsze;
+		if (u->durb[0].urb.transfer_buffer)
+			kfree(u->durb[0].urb.transfer_buffer);
+		u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[0].urb.transfer_buffer_length = bufsz;
+		if (u->durb[1].urb.transfer_buffer)
+			kfree(u->durb[1].urb.transfer_buffer);
+		u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[1].urb.transfer_buffer_length = bufsz;
+		if (u->syncpipe) {
+			if (u->surb[0].urb.transfer_buffer)
+				kfree(u->surb[0].urb.transfer_buffer);
+			u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[1].urb.transfer_buffer)
+				kfree(u->surb[1].urb.transfer_buffer);
+			u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
+		}
+		if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer || 
+		    (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
+			return 0;
+		}
+		spin_lock_irqsave(&as->lock, flags);
+	}
+	if (u->dma.count <= 0 && !u->dma.mapped)
+		return 0;
+       	u->flags |= FLG_RUNNING;
+	if (!(u->flags & FLG_URB0RUNNING)) {
+		urb = &u->durb[0].urb;
+		urb->dev = dev;
+		urb->pipe = u->datapipe;
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->number_of_packets = DESCFRAMES;
+		urb->context = as;
+		urb->complete = usbout_completed;
+		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb))
+			u->flags |= FLG_URB0RUNNING;
+		else
+			u->flags &= ~FLG_RUNNING;
+	}
+	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
+		urb = &u->durb[1].urb;
+		urb->dev = dev;
+		urb->pipe = u->datapipe;
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->number_of_packets = DESCFRAMES;
+		urb->context = as;
+		urb->complete = usbout_completed;
+		if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb))
+			u->flags |= FLG_URB1RUNNING;
+		else
+			u->flags &= ~FLG_RUNNING;
+	}
+	if (u->syncpipe) {
+		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
+			urb = &u->surb[0].urb;
+			urb->dev = dev;
+			urb->pipe = u->syncpipe;
+			urb->transfer_flags = USB_ISO_ASAP;
+			urb->number_of_packets = SYNCFRAMES;
+			urb->context = as;
+			urb->complete = usbout_sync_completed;
+			/* stride: u->syncinterval */
+			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb))
+				u->flags |= FLG_SYNC0RUNNING;
+			else
+				u->flags &= ~FLG_RUNNING;
+		}
+		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
+			urb = &u->surb[1].urb;
+			urb->dev = dev;
+			urb->pipe = u->syncpipe;
+			urb->transfer_flags = USB_ISO_ASAP;
+			urb->number_of_packets = SYNCFRAMES;
+			urb->context = as;
+			urb->complete = usbout_sync_completed;
+			/* stride: u->syncinterval */
+			if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb))
+				u->flags |= FLG_SYNC1RUNNING;
+			else
+				u->flags &= ~FLG_RUNNING;
+		}
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate)
+{
+	unsigned int g = 0;
+
+	if (srate < afp->sratelo)
+		g += afp->sratelo - srate;
+	if (srate > afp->sratehi)
+		g += srate - afp->sratehi;
+	if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt))
+		g += 0x100000;
+	if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt))
+		g += 0x400000;
+	if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt))
+		g += 0x100000;
+	if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt))
+		g += 0x400000;
+	return g;
+}
+
+static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate)
+{
+	unsigned int i, g, gb = ~0;
+	int j = -1; /* default to failure */
+
+	/* find "best" format (according to format_goodness) */
+	for (i = 0; i < nr; i++) {
+		g = format_goodness(&afp[i], fmt, srate);
+		if (g >= gb) 
+			continue;
+		j = i;
+		gb = g;
+	}
+       	return j;
+}
+
+static int set_format_in(struct usb_audiodev *as)
+{
+	struct usb_device *dev = as->state->usbdev;
+	struct usb_config_descriptor *config = dev->actconfig;
+	struct usb_interface_descriptor *alts;
+	struct usb_interface *iface;
+	struct usbin *u = &as->usbin;
+	struct dmabuf *d = &u->dma;
+	struct audioformat *fmt;
+	unsigned int ep;
+	unsigned char data[3];
+	int fmtnr, ret;
+
+	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
+		return 0;
+	iface = &config->interface[u->interface];
+
+	fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate);
+	if (fmtnr < 0) {
+		printk(KERN_ERR "usbaudio: set_format_in(): failed to find desired format/speed combination.\n");
+		return -1;
+	}
+
+	fmt = as->fmtin + fmtnr;
+	alts = &iface->altsetting[fmt->altsetting];
+	u->format = fmt->format;
+	u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].bEndpointAddress & 0xf);
+	u->syncpipe = u->syncinterval = 0;
+	if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x08) {
+		if (alts->bNumEndpoints < 2 ||
+		    alts->endpoint[1].bmAttributes != 0x01 ||
+		    alts->endpoint[1].bSynchAddress != 0 ||
+		    alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress & 0x7f)) {
+			printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n",
+			       dev->devnum, u->interface, fmt->altsetting);
+			return -1;
+		}
+		u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf);
+		u->syncinterval = alts->endpoint[1].bRefresh;
+	}
+	if (d->srate < fmt->sratelo)
+		d->srate = fmt->sratelo;
+	if (d->srate > fmt->sratehi)
+		d->srate = fmt->sratehi;
+	dprintk((KERN_DEBUG "usb_audio: set_format_in: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting));
+	
+	if (usb_set_interface(dev, alts->bInterfaceNumber, fmt->altsetting) < 0) {
+		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
+		       dev->devnum, u->interface, fmt->altsetting);
+		return -1;
+	}
+	if (fmt->sratelo == fmt->sratehi)
+		return 0;
+	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
+	/* if endpoint has pitch control, enable it */
+	if (fmt->attributes & 0x02) {
+		data[0] = 1;
+		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+					   PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
+			printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
+			       ret, dev->devnum, u->interface, ep, d->srate);
+			return -1;
+		}
+	}
+	/* if endpoint has sampling rate control, set it */
+	if (fmt->attributes & 0x01) {
+		data[0] = d->srate;
+		data[1] = d->srate >> 8;
+		data[2] = d->srate >> 16;
+		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+			printk(KERN_ERR "usbaudio: failure (error %d) to set input sampling frequency device %d interface %u endpoint 0x%x to %u\n",
+			       ret, dev->devnum, u->interface, ep, d->srate);
+			return -1;
+		}
+		if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+			printk(KERN_ERR "usbaudio: failure (error %d) to get input sampling frequency device %d interface %u endpoint 0x%x\n",
+			       ret, dev->devnum, u->interface, ep);
+			return -1;
+		}
+		dprintk((KERN_DEBUG "usbaudio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n",
+		       dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)));
+		d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
+	}
+	return 0;
+}
+
+static int set_format_out(struct usb_audiodev *as)
+{
+	struct usb_device *dev = as->state->usbdev;
+	struct usb_config_descriptor *config = dev->actconfig;
+	struct usb_interface_descriptor *alts;
+	struct usb_interface *iface;	
+	struct usbout *u = &as->usbout;
+	struct dmabuf *d = &u->dma;
+	struct audioformat *fmt;
+	unsigned int ep;
+	unsigned char data[3];
+	int fmtnr, ret;
+
+	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
+		return 0;
+	iface = &config->interface[u->interface];
+
+	fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate);
+	if (fmtnr < 0) {
+		printk(KERN_ERR "usbaudio: set_format_out(): failed to find desired format/speed combination.\n");
+		return -1;
+	}
+
+	fmt = as->fmtout + fmtnr;
+	u->format = fmt->format;
+	alts = &iface->altsetting[fmt->altsetting];
+	u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].bEndpointAddress & 0xf);
+	u->syncpipe = u->syncinterval = 0;
+	if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x04) {
+#if 0
+		printk(KERN_DEBUG "bNumEndpoints 0x%02x endpoint[1].bmAttributes 0x%02x\n"
+		       KERN_DEBUG "endpoint[1].bSynchAddress 0x%02x endpoint[1].bEndpointAddress 0x%02x\n"
+		       KERN_DEBUG "endpoint[0].bSynchAddress 0x%02x\n", alts->bNumEndpoints,
+		       alts->endpoint[1].bmAttributes, alts->endpoint[1].bSynchAddress,
+		       alts->endpoint[1].bEndpointAddress, alts->endpoint[0].bSynchAddress);
+#endif
+		if (alts->bNumEndpoints < 2 ||
+		    alts->endpoint[1].bmAttributes != 0x01 ||
+		    alts->endpoint[1].bSynchAddress != 0 ||
+		    alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress | 0x80)) {
+			printk(KERN_ERR "usbaudio: device %d interface %d altsetting %d invalid synch pipe\n",
+			       dev->devnum, u->interface, fmt->altsetting);
+			return -1;
+		}
+		u->syncpipe = usb_rcvisocpipe(dev, alts->endpoint[1].bEndpointAddress & 0xf);
+		u->syncinterval = alts->endpoint[1].bRefresh;
+	}
+	if (d->srate < fmt->sratelo)
+		d->srate = fmt->sratelo;
+	if (d->srate > fmt->sratehi)
+		d->srate = fmt->sratehi;
+	
+	dprintk((KERN_DEBUG "usb_audio: set_format_out: usb_set_interface %u %u\n", alts->bInterfaceNumber, fmt->altsetting));
+
+	if (usb_set_interface(dev, u->interface, fmt->altsetting) < 0) {
+		printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
+		       dev->devnum, u->interface, fmt->altsetting);
+		return -1;
+	}
+	if (fmt->sratelo == fmt->sratehi)
+		return 0;
+	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
+	/* if endpoint has pitch control, enable it */
+	if (fmt->attributes & 0x02) {
+		data[0] = 1;
+		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+					   PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
+			printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
+			       ret, dev->devnum, u->interface, ep, d->srate);
+			return -1;
+		}
+	}
+	/* if endpoint has sampling rate control, set it */
+	if (fmt->attributes & 0x01) {
+		data[0] = d->srate;
+		data[1] = d->srate >> 8;
+		data[2] = d->srate >> 16;
+		if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+			printk(KERN_ERR "usbaudio: failure (error %d) to set output sampling frequency device %d interface %u endpoint 0x%x to %u\n",
+			       ret, dev->devnum, u->interface, ep, d->srate);
+			return -1;
+		}
+		if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
+					   SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
+			printk(KERN_ERR "usbaudio: failure (error %d) to get output sampling frequency device %d interface %u endpoint 0x%x\n",
+			       ret, dev->devnum, u->interface, ep);
+			return -1;
+		}
+		dprintk((KERN_DEBUG "usbaudio: set_format_out: device %d interface %d altsetting %d srate req: %u real %u\n",
+		       dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)));
+		d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
+	}
+	return 0;
+}
+
+static int set_format(struct usb_audiodev *s, unsigned int fmode, unsigned int fmt, unsigned int srate)
+{
+	int ret1 = 0, ret2 = 0;
+
+	if (!(fmode & (FMODE_READ|FMODE_WRITE)))
+		return -EINVAL;
+	if (fmode & FMODE_READ) {
+		usbin_stop(s);
+		s->usbin.dma.ready = 0;
+		if (fmt == AFMT_QUERY)
+			fmt = s->usbin.dma.format;
+		else
+			s->usbin.dma.format = fmt;
+		if (!srate)
+			srate = s->usbin.dma.srate;
+		else
+			s->usbin.dma.srate = srate;
+	}
+	if (fmode & FMODE_WRITE) {
+		usbout_stop(s);
+		s->usbout.dma.ready = 0;
+		if (fmt == AFMT_QUERY)
+			fmt = s->usbout.dma.format;
+		else
+			s->usbout.dma.format = fmt;
+		if (!srate)
+			srate = s->usbout.dma.srate;
+		else
+			s->usbout.dma.srate = srate;
+	}
+	if (fmode & FMODE_READ)
+		ret1 = set_format_in(s);
+	if (fmode & FMODE_WRITE)
+		ret2 = set_format_out(s);
+	return ret1 ? ret1 : ret2;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
+{
+	struct usb_device *dev = ms->state->usbdev;
+	unsigned char data[2];
+	struct mixerchannel *ch;
+	int v1, v2, v3;
+
+	if (mixch >= ms->numch)
+		return -1;
+	ch = &ms->ch[mixch];
+	v3 = ch->maxval - ch->minval;
+	v1 = value & 0xff;
+	v2 = (value >> 8) & 0xff;
+	if (v1 > 100)
+		v1 = 100;
+	if (v2 > 100)
+		v2 = 100;
+	if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+		v2 = v1;
+	ch->value = v1 | (v2 << 8);
+	v1 = (v1 * v3) / 100 + ch->minval;
+	v2 = (v2 * v3) / 100 + ch->minval;
+	switch (ch->selector) {
+	case 0:  /* mixer unit request */
+		data[0] = v1;
+		data[1] = v1 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+			goto err;
+		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+			return 0;
+		data[0] = v2;
+		data[1] = v2 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
+				    ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+			goto err;
+		return 0;
+
+		/* various feature unit controls */
+	case VOLUME_CONTROL:
+		data[0] = v1;
+		data[1] = v1 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+			goto err;
+		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+			return 0;
+		data[0] = v2;
+		data[1] = v2 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
+			goto err;
+		return 0;
+                
+	case BASS_CONTROL:
+	case MID_CONTROL:
+	case TREBLE_CONTROL:
+		data[0] = v1 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
+			goto err;
+		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+			return 0;
+		data[0] = v2 >> 8;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
+			goto err;
+		return 0;
+
+	default:
+		return -1;
+	}
+	return 0;
+
+ err:
+	printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
+		dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector);
+	return -1;
+}
+
+static int get_rec_src(struct usb_mixerdev *ms)
+{
+	struct usb_device *dev = ms->state->usbdev;
+	unsigned int mask = 0, retmask = 0;
+	unsigned int i, j;
+	unsigned char buf;
+	int err = 0;
+
+	for (i = 0; i < ms->numch; i++) {
+		if (!ms->ch[i].slctunitid || (mask & (1 << i)))
+			continue;
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+			err = -EIO;
+			printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
+			       dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
+			continue;
+		}
+		for (j = i; j < ms->numch; j++) {
+			if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
+				continue;
+			mask |= 1 << j;
+			if (buf == (ms->ch[j].slctunitid >> 8))
+				retmask |= 1 << ms->ch[j].osschannel;
+		}
+	}
+	if (err)
+		return -EIO;
+	return retmask;
+}
+
+static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
+{
+	struct usb_device *dev = ms->state->usbdev;
+	unsigned int mask = 0, smask, bmask;
+	unsigned int i, j;
+	unsigned char buf;
+	int err = 0;
+
+	for (i = 0; i < ms->numch; i++) {
+		if (!ms->ch[i].slctunitid || (mask & (1 << i)))
+			continue;
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+			err = -EIO;
+			printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n", 
+			       dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
+			continue;
+		}
+		/* first generate smask */
+		smask = bmask = 0;
+		for (j = i; j < ms->numch; j++) {
+			if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
+				continue;
+			smask |= 1 << ms->ch[j].osschannel;
+			if (buf == (ms->ch[j].slctunitid >> 8))
+				bmask |= 1 << ms->ch[j].osschannel;
+			mask |= 1 << j;
+		}
+		/* check for multiple set sources */
+		j = hweight32(srcmask & smask);
+		if (j == 0)
+			continue;
+		if (j > 1)
+			srcmask &= ~bmask;
+		for (j = i; j < ms->numch; j++) {
+			if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
+				continue;
+			if (!(srcmask & (1 << ms->ch[j].osschannel)))
+				continue;
+			buf = ms->ch[j].slctunitid >> 8;
+			if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, HZ) < 0) {
+				err = -EIO;
+				printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n", 
+				       dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff);
+				continue;
+			}
+		}
+	}
+	return err ? -EIO : 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * should be called with open_sem hold, so that no new processes
+ * look at the audio device to be destroyed
+ */
+
+static void release(struct usb_audio_state *s)
+{
+	struct usb_audiodev *as;
+	struct usb_mixerdev *ms;
+
+	s->count--;
+	if (s->count) {
+		up(&open_sem);
+		return;
+	}
+	up(&open_sem);
+	wake_up(&open_wait);
+	while (!list_empty(&s->audiolist)) {
+		as = list_entry(s->audiolist.next, struct usb_audiodev, list);
+		list_del(&as->list);
+		usbin_release(as);
+		usbout_release(as);
+		dmabuf_release(&as->usbin.dma);
+		dmabuf_release(&as->usbout.dma);
+		kfree(as);
+	}
+	while (!list_empty(&s->mixerlist)) {
+		ms = list_entry(s->mixerlist.next, struct usb_mixerdev, list);
+		list_del(&ms->list);
+		kfree(ms);
+	}
+	kfree(s);
+}
+
+extern inline int prog_dmabuf_in(struct usb_audiodev *as)
+{
+	usbin_stop(as);
+	return dmabuf_init(&as->usbin.dma);
+}
+
+extern inline int prog_dmabuf_out(struct usb_audiodev *as)
+{
+	usbout_stop(as);
+	return dmabuf_init(&as->usbout.dma);
+}
+
+/* --------------------------------------------------------------------- */
+
+static loff_t usb_audio_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct list_head *devs, *mdevs;
+	struct usb_mixerdev *ms;
+	struct usb_audio_state *s;
+
+	down(&open_sem);
+	for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) {
+		s = list_entry(devs, struct usb_audio_state, audiodev);
+		for (mdevs = s->mixerlist.next; mdevs != &s->mixerlist; mdevs = mdevs->next) {
+			ms = list_entry(mdevs, struct usb_mixerdev, list);
+			if (ms->dev_mixer == minor)
+				goto mixer_found;
+		}
+	}
+	up(&open_sem);
+	return -ENODEV;
+
+ mixer_found:
+	if (!s->usbdev) {
+		up(&open_sem);
+		return -EIO;
+	}
+	file->private_data = ms;
+	s->count++;
+
+	up(&open_sem);
+	return 0;
+}
+
+static int usb_audio_release_mixdev(struct inode *inode, struct file *file)
+{
+	struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
+	struct usb_audio_state *s = ms->state;
+
+	down(&open_sem);
+	release(s);
+	return 0;
+}
+
+static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
+	int i, j, val;
+
+	if (!ms->state->usbdev)
+		return -ENODEV;
+  
+	if (cmd == SOUND_MIXER_INFO) {
+		mixer_info info;
+		strncpy(info.id, "USB_AUDIO", sizeof(info.id));
+		strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
+		info.modify_counter = ms->modcnt;
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == SOUND_OLD_MIXER_INFO) {
+		_old_mixer_info info;
+		strncpy(info.id, "USB_AUDIO", sizeof(info.id));
+		strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == OSS_GETVERSION)
+		return put_user(SOUND_VERSION, (int *)arg);
+	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+		return -EINVAL;
+	if (_IOC_DIR(cmd) == _IOC_READ) {
+		switch (_IOC_NR(cmd)) {
+		case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+			val = get_rec_src(ms);
+			if (val < 0)
+				return val;
+			return put_user(val, (int *)arg);
+
+		case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
+			for (val = i = 0; i < ms->numch; i++)
+				val |= 1 << ms->ch[i].osschannel;
+			return put_user(val, (int *)arg);
+
+		case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
+			for (val = i = 0; i < ms->numch; i++)
+				if (ms->ch[i].slctunitid)
+					val |= 1 << ms->ch[i].osschannel;
+			return put_user(val, (int *)arg);
+
+		case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
+			for (val = i = 0; i < ms->numch; i++)
+				if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
+					val |= 1 << ms->ch[i].osschannel;
+			return put_user(val, (int *)arg);
+			
+		case SOUND_MIXER_CAPS:
+			return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
+
+		default:
+			i = _IOC_NR(cmd);
+			if (i >= SOUND_MIXER_NRDEVICES)
+				return -EINVAL;
+			for (j = 0; j < ms->numch; j++) {
+				if (ms->ch[j].osschannel == i) {
+					return put_user(ms->ch[j].value, (int *)arg);
+				}
+			}
+			return -EINVAL;
+		}
+	}
+	if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) 
+		return -EINVAL;
+	ms->modcnt++;
+	switch (_IOC_NR(cmd)) {
+	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
+		get_user_ret(val, (int *)arg, -EFAULT);
+		return set_rec_src(ms, val);
+
+	default:
+		i = _IOC_NR(cmd);
+		if (i >= SOUND_MIXER_NRDEVICES)
+			return -EINVAL;
+		for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++);
+		if (j >= ms->numch)
+			return -EINVAL;
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (wrmixer(ms, j, val))
+			return -EIO;
+		return put_user(ms->ch[j].value, (int *)arg);
+	}
+}
+
+static /*const*/ struct file_operations usb_mixer_fops = {
+	llseek:		usb_audio_llseek,
+	ioctl:		usb_audio_ioctl_mixdev,
+	open:		usb_audio_open_mixdev,
+	release:	usb_audio_release_mixdev,
+};
+
+/* --------------------------------------------------------------------- */
+
+static int drain_out(struct usb_audiodev *as, int nonblock)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
+	int count, tmo;
+	
+	if (as->usbout.dma.mapped || !as->usbout.dma.ready)
+		return 0;
+	usbout_start(as);
+	add_wait_queue(&as->usbout.dma.wait, &wait);
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		spin_lock_irqsave(&as->lock, flags);
+		count = as->usbout.dma.count;
+		spin_unlock_irqrestore(&as->lock, flags);
+		if (count <= 0)
+			break;
+		if (signal_pending(current))
+			break;
+		if (nonblock) {
+			remove_wait_queue(&as->usbout.dma.wait, &wait);
+			set_current_state(TASK_RUNNING);
+			return -EBUSY;
+		}
+		tmo = 3 * HZ * count / as->usbout.dma.srate;
+		tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);
+		if (!schedule_timeout(tmo + 1)) {
+			printk(KERN_DEBUG "usbaudio: dma timed out??\n");
+			break;
+		}
+	}
+	remove_wait_queue(&as->usbout.dma.wait, &wait);
+	set_current_state(TASK_RUNNING);
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static ssize_t usb_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t ret = 0;
+	unsigned long flags;
+	unsigned int ptr;
+	int cnt, err;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (as->usbin.dma.mapped)
+		return -ENXIO;
+	if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
+		return ret;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
+	add_wait_queue(&as->usbin.dma.wait, &wait);
+	while (count > 0) {
+		spin_lock_irqsave(&as->lock, flags);
+		ptr = as->usbin.dma.rdptr;
+		cnt = as->usbin.dma.count;
+		/* set task state early to avoid wakeup races */
+		if (cnt <= 0)
+			__set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&as->lock, flags);
+		if (cnt > count)
+			cnt = count;
+		if (cnt <= 0) {
+			if (usbin_start(as)) {
+				if (!ret)
+					ret = -ENODEV;
+				break;
+			}
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
+			continue;
+		}
+		if ((err = dmabuf_copyout_user(&as->usbin.dma, ptr, buffer, cnt))) {
+			if (!ret)
+				ret = err;
+			break;
+		}
+		ptr += cnt;
+		if (ptr >= as->usbin.dma.dmasize)
+			ptr -= as->usbin.dma.dmasize;
+		spin_lock_irqsave(&as->lock, flags);
+		as->usbin.dma.rdptr = ptr;
+		as->usbin.dma.count -= cnt;
+		spin_unlock_irqrestore(&as->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&as->usbin.dma.wait, &wait);
+	return ret;
+}
+
+static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t ret = 0;
+	unsigned long flags;
+	unsigned int ptr;
+	unsigned int start_thr;
+	int cnt, err;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+	if (as->usbout.dma.mapped)
+		return -ENXIO;
+	if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
+		return ret;
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+	start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
+	add_wait_queue(&as->usbout.dma.wait, &wait);
+	while (count > 0) {
+#if 0
+		printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%lx\n",
+		       count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize,
+		       as->usbout.flags, current->state);
+#endif
+		spin_lock_irqsave(&as->lock, flags);
+		if (as->usbout.dma.count < 0) {
+			as->usbout.dma.count = 0;
+			as->usbout.dma.rdptr = as->usbout.dma.wrptr;
+		}
+		ptr = as->usbout.dma.wrptr;
+		cnt = as->usbout.dma.dmasize - as->usbout.dma.count;
+		/* set task state early to avoid wakeup races */
+		if (cnt <= 0)
+			__set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&as->lock, flags);
+		if (cnt > count)
+			cnt = count;
+		if (cnt <= 0) {
+			if (usbout_start(as)) {
+				if (!ret)
+					ret = -ENODEV;
+				break;
+			}
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
+			continue;
+		}
+		if ((err = dmabuf_copyin_user(&as->usbout.dma, ptr, buffer, cnt))) {
+			if (!ret)
+				ret = err;
+			break;
+		}
+		ptr += cnt;
+		if (ptr >= as->usbout.dma.dmasize)
+			ptr -= as->usbout.dma.dmasize;
+		spin_lock_irqsave(&as->lock, flags);
+		as->usbout.dma.wrptr = ptr;
+		as->usbout.dma.count += cnt;
+		spin_unlock_irqrestore(&as->lock, flags);
+		count -= cnt;
+		buffer += cnt;
+		ret += cnt;
+		if (as->usbout.dma.count >= start_thr && usbout_start(as)) {
+			if (!ret)
+				ret = -ENODEV;
+			break;
+		}
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&as->usbout.dma.wait, &wait);
+	return ret;
+}
+
+/* Called without the kernel lock - fine */
+static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	unsigned long flags;
+	unsigned int mask = 0;
+
+	if (file->f_mode & FMODE_WRITE) {
+		if (!as->usbout.dma.ready)
+			prog_dmabuf_out(as);
+		poll_wait(file, &as->usbout.dma.wait, wait);
+	}
+	if (file->f_mode & FMODE_READ) {
+		if (!as->usbin.dma.ready)
+			prog_dmabuf_in(as);
+		poll_wait(file, &as->usbin.dma.wait, wait);
+	}
+	spin_lock_irqsave(&as->lock, flags);
+	if (file->f_mode & FMODE_READ) {
+		if (as->usbin.dma.count >= (signed)as->usbin.dma.fragsize)
+			mask |= POLLIN | POLLRDNORM;
+	}
+	if (file->f_mode & FMODE_WRITE) {
+		if (as->usbout.dma.mapped) {
+			if (as->usbout.dma.count >= (signed)as->usbout.dma.fragsize) 
+				mask |= POLLOUT | POLLWRNORM;
+		} else {
+			if ((signed)as->usbout.dma.dmasize >= as->usbout.dma.count + (signed)as->usbout.dma.fragsize)
+				mask |= POLLOUT | POLLWRNORM;
+		}
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
+	return mask;
+}
+
+static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	struct dmabuf *db;
+	int ret;
+
+	if (vma->vm_flags & VM_WRITE) {
+		if ((ret = prog_dmabuf_out(as)) != 0)
+			return ret;
+		db = &as->usbout.dma;
+	} else if (vma->vm_flags & VM_READ) {
+		if ((ret = prog_dmabuf_in(as)) != 0)
+			return ret;
+		db = &as->usbin.dma;
+	} else
+		return -EINVAL;
+
+	return dmabuf_mmap(db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	struct usb_audio_state *s = as->state;
+	unsigned long flags;
+	audio_buf_info abinfo;
+	count_info cinfo;
+	int val, val2, mapped, ret;
+
+	if (!s->usbdev)
+		return -EIO;
+	mapped = ((file->f_mode & FMODE_WRITE) && as->usbout.dma.mapped) ||
+		((file->f_mode & FMODE_READ) && as->usbin.dma.mapped);
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_SYNC:
+		if (file->f_mode & FMODE_WRITE)
+			return drain_out(as, 0/*file->f_flags & O_NONBLOCK*/);
+		return 0;
+
+	case SNDCTL_DSP_SETDUPLEX:
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | 
+				DSP_CAP_MMAP | DSP_CAP_BATCH, (int *)arg);
+
+	case SNDCTL_DSP_RESET:
+		if (file->f_mode & FMODE_WRITE) {
+			usbout_stop(as);
+			as->usbout.dma.rdptr = as->usbout.dma.wrptr = as->usbout.dma.count = as->usbout.dma.total_bytes = 0;
+		}
+		if (file->f_mode & FMODE_READ) {
+			usbin_stop(as);
+			as->usbin.dma.rdptr = as->usbin.dma.wrptr = as->usbin.dma.count = as->usbin.dma.total_bytes = 0;
+		}
+		return 0;
+
+	case SNDCTL_DSP_SPEED:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val >= 0) {
+			if (val < 4000)
+				val = 4000;
+			if (val > 100000)
+				val = 100000;
+			if (set_format(as, file->f_mode, AFMT_QUERY, val))
+				return -EIO;
+		}
+		return put_user((file->f_mode & FMODE_READ) ? as->usbin.dma.srate : as->usbout.dma.srate, (int *)arg);
+
+	case SNDCTL_DSP_STEREO:
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+		if (set_format(as, file->f_mode, val2 | AFMT_STEREO, 0))
+			return -EIO;
+		return 0;
+
+	case SNDCTL_DSP_CHANNELS:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 0) {
+			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+			if (val == 1)
+				val2 &= ~AFMT_STEREO;
+			else
+				val2 |= AFMT_STEREO;
+			if (set_format(as, file->f_mode, val2, 0))
+				return -EIO;
+		}
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
+
+	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+		return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
+				AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != AFMT_QUERY) {
+			if (hweight32(val) != 1)
+				return -EINVAL;
+			if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
+				     AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE)))
+				return -EINVAL;
+			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+			val |= val2 & AFMT_STEREO;
+			if (set_format(as, file->f_mode, val, 0))
+				return -EIO;
+		}
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+		return put_user(val2 & ~AFMT_STEREO, (int *)arg);
+
+	case SNDCTL_DSP_POST:
+		return 0;
+
+	case SNDCTL_DSP_GETTRIGGER:
+		val = 0;
+		if (file->f_mode & FMODE_READ && as->usbin.flags & FLG_RUNNING) 
+			val |= PCM_ENABLE_INPUT;
+		if (file->f_mode & FMODE_WRITE && as->usbout.flags & FLG_RUNNING) 
+			val |= PCM_ENABLE_OUTPUT;
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_SETTRIGGER:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (file->f_mode & FMODE_READ) {
+			if (val & PCM_ENABLE_INPUT) {
+				if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
+					return ret;
+				if (usbin_start(as))
+					return -ENODEV;
+			} else
+				usbin_stop(as);
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			if (val & PCM_ENABLE_OUTPUT) {
+				if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))
+					return ret;
+				if (usbout_start(as))
+					return -ENODEV;
+			} else
+				usbout_stop(as);
+		}
+		return 0;
+
+	case SNDCTL_DSP_GETOSPACE:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
+			return val;
+		spin_lock_irqsave(&as->lock, flags);
+		abinfo.fragsize = as->usbout.dma.fragsize;
+		abinfo.bytes = as->usbout.dma.dmasize - as->usbout.dma.count;
+		abinfo.fragstotal = as->usbout.dma.numfrag;
+		abinfo.fragments = abinfo.bytes >> as->usbout.dma.fragshift;      
+		spin_unlock_irqrestore(&as->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+	case SNDCTL_DSP_GETISPACE:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)
+			return val;
+		spin_lock_irqsave(&as->lock, flags);
+		abinfo.fragsize = as->usbin.dma.fragsize;
+		abinfo.bytes = as->usbin.dma.count;
+		abinfo.fragstotal = as->usbin.dma.numfrag;
+		abinfo.fragments = abinfo.bytes >> as->usbin.dma.fragshift;      
+		spin_unlock_irqrestore(&as->lock, flags);
+		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+		
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+
+	case SNDCTL_DSP_GETODELAY:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&as->lock, flags);
+		val = as->usbout.dma.count;
+		spin_unlock_irqrestore(&as->lock, flags);
+		return put_user(val, (int *)arg);
+
+	case SNDCTL_DSP_GETIPTR:
+		if (!(file->f_mode & FMODE_READ))
+			return -EINVAL;
+		spin_lock_irqsave(&as->lock, flags);
+		cinfo.bytes = as->usbin.dma.total_bytes;
+		cinfo.blocks = as->usbin.dma.count >> as->usbin.dma.fragshift;
+		cinfo.ptr = as->usbin.dma.wrptr;
+		if (as->usbin.dma.mapped)
+			as->usbin.dma.count &= as->usbin.dma.fragsize-1;
+		spin_unlock_irqrestore(&as->lock, flags);
+		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+	case SNDCTL_DSP_GETOPTR:
+		if (!(file->f_mode & FMODE_WRITE))
+			return -EINVAL;
+		spin_lock_irqsave(&as->lock, flags);
+		cinfo.bytes = as->usbout.dma.total_bytes;
+		cinfo.blocks = as->usbout.dma.count >> as->usbout.dma.fragshift;
+		cinfo.ptr = as->usbout.dma.rdptr;
+		if (as->usbout.dma.mapped)
+			as->usbout.dma.count &= as->usbout.dma.fragsize-1;
+		spin_unlock_irqrestore(&as->lock, flags);
+		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+       case SNDCTL_DSP_GETBLKSIZE:
+		if (file->f_mode & FMODE_WRITE) {
+			if ((val = prog_dmabuf_out(as)))
+				return val;
+			return put_user(as->usbout.dma.fragsize, (int *)arg);
+		}
+		if ((val = prog_dmabuf_in(as)))
+			return val;
+		return put_user(as->usbin.dma.fragsize, (int *)arg);
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (file->f_mode & FMODE_READ) {
+			as->usbin.dma.ossfragshift = val & 0xffff;
+			as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff;
+			if (as->usbin.dma.ossfragshift < 4)
+				as->usbin.dma.ossfragshift = 4;
+			if (as->usbin.dma.ossfragshift > 15)
+				as->usbin.dma.ossfragshift = 15;
+			if (as->usbin.dma.ossmaxfrags < 4)
+				as->usbin.dma.ossmaxfrags = 4;
+		}
+		if (file->f_mode & FMODE_WRITE) {
+			as->usbout.dma.ossfragshift = val & 0xffff;
+			as->usbout.dma.ossmaxfrags = (val >> 16) & 0xffff;
+			if (as->usbout.dma.ossfragshift < 4)
+				as->usbout.dma.ossfragshift = 4;
+			if (as->usbout.dma.ossfragshift > 15)
+				as->usbout.dma.ossfragshift = 15;
+			if (as->usbout.dma.ossmaxfrags < 4)
+				as->usbout.dma.ossmaxfrags = 4;
+		}
+		return 0;
+
+	case SNDCTL_DSP_SUBDIVIDE:
+		if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) ||
+		    (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision))
+			return -EINVAL;
+		get_user_ret(val, (int *)arg, -EFAULT);
+		if (val != 1 && val != 2 && val != 4)
+			return -EINVAL;
+		if (file->f_mode & FMODE_READ)
+			as->usbin.dma.subdivision = val;
+		if (file->f_mode & FMODE_WRITE)
+			as->usbout.dma.subdivision = val;
+		return 0;
+
+	case SOUND_PCM_READ_RATE:
+		return put_user((file->f_mode & FMODE_READ) ? as->usbin.dma.srate : as->usbout.dma.srate, (int *)arg);
+
+	case SOUND_PCM_READ_CHANNELS:
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
+
+	case SOUND_PCM_READ_BITS:
+		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+		return put_user(AFMT_IS16BIT(val2) ? 16 : 8, (int *)arg);
+
+	case SOUND_PCM_WRITE_FILTER:
+	case SNDCTL_DSP_SETSYNCRO:
+	case SOUND_PCM_READ_FILTER:
+		return -EINVAL;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static int usb_audio_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev);
+	DECLARE_WAITQUEUE(wait, current);
+	struct list_head *devs, *adevs;
+	struct usb_audiodev *as;
+	struct usb_audio_state *s;
+
+	for (;;) {
+		down(&open_sem);
+		for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) {
+			s = list_entry(devs, struct usb_audio_state, audiodev);
+			for (adevs = s->audiolist.next; adevs != &s->audiolist; adevs = adevs->next) {
+				as = list_entry(adevs, struct usb_audiodev, list);
+				if (!((as->dev_audio ^ minor) & ~0xf))
+					goto device_found;
+			}
+		}
+		up(&open_sem);
+		return -ENODEV;
+
+	device_found:
+		if (!s->usbdev) {
+			up(&open_sem);
+			return -EIO;
+		}
+		/* wait for device to become free */
+		if (!(as->open_mode & file->f_mode))
+			break;
+		if (file->f_flags & O_NONBLOCK) {
+			up(&open_sem);
+			return -EBUSY;
+		}
+		__set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&open_wait, &wait);
+		up(&open_sem);
+		schedule();
+		__set_current_state(TASK_RUNNING);
+		remove_wait_queue(&open_wait, &wait);
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+	}
+	if (file->f_mode & FMODE_READ)
+		as->usbin.dma.ossfragshift = as->usbin.dma.ossmaxfrags = as->usbin.dma.subdivision = 0;
+	if (file->f_mode & FMODE_WRITE)
+		as->usbout.dma.ossfragshift = as->usbout.dma.ossmaxfrags = as->usbout.dma.subdivision = 0;
+	if (set_format(as, file->f_mode, ((minor & 0xf) == SND_DEV_DSP16) ? AFMT_S16_LE : AFMT_U8 /* AFMT_ULAW */, 8000)) {
+		up(&open_sem);
+		return -EIO;
+	}
+	file->private_data = as;
+	as->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+	s->count++;
+	up(&open_sem);
+	return 0;
+}
+
+static int usb_audio_release(struct inode *inode, struct file *file)
+{
+	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
+	struct usb_audio_state *s = as->state;
+	struct usb_device *dev = s->usbdev;
+	struct usb_interface *iface;
+
+	if (file->f_mode & FMODE_WRITE)
+		drain_out(as, file->f_flags & O_NONBLOCK);
+	down(&open_sem);
+	if (file->f_mode & FMODE_WRITE) {
+		usbout_stop(as);
+		if (dev && as->usbout.interface >= 0) {
+			iface = &dev->actconfig->interface[as->usbout.interface];
+			usb_set_interface(dev, iface->altsetting->bInterfaceNumber, 0);
+		}
+		dmabuf_release(&as->usbout.dma);
+		usbout_release(as);
+	}
+	if (file->f_mode & FMODE_READ) {
+		usbin_stop(as);
+		if (dev && as->usbin.interface >= 0) {
+			iface = &dev->actconfig->interface[as->usbin.interface];
+			usb_set_interface(dev, iface->altsetting->bInterfaceNumber, 0);
+		}
+		dmabuf_release(&as->usbin.dma);
+		usbin_release(as);
+	}
+	as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+	release(s);
+	wake_up(&open_wait);
+	return 0;
+}
+
+static /*const*/ struct file_operations usb_audio_fops = {
+	llseek:		usb_audio_llseek,
+	read:		usb_audio_read,
+	write:		usb_audio_write,
+	poll:		usb_audio_poll,
+	ioctl:		usb_audio_ioctl,
+	mmap:		usb_audio_mmap,
+	open:		usb_audio_open,
+	release:	usb_audio_release,
+};
+
+/* --------------------------------------------------------------------- */
+
+static void * usb_audio_probe(struct usb_device *dev, unsigned int ifnum);
+static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver usb_audio_driver = {
+	"audio",
+	usb_audio_probe,
+	usb_audio_disconnect,
+	LIST_HEAD_INIT(usb_audio_driver.driver_list), 
+	NULL,
+	0
+};
+
+static void *find_descriptor(void *descstart, unsigned int desclen, void *after, 
+			     u8 dtype, int iface, int altsetting)
+{
+	u8 *p, *end, *next;
+	int ifc = -1, as = -1;
+
+	p = descstart;
+	end = p + desclen;
+	for (; p < end;) {
+		if (p[0] < 2)
+			return NULL;
+		next = p + p[0];
+		if (next > end)
+			return NULL;
+		if (p[1] == USB_DT_INTERFACE) {
+			/* minimum length of interface descriptor */
+			if (p[0] < 9)
+				return NULL;
+			ifc = p[2];
+			as = p[3];
+		}
+		if (p[1] == dtype && (!after || (void *)p > after) &&
+		    (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting == as)) {
+			return p;
+		}
+		p = next;
+	}
+	return NULL;
+}
+
+static void *find_csinterface_descriptor(void *descstart, unsigned int desclen, void *after, u8 dsubtype, int iface, int altsetting)
+{
+	unsigned char *p;
+
+	p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, altsetting);
+	while (p) {
+		if (p[0] >= 3 && p[2] == dsubtype)
+			return p;
+		p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, altsetting);
+	}
+	return NULL;
+}
+
+static void *find_audiocontrol_unit(void *descstart, unsigned int desclen, void *after, u8 unit, int iface)
+{
+	unsigned char *p;
+
+	p = find_descriptor(descstart, desclen, after, USB_DT_CS_INTERFACE, iface, -1);
+	while (p) {
+		if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit)
+			return p;
+		p = find_descriptor(descstart, desclen, p, USB_DT_CS_INTERFACE, iface, -1);
+	}
+	return NULL;
+}
+
+static void usb_audio_parsestreaming(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, int asifin, int asifout)
+{
+	struct usb_device *dev = s->usbdev;
+	struct usb_audiodev *as;
+	struct usb_config_descriptor *config = dev->actconfig;
+	struct usb_interface_descriptor *alts;
+	struct usb_interface *iface;
+	struct audioformat *fp;
+	unsigned char *fmt, *csep;
+	unsigned int i, j, k, format;
+
+	if (!(as = kmalloc(sizeof(struct usb_audiodev), GFP_KERNEL)))
+		return;
+	memset(as, 0, sizeof(struct usb_audiodev));
+	init_waitqueue_head(&as->usbin.dma.wait);
+	init_waitqueue_head(&as->usbout.dma.wait);
+	spin_lock_init(&as->lock);
+	as->state = s;
+	as->usbin.interface = asifin;
+	as->usbout.interface = asifout;
+	/* search for input formats */
+	if (asifin >= 0) {
+		as->usbin.flags = FLG_CONNECTED;
+		iface = &config->interface[asifin];
+		for (i = 0; i < iface->num_altsetting; i++) {
+			alts = &iface->altsetting[i];
+			if (alts->bInterfaceClass != USB_CLASS_AUDIO || alts->bInterfaceSubClass != 2)
+				continue;
+			if (alts->bNumEndpoints < 1) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			if ((alts->endpoint[0].bmAttributes & 0x03) != 0x01 ||
+			    !(alts->endpoint[0].bEndpointAddress & 0x80)) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous in\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifin, i);
+			if (!fmt) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
+			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i);
+			if (!fmt) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
+				       dev->devnum, asifin, i, fmt[4], fmt[5]);
+				continue;
+			}
+			csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifin, i);
+			if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", 
+				       dev->devnum, asifin, i);
+				continue;
+			}
+			if (as->numfmtin >= MAXFORMATS)
+				continue;
+			fp = &as->fmtin[as->numfmtin++];
+			if (fmt[5] == 2)
+				format &= (AFMT_U16_LE | AFMT_S16_LE);
+			else
+				format &= (AFMT_U8 | AFMT_S8);
+			if (fmt[4] == 2)
+				format |= AFMT_STEREO;
+			fp->format = format;
+			fp->altsetting = i;
+			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
+			for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
+				k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
+				if (k > fp->sratehi)
+					fp->sratehi = k;
+				if (k < fp->sratelo)
+					fp->sratelo = k;
+			}
+			fp->attributes = csep[3];
+			printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", 
+			       dev->devnum, asifin, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes);
+		}
+	}
+	/* search for output formats */
+	if (asifout >= 0) {
+		as->usbout.flags = FLG_CONNECTED;
+		iface = &config->interface[asifout];
+		for (i = 0; i < iface->num_altsetting; i++) {
+			alts = &iface->altsetting[i];
+			if (alts->bInterfaceClass != USB_CLASS_AUDIO || alts->bInterfaceSubClass != 2)
+				continue;
+			if (alts->bNumEndpoints < 1) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u does not have an endpoint\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			if ((alts->endpoint[0].bmAttributes & 0x03) != 0x01 ||
+			    (alts->endpoint[0].bEndpointAddress & 0x80)) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u first endpoint not isochronous out\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			fmt = find_csinterface_descriptor(buffer, buflen, NULL, AS_GENERAL, asifout, i);
+			if (!fmt) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			if (fmt[0] < 7 || fmt[6] != 0 || (fmt[5] != 1 && fmt[5] != 2)) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u format not supported\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
+			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifout, i);
+			if (!fmt) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			if (fmt[0] < 8+3*(fmt[7] ? fmt[7] : 2) || fmt[3] != 1) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not supported\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
+				       dev->devnum, asifout, i, fmt[4], fmt[5]);
+				continue;
+			}
+			csep = find_descriptor(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, asifout, i);
+			if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
+				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u no or invalid class specific endpoint descriptor\n", 
+				       dev->devnum, asifout, i);
+				continue;
+			}
+			if (as->numfmtout >= MAXFORMATS)
+				continue;
+			fp = &as->fmtout[as->numfmtout++];
+			if (fmt[5] == 2)
+				format &= (AFMT_U16_LE | AFMT_S16_LE);
+			else
+				format &= (AFMT_U8 | AFMT_S8);
+			if (fmt[4] == 2)
+				format |= AFMT_STEREO;
+			fp->format = format;
+			fp->altsetting = i;
+			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
+			for (j = fmt[7] ? (fmt[7]-1) : 1; j > 0; j--) {
+				k = fmt[8+3*j] | (fmt[9+3*j] << 8) | (fmt[10+3*j] << 16);
+				if (k > fp->sratehi)
+					fp->sratehi = k;
+				if (k < fp->sratelo)
+					fp->sratelo = k;
+			}
+			fp->attributes = csep[3];
+			printk(KERN_INFO "usbaudio: device %u interface %u altsetting %u: format 0x%08x sratelo %u sratehi %u attributes 0x%02x\n", 
+			       dev->devnum, asifout, i, fp->format, fp->sratelo, fp->sratehi, fp->attributes);
+		}
+	}
+	if (as->numfmtin == 0 && as->numfmtout == 0) {
+		kfree(as);
+		return;
+	}
+	if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
+		printk(KERN_ERR "usbaudio: cannot register dsp\n");
+		kfree(as);
+		return;
+	}
+	/* everything successful */
+	list_add_tail(&as->list, &s->audiolist);
+}
+
+struct consmixstate {
+	struct usb_audio_state *s;
+	unsigned char *buffer;
+	unsigned int buflen;
+	unsigned int ctrlif;
+	struct mixerchannel mixch[SOUND_MIXER_NRDEVICES];
+	unsigned int nrmixch;
+	unsigned int mixchmask;
+	unsigned long unitbitmap[32/sizeof(unsigned long)];
+	/* return values */
+	unsigned int nrchannels;
+	unsigned int termtype;
+	unsigned int chconfig;
+};
+
+static struct mixerchannel *getmixchannel(struct consmixstate *state, unsigned int nr)
+{
+	struct mixerchannel *c;
+
+	if (nr >= SOUND_MIXER_NRDEVICES) {
+		printk(KERN_ERR "usbaudio: invalid OSS mixer channel %u\n", nr);
+		return NULL;
+	}
+	if (!(state->mixchmask & (1 << nr))) {
+		printk(KERN_WARNING "usbaudio: OSS mixer channel %u already in use\n", nr);
+		return NULL;
+	}
+	c = &state->mixch[state->nrmixch++];
+	c->osschannel = nr;
+	state->mixchmask &= ~(1 << nr);
+	return c;
+}
+
+static unsigned int getvolchannel(struct consmixstate *state)
+{
+	unsigned int u;
+
+	if ((state->termtype & 0xff00) == 0x0000 && (state->mixchmask & SOUND_MASK_VOLUME))
+		return SOUND_MIXER_VOLUME;
+	if ((state->termtype & 0xff00) == 0x0100) {
+		if (state->mixchmask & SOUND_MASK_PCM)
+			return SOUND_MIXER_PCM;
+		if (state->mixchmask & SOUND_MASK_ALTPCM)
+			return SOUND_MIXER_ALTPCM;
+	}
+	if ((state->termtype & 0xff00) == 0x0200 && (state->mixchmask & SOUND_MASK_MIC))
+		return SOUND_MIXER_MIC;
+	if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
+		return SOUND_MIXER_SPEAKER;
+	if ((state->termtype & 0xff00) == 0x0500) {
+		if (state->mixchmask & SOUND_MASK_PHONEIN)
+			return SOUND_MIXER_PHONEIN;
+		if (state->mixchmask & SOUND_MASK_PHONEOUT)
+			return SOUND_MIXER_PHONEOUT;
+	}
+	if (state->termtype >= 0x710 && state->termtype <= 0x711 && (state->mixchmask & SOUND_MASK_RADIO))
+		return SOUND_MIXER_RADIO;
+	if (state->termtype >= 0x709 && state->termtype <= 0x70f && (state->mixchmask & SOUND_MASK_VIDEO))
+		return SOUND_MIXER_VIDEO;
+	u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 |
+				    SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3));
+	return u-1;
+}
+
+static void prepmixch(struct consmixstate *state)
+{
+	struct usb_device *dev = state->s->usbdev;
+	struct mixerchannel *ch;
+	unsigned char buf[2];
+	__s16 v1;
+	unsigned int v2, v3;
+
+	if (!state->nrmixch || state->nrmixch > SOUND_MIXER_NRDEVICES)
+		return;
+	ch = &state->mixch[state->nrmixch-1];
+	switch (ch->selector) {
+	case 0:  /* mixer unit request */
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+			goto err;
+		ch->minval = buf[0] | (buf[1] << 8);
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+			goto err;
+		ch->maxval = buf[0] | (buf[1] << 8);
+		v2 = ch->maxval - ch->minval;
+		if (!v2)
+			v2 = 1;
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+			goto err;
+		v1 = buf[0] | (buf[1] << 8);
+		v3 = v1 - ch->minval;
+		v3 = 100 * v3 / v2;
+		if (v3 > 100)
+			v3 = 100;
+		ch->value = v3;
+		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
+			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+					    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
+					    state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+			goto err;
+			v1 = buf[0] | (buf[1] << 8);
+			v3 = v1 - ch->minval;
+			v3 = 100 * v3 / v2;
+			if (v3 > 100)
+				v3 = 100;
+		}
+		ch->value |= v3 << 8;
+		break;
+
+		/* various feature unit controls */
+	case VOLUME_CONTROL:
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+			goto err;
+		ch->minval = buf[0] | (buf[1] << 8);
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+			goto err;
+		ch->maxval = buf[0] | (buf[1] << 8);
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+			goto err;
+		v1 = buf[0] | (buf[1] << 8);
+		v2 = ch->maxval - ch->minval;
+		v3 = v1 - ch->minval;
+		if (!v2)
+			v2 = 1;
+		v3 = 100 * v3 / v2;
+		if (v3 > 100)
+			v3 = 100;
+		ch->value = v3;
+		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
+			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
+				goto err;
+			v1 = buf[0] | (buf[1] << 8);
+			v3 = v1 - ch->minval;
+			v3 = 100 * v3 / v2;
+			if (v3 > 100)
+				v3 = 100;
+		}
+		ch->value |= v3 << 8;
+		break;
+		
+	case BASS_CONTROL:
+	case MID_CONTROL:
+	case TREBLE_CONTROL:
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+			goto err;
+		ch->minval = buf[0] << 8;
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+			goto err;
+		ch->maxval = buf[0] << 8;
+		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+			goto err;
+		v1 = buf[0] << 8;
+		v2 = ch->maxval - ch->minval;
+		v3 = v1 - ch->minval;
+		if (!v2)
+			v2 = 1;
+		v3 = 100 * v3 / v2;
+		if (v3 > 100)
+			v3 = 100;
+		ch->value = v3;
+		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
+			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
+				goto err;
+			v1 = buf[0] << 8;
+			v3 = v1 - ch->minval;
+			v3 = 100 * v3 / v2;
+			if (v3 > 100)
+				v3 = 100;
+		}
+		ch->value |= v3 << 8;
+		break;
+		
+	default:
+		goto err;
+	}
+	return;
+
+ err:
+	printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n", 
+	       dev->devnum, state->ctrlif, ch->unitid, ch->chnum, ch->selector);
+	if (state->nrmixch)
+		state->nrmixch--;
+}
+
+
+static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid);
+
+extern inline int checkmixbmap(unsigned char *bmap, unsigned char flg, unsigned int inidx, unsigned int numoch)
+{
+	unsigned int idx;
+
+	idx = inidx*numoch;
+	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
+		return 0;
+	if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
+		return 1;
+	idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT);
+	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
+		return 0;
+	return 1;
+}
+
+static void usb_audio_mixerunit(struct consmixstate *state, unsigned char *mixer)
+{
+	unsigned int nroutch = mixer[5+mixer[4]];
+	unsigned int chidx[SOUND_MIXER_NRDEVICES+1];
+	unsigned int termt[SOUND_MIXER_NRDEVICES];
+	unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0;
+	unsigned char *bmap = &mixer[9+mixer[4]];
+	unsigned int bmapsize;
+	struct mixerchannel *ch;
+	unsigned int i;
+
+	if (!mixer[4]) {
+		printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor\n", mixer[3]);
+		return;
+	}
+	if (mixer[4] > SOUND_MIXER_NRDEVICES) {
+		printk(KERN_ERR "usbaudio: mixer unit %u: too many input pins\n", mixer[3]);
+		return;
+	}
+	chidx[0] = 0;
+	for (i = 0; i < mixer[4]; i++) {
+		usb_audio_recurseunit(state, mixer[5+i]);
+		chidx[i+1] = chidx[i] + state->nrchannels;
+		termt[i] = state->termtype;
+	}
+	state->termtype = 0;
+	state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8);
+	bmapsize = (nroutch * chidx[mixer[4]] + 7) >> 3;
+	bmap += bmapsize - 1;
+	if (mixer[0] < 10+mixer[4]+bmapsize) {
+		printk(KERN_ERR "usbaudio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]);
+		return;
+	}
+	for (i = 0; i < mixer[4]; i++) {
+		state->termtype = termt[i];
+		if (chidx[i+1]-chidx[i] >= 2) {
+			flg |= MIXFLG_STEREOIN;
+			if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
+				ch = getmixchannel(state, getvolchannel(state));
+				if (ch) {
+					ch->unitid = mixer[3];
+					ch->selector = 0;
+					ch->chnum = chidx[i]+1;
+					ch->flags = flg;
+					prepmixch(state);
+				}
+				continue;
+			}
+		}
+		flg &= ~MIXFLG_STEREOIN;
+		if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
+			ch = getmixchannel(state, getvolchannel(state));
+			if (ch) {
+				ch->unitid = mixer[3];
+				ch->selector = 0;
+				ch->chnum = chidx[i]+1;
+				ch->flags = flg;
+				prepmixch(state);
+			}
+		}
+	}	
+	state->termtype = 0;
+}
+
+static struct mixerchannel *slctsrc_findunit(struct consmixstate *state, __u8 unitid)
+{
+	unsigned int i;
+	
+	for (i = 0; i < state->nrmixch; i++)
+		if (state->mixch[i].unitid == unitid)
+			return &state->mixch[i];
+	return NULL;
+}
+
+static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector)
+{
+	unsigned int chnum, i, mixch;
+	struct mixerchannel *mch;
+
+	if (!selector[4]) {
+		printk(KERN_ERR "usbaudio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]);
+		return;
+	}
+	mixch = state->nrmixch;
+	usb_audio_recurseunit(state, selector[5]);
+	if (state->nrmixch != mixch) {
+		mch = &state->mixch[state->nrmixch-1];
+		mch->slctunitid = selector[3] | (1 << 8);
+	} else if ((mch = slctsrc_findunit(state, selector[5]))) {
+		mch->slctunitid = selector[3] | (1 << 8);
+	} else {
+		printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel 1\n", selector[3]);
+	}
+	chnum = state->nrchannels;
+	for (i = 1; i < selector[4]; i++) {
+		mixch = state->nrmixch;
+		usb_audio_recurseunit(state, selector[5+i]);
+		if (chnum != state->nrchannels) {
+			printk(KERN_ERR "usbaudio: selector unit %u: input pins with varying channel numbers\n", selector[3]);
+			state->termtype = 0;
+			state->chconfig = 0;
+			state->nrchannels = 0;
+			return;
+		}
+		if (state->nrmixch != mixch) {
+			mch = &state->mixch[state->nrmixch-1];
+			mch->slctunitid = selector[3] | ((i + 1) << 8);
+		} else if ((mch = slctsrc_findunit(state, selector[5+i]))) {
+			mch->slctunitid = selector[3] | ((i + 1) << 8);
+		} else {
+			printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel %u\n", selector[3], i+1);
+		}
+	}
+	state->termtype = 0;
+	state->chconfig = 0;
+}
+
+/* in the future we might try to handle 3D etc. effect units */
+
+static void usb_audio_processingunit(struct consmixstate *state, unsigned char *proc)
+{
+	unsigned int i;
+
+	for (i = 0; i < proc[6]; i++)
+		usb_audio_recurseunit(state, proc[7+i]);
+	state->nrchannels = proc[7+proc[6]];
+	state->termtype = 0;
+	state->chconfig = proc[8+proc[6]] | (proc[9+proc[6]] << 8);
+}
+
+static void usb_audio_featureunit(struct consmixstate *state, unsigned char *ftr)
+{
+	struct mixerchannel *ch;
+	unsigned short chftr, mchftr;
+#if 0
+	struct usb_device *dev = state->s->usbdev;
+	unsigned char data[1];
+#endif
+
+	usb_audio_recurseunit(state, ftr[4]);
+	if (state->nrchannels == 0) {
+		printk(KERN_ERR "usbaudio: feature unit %u source has no channels\n", ftr[3]);
+		return;
+	}
+	if (state->nrchannels > 2)
+		printk(KERN_WARNING "usbaudio: feature unit %u: OSS mixer interface does not support more than 2 channels\n", ftr[3]);
+	if (state->nrchannels == 1 && ftr[0] == 7+ftr[5]) {
+		printk(KERN_WARNING "usbaudio: workaround for broken Philips Camera Microphone descriptor enabled\n");
+		mchftr = ftr[6];
+		chftr = 0;
+	} else {
+		if (ftr[0] < 7+ftr[5]*(1+state->nrchannels)) {
+			printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", ftr[3]);
+			return;
+		}
+		mchftr = ftr[6];
+		chftr = ftr[6+ftr[5]];
+		if (state->nrchannels > 1)
+			chftr &= ftr[6+2*ftr[5]];
+	}
+	/* volume control */
+	if (chftr & 2) {
+		ch = getmixchannel(state, getvolchannel(state));
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = VOLUME_CONTROL;
+			ch->chnum = 1;
+			ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
+			prepmixch(state);
+		}
+	} else if (mchftr & 2) {
+		ch = getmixchannel(state, getvolchannel(state));
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = VOLUME_CONTROL;
+			ch->chnum = 0;
+			ch->flags = 0;
+			prepmixch(state);
+		}
+	}
+	/* bass control */
+	if (chftr & 4) {
+		ch = getmixchannel(state, SOUND_MIXER_BASS);
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = BASS_CONTROL;
+			ch->chnum = 1;
+			ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
+			prepmixch(state);
+		}
+	} else if (mchftr & 4) {
+		ch = getmixchannel(state, SOUND_MIXER_BASS);
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = BASS_CONTROL;
+			ch->chnum = 0;
+			ch->flags = 0;
+			prepmixch(state);
+		}
+	}
+	/* treble control */
+	if (chftr & 16) {
+		ch = getmixchannel(state, SOUND_MIXER_TREBLE);
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = TREBLE_CONTROL;
+			ch->chnum = 1;
+			ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
+			prepmixch(state);
+		}
+	} else if (mchftr & 16) {
+		ch = getmixchannel(state, SOUND_MIXER_TREBLE);
+		if (ch) {
+			ch->unitid = ftr[3];
+			ch->selector = TREBLE_CONTROL;
+			ch->chnum = 0;
+			ch->flags = 0;
+			prepmixch(state);
+		}
+	}
+#if 0
+	/* if there are mute controls, unmute them */
+	/* does not seem to be necessary, and the Dallas chip does not seem to support the "all" channel (255) */
+	if ((chftr & 1) || (mchftr & 1)) {
+		printk(KERN_DEBUG "usbaudio: unmuting feature unit %u interface %u\n", ftr[3], state->ctrlif);
+		data[0] = 0;
+		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+				    (MUTE_CONTROL << 8) | 0xff, state->ctrlif | (ftr[3] << 8), data, 1, HZ) < 0)
+			printk(KERN_WARNING "usbaudio: failure to unmute feature unit %u interface %u\n", ftr[3], state->ctrlif);
+ 	}
+#endif
+}
+
+static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid)
+{
+	unsigned char *p1;
+	unsigned int i, j;
+
+	if (test_and_set_bit(unitid, &state->unitbitmap)) {
+		printk(KERN_INFO "usbaudio: mixer path revisits unit %d\n", unitid);
+		return;
+	}
+	p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif);
+	if (!p1) {
+		printk(KERN_ERR "usbaudio: unit %d not found!\n", unitid);
+		return;
+	}
+	state->nrchannels = 0;
+	state->termtype = 0;
+	state->chconfig = 0;
+	switch (p1[2]) {
+	case INPUT_TERMINAL:
+		if (p1[0] < 12) {
+			printk(KERN_ERR "usbaudio: unit %u: invalid INPUT_TERMINAL descriptor\n", unitid);
+			return;
+		}
+		state->nrchannels = p1[7];
+		state->termtype = p1[4] | (p1[5] << 8);
+		state->chconfig = p1[8] | (p1[9] << 8);
+		return;
+
+	case MIXER_UNIT:
+		if (p1[0] < 10 || p1[0] < 10+p1[4]) {
+			printk(KERN_ERR "usbaudio: unit %u: invalid MIXER_UNIT descriptor\n", unitid);
+			return;
+		}
+		usb_audio_mixerunit(state, p1);
+		return;
+
+	case SELECTOR_UNIT:
+		if (p1[0] < 6 || p1[0] < 6+p1[4]) {
+			printk(KERN_ERR "usbaudio: unit %u: invalid SELECTOR_UNIT descriptor\n", unitid);
+			return;
+		}
+		usb_audio_selectorunit(state, p1);
+		return;
+
+	case FEATURE_UNIT:
+		if (p1[0] < 7 || p1[0] < 7+p1[5]) {
+			printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid);
+			return;
+		}
+		usb_audio_featureunit(state, p1);
+		return;		
+
+	case PROCESSING_UNIT:
+		if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]] || p1[0] < 13+p1[6]+p1[11+p1[6]]+p1[13+p1[6]+p1[11+p1[6]]]) {
+			printk(KERN_ERR "usbaudio: unit %u: invalid PROCESSING_UNIT descriptor\n", unitid);
+			return;
+		}
+		usb_audio_processingunit(state, p1);
+		return;		
+
+	case EXTENSION_UNIT:
+		if (p1[0] < 13 || p1[0] < 13+p1[6] || p1[0] < 13+p1[6]+p1[11+p1[6]]) {
+			printk(KERN_ERR "usbaudio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid);
+			return;
+		}
+		for (j = i = 0; i < p1[6]; i++) {
+			usb_audio_recurseunit(state, p1[7+i]);
+			if (!i)
+				j = state->termtype;
+			else if (j != state->termtype)
+				j = 0;
+		}
+		state->nrchannels = p1[7+p1[6]];
+		state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8);
+		state->termtype = j;
+		return;
+
+	default:
+		printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]);
+		return;
+	}
+}
+
+static void usb_audio_constructmixer(struct usb_audio_state *s, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif, unsigned char *oterm)
+{
+	struct usb_mixerdev *ms;
+	struct consmixstate state;
+
+	memset(&state, 0, sizeof(state));
+	state.s = s;
+	state.nrmixch = 0;
+	state.mixchmask = ~0;
+	state.buffer = buffer;
+	state.buflen = buflen;
+	state.ctrlif = ctrlif;
+	set_bit(oterm[3], &state.unitbitmap);  /* mark terminal ID as visited */
+	printk(KERN_INFO "usbaudio: constructing mixer for Terminal %u type 0x%04x\n",
+	       oterm[3], oterm[4] | (oterm[5] << 8));
+	usb_audio_recurseunit(&state, oterm[7]);
+	if (!state.nrmixch) {
+		printk(KERN_INFO "usbaudio: no mixer controls found for Terminal %u\n", oterm[3]);
+		return;
+	}
+	if (!(ms = kmalloc(sizeof(struct usb_mixerdev)+state.nrmixch*sizeof(struct mixerchannel), GFP_KERNEL)))
+		return;
+	memset(ms, 0, sizeof(struct usb_mixerdev));
+	memcpy(&ms->ch, &state.mixch, state.nrmixch*sizeof(struct mixerchannel));
+	ms->state = s;
+	ms->iface = ctrlif;
+	ms->numch = state.nrmixch;
+	if ((ms->dev_mixer = register_sound_mixer(&usb_mixer_fops, -1)) < 0) {
+		printk(KERN_ERR "usbaudio: cannot register mixer\n");
+		kfree(ms);
+		return;
+	}
+	list_add_tail(&ms->list, &s->mixerlist);
+}
+
+static void *usb_audio_parsecontrol(struct usb_device *dev, unsigned char *buffer, unsigned int buflen, unsigned int ctrlif)
+{
+	struct usb_audio_state *s;
+	struct usb_config_descriptor *config = dev->actconfig;
+	struct usb_interface *iface;
+	unsigned char ifin[USB_MAXINTERFACES], ifout[USB_MAXINTERFACES];
+	unsigned char *p1;
+	unsigned int i, j, k, numifin = 0, numifout = 0;
+	
+	if (!(s = kmalloc(sizeof(struct usb_audio_state), GFP_KERNEL)))
+		return NULL;
+	memset(s, 0, sizeof(struct usb_audio_state));
+	INIT_LIST_HEAD(&s->audiolist);
+	INIT_LIST_HEAD(&s->mixerlist);
+	s->usbdev = dev;
+	s->count = 1;
+
+	/* find audiocontrol interface */
+	if (!(p1 = find_csinterface_descriptor(buffer, buflen, NULL, HEADER, ctrlif, -1))) {
+		printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u no HEADER found\n",
+		       dev->devnum, ctrlif);
+		goto ret;
+	}
+	if (p1[0] < 8 + p1[7]) {
+		printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u HEADER error\n",
+		       dev->devnum, ctrlif);
+		goto ret;
+	}
+	if (!p1[7])
+		printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has no AudioStreaming and MidiStreaming interfaces\n",
+		       dev->devnum, ctrlif);
+	for (i = 0; i < p1[7]; i++) {
+		j = p1[8+i];
+		if (j >= config->bNumInterfaces) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u does not exist\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		iface = &config->interface[j];
+		if (iface->altsetting[0].bInterfaceClass != USB_CLASS_AUDIO) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u is not an AudioClass interface\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		if (iface->altsetting[0].bInterfaceSubClass == 3) {
+			printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u interface %u MIDIStreaming not supported\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		if (iface->altsetting[0].bInterfaceSubClass != 2) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u invalid AudioClass subtype\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		if (iface->num_altsetting == 0) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has no working interface.\n", dev->devnum, ctrlif);
+			continue;
+		}
+		if (iface->num_altsetting == 1) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u has only 1 altsetting.\n", dev->devnum, ctrlif);
+			continue;
+		}
+		if (iface->altsetting[0].bNumEndpoints > 0) {
+			/* Check all endpoints; should they all have a bandwidth of 0 ? */
+			for (k = 0; k < iface->altsetting[0].bNumEndpoints; k++) {
+				if (iface->altsetting[0].endpoint[k].wMaxPacketSize > 0) {
+					printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u endpoint %d does not have 0 bandwidth at alt[0]\n", dev->devnum, ctrlif, k);
+					break;
+				}
+			}
+			if (k < iface->altsetting[0].bNumEndpoints)
+				continue;
+		}
+		if (iface->altsetting[1].bNumEndpoints < 1) {
+			printk(KERN_ERR "usbaudio: device %d audiocontrol interface %u interface %u has no endpoint\n",
+			       dev->devnum, ctrlif, j);
+			continue;
+		}
+		/* note: this requires the data endpoint to be ep0 and the optional sync
+		   ep to be ep1, which seems to be the case */
+		if (iface->altsetting[1].endpoint[0].bEndpointAddress & USB_DIR_IN) {
+			if (numifin < USB_MAXINTERFACES) {
+				ifin[numifin++] = j;
+				usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
+			}
+		} else {
+			if (numifout < USB_MAXINTERFACES) {
+				ifout[numifout++] = j;
+				usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
+			}
+		}
+	}
+	printk(KERN_INFO "usbaudio: device %d audiocontrol interface %u has %u input and %u output AudioStreaming interfaces\n",
+	       dev->devnum, ctrlif, numifin, numifout);
+	for (i = 0; i < numifin && i < numifout; i++)
+		usb_audio_parsestreaming(s, buffer, buflen, ifin[i], ifout[i]);
+	for (j = i; j < numifin; j++)
+		usb_audio_parsestreaming(s, buffer, buflen, ifin[i], -1);
+	for (j = i; j < numifout; j++)
+		usb_audio_parsestreaming(s, buffer, buflen, -1, ifout[i]);
+	/* now walk through all OUTPUT_TERMINAL descriptors to search for mixers */
+	p1 = find_csinterface_descriptor(buffer, buflen, NULL, OUTPUT_TERMINAL, ctrlif, -1);
+	while (p1) {
+		if (p1[0] >= 9)
+			usb_audio_constructmixer(s, buffer, buflen, ctrlif, p1);
+		p1 = find_csinterface_descriptor(buffer, buflen, p1, OUTPUT_TERMINAL, ctrlif, -1);
+	}
+
+ret:
+	if (list_empty(&s->audiolist) && list_empty(&s->mixerlist)) {
+		kfree(s);
+		return NULL;
+	}
+	/* everything successful */
+	down(&open_sem);
+	list_add_tail(&s->audiodev, &audiodevs);
+	up(&open_sem);
+	printk(KERN_DEBUG "usb_audio_parsecontrol: usb_audio_state at %p\n", s);
+	return s;
+}
+
+/* we only care for the currently active configuration */
+
+static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_config_descriptor *config = dev->actconfig;	
+	unsigned char *buffer;
+	unsigned char buf[8];
+	unsigned int i, buflen;
+	int ret;
+
+#if 0
+	printk(KERN_DEBUG "usbaudio: Probing if %i: IC %x, ISC %x\n", ifnum,
+	       config->interface[ifnum].altsetting[0].bInterfaceClass,
+	       config->interface[ifnum].altsetting[0].bInterfaceSubClass);
+#endif
+	if (config->interface[ifnum].altsetting[0].bInterfaceClass != USB_CLASS_AUDIO ||
+	    config->interface[ifnum].altsetting[0].bInterfaceSubClass != 1) {
+#if 0
+		printk(KERN_DEBUG "usbaudio: vendor id 0x%04x, product id 0x%04x contains no AudioControl interface\n",
+		       dev->descriptor.idVendor, dev->descriptor.idProduct);
+#endif
+		return NULL;
+	}
+	/*
+	 * audiocontrol interface found
+	 * find which configuration number is active
+	 */
+	for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+		if (dev->config+i == config)
+			goto configfound;
+	printk(KERN_ERR "usbaudio: cannot find active configuration number of device %d\n", dev->devnum);
+	return NULL;
+
+ configfound:
+	if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
+		printk(KERN_ERR "usbaudio: set_configuration failed (ConfigValue 0x%x)\n", config->bConfigurationValue);
+		return NULL;
+	}
+	ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8);
+	if (ret<0) {
+		printk(KERN_ERR "usbaudio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum);
+		return NULL;
+	}
+	if (buf[1] != USB_DT_CONFIG || buf[0] < 9) {
+		printk(KERN_ERR "usbaudio: invalid config descriptor %d of device %d\n", i, dev->devnum);
+		return NULL;
+	}
+	buflen = buf[2] | (buf[3] << 8);
+	if (!(buffer = kmalloc(buflen, GFP_KERNEL)))
+		return NULL;
+	ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buffer, buflen);
+	if (ret < 0) {
+		kfree(buffer);
+		printk(KERN_ERR "usbaudio: cannot get config descriptor %d of device %d\n", i, dev->devnum);
+		return NULL;
+	}
+	return usb_audio_parsecontrol(dev, buffer, buflen, ifnum);
+}
+
+
+/* a revoke facility would make things simpler */
+
+static void usb_audio_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_audio_state *s = (struct usb_audio_state *)ptr;
+	struct list_head *list;
+	struct usb_audiodev *as;
+	struct usb_mixerdev *ms;
+
+	/* we get called with -1 for every audiostreaming interface registered */
+	if (s == (struct usb_audio_state *)-1) {
+		dprintk((KERN_DEBUG "usb_audio_disconnect: called with -1\n"));
+		return;
+	}
+	if (!s->usbdev) {
+		dprintk((KERN_DEBUG "usb_audio_disconnect: already called for %p!\n", s));
+		return;
+	}
+	down(&open_sem);
+	list_del(&s->audiodev);
+	INIT_LIST_HEAD(&s->audiodev);
+	s->usbdev = NULL;
+	/* deregister all audio and mixer devices, so no new processes can open this device */
+	for(list = s->audiolist.next; list != &s->audiolist; list = list->next) {
+		as = list_entry(list, struct usb_audiodev, list);
+		usbin_disc(as);
+		usbout_disc(as);
+		wake_up(&as->usbin.dma.wait);
+		wake_up(&as->usbout.dma.wait);
+		if (as->dev_audio >= 0)
+			unregister_sound_dsp(as->dev_audio);
+		as->dev_audio = -1;
+	}
+	for(list = s->mixerlist.next; list != &s->mixerlist; list = list->next) {
+		ms = list_entry(list, struct usb_mixerdev, list);
+		if (ms->dev_mixer >= 0)
+			unregister_sound_mixer(ms->dev_mixer);
+		ms->dev_mixer = -1;
+	}
+	release(s);
+	wake_up(&open_wait);
+}
+
+int usb_audio_init(void)
+{
+	usb_register(&usb_audio_driver);
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
 {
+	return usb_audio_init();
 }
 
-void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data)
+void cleanup_module(void)
 {
+	usb_deregister(&usb_audio_driver);
 }
 
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/audio.h linux.18p8/drivers/usb/audio.h
--- linux.vanilla/drivers/usb/audio.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/audio.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,116 @@
+#define USB_DT_CS_DEVICE                0x21
+#define USB_DT_CS_CONFIG                0x22
+#define USB_DT_CS_STRING                0x23
+#define USB_DT_CS_INTERFACE             0x24
+#define USB_DT_CS_ENDPOINT              0x25
+
+#define CS_AUDIO_UNDEFINED		0x20
+#define CS_AUDIO_DEVICE			0x21
+#define CS_AUDIO_CONFIGURATION		0x22
+#define CS_AUDIO_STRING			0x23
+#define CS_AUDIO_INTERFACE		0x24
+#define CS_AUDIO_ENDPOINT		0x25
+
+#define HEADER				0x01
+#define INPUT_TERMINAL			0x02
+#define OUTPUT_TERMINAL			0x03
+#define MIXER_UNIT			0x04
+#define SELECTOR_UNIT			0x05
+#define FEATURE_UNIT			0x06
+#define PROCESSING_UNIT			0x07
+#define EXTENSION_UNIT			0x08
+
+#define AS_GENERAL			0x01
+#define FORMAT_TYPE			0x02
+#define FORMAT_SPECIFIC			0x03
+
+#define EP_GENERAL			0x01
+
+#define MAX_CHAN			9
+#define MAX_FREQ			16
+#define MAX_IFACE			8
+#define MAX_FORMAT			8
+#define MAX_ALT				32 	/* Sorry, we need quite a few for the Philips webcams */
+
+struct usb_audio_terminal
+{	
+	u8	flags;
+	u8	assoc;
+	u16	type;			/* Mic etc */
+	u8	channels;
+	u8	source;
+	u16	chancfg;
+};
+
+struct usb_audio_format
+{
+	u8	type;
+	u8	channels;
+	u8	num_freq;
+	u8	sfz;
+	u8	bits;
+	u16	freq[MAX_FREQ];
+};
+
+struct usb_audio_interface
+{
+	u8	terminal;
+	u8	delay;
+	u16	num_formats;
+	u16	format_type;
+	u8	flags;
+	u8	idleconf;	/* Idle config */
+#define AU_IFACE_FOUND	1
+	struct  usb_audio_format format[MAX_FORMAT];
+};
+
+struct usb_audio_device
+{
+	struct list_head list;
+	u8	mixer;
+	u8	selector;
+	void	*irq_handle;
+	u8	num_channels;
+	u8	num_dsp_iface;
+	u8	channel_map[MAX_CHAN];
+	struct usb_audio_terminal terminal[MAX_CHAN];
+	struct usb_audio_interface interface[MAX_IFACE][MAX_ALT];
+};
+
+
+
+/* Audio Class specific Request Codes */
+
+#define SET_CUR    0x01
+#define GET_CUR    0x81
+#define SET_MIN    0x02
+#define GET_MIN    0x82
+#define SET_MAX    0x03
+#define GET_MAX    0x83
+#define SET_RES    0x04
+#define GET_RES    0x84
+#define SET_MEM    0x05
+#define GET_MEM    0x85
+#define GET_STAT   0xff
+
+/* Terminal Control Selectors */
+
+#define COPY_PROTECT_CONTROL       0x01
+
+/* Feature Unit Control Selectors */
+
+#define MUTE_CONTROL               0x01
+#define VOLUME_CONTROL             0x02
+#define BASS_CONTROL               0x03
+#define MID_CONTROL                0x04
+#define TREBLE_CONTROL             0x05
+#define GRAPHIC_EQUALIZER_CONTROL  0x06
+#define AUTOMATIC_GAIN_CONTROL     0x07
+#define DELAY_CONTROL              0x08
+#define BASS_BOOST_CONTROL         0x09
+#define LOUDNESS_CONTROL           0x0a
+
+/* Endpoint Control Selectors */
+
+#define SAMPLING_FREQ_CONTROL      0x01
+#define PITCH_CONTROL              0x02
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/bluetooth.c linux.18p8/drivers/usb/bluetooth.c
--- linux.vanilla/drivers/usb/bluetooth.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/bluetooth.c	Tue Sep 12 12:52:02 2000
@@ -0,0 +1,1234 @@
+/*
+ * bluetooth.c   Version 0.5
+ *
+ * Copyright (c) 2000 Greg Kroah-Hartman	<greg@kroah.com>
+ * Copyright (c) 2000 Mark Douglas Corner	<mcorner@umich.edu>
+ *
+ * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
+ *
+ * (08/06/2000) Version 0.5 gkh
+ *	Fixed problem of not resubmitting the bulk read urb if there is
+ *	an error in the callback.  Ericsson devices seem to need this.
+ *
+ * (07/11/2000) Version 0.4 gkh
+ *	Fixed bug in disconnect for when we call tty_hangup
+ *	Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not
+ *	getting attached to the control urb properly.
+ *	Fixed bug in bluetooth_write where we pay attention to the result
+ *	of bluetooth_ctrl_msg.
+ *
+ * (08/03/2000) Version 0.3 gkh mdc
+ *	Merged in Mark's changes to make the driver play nice with the Axis
+ *	stack.
+ *	Made the write bulk use an urb pool to enable larger transfers with
+ *	fewer calls to the driver.
+ *	Fixed off by one bug in acl pkt receive
+ *	Made packet counters specific to each bluetooth device 
+ *	Added checks for zero length callbacks
+ *	Added buffers for int and bulk packets.  Had to do this otherwise 
+ *	packet types could intermingle.
+ *	Made a control urb pool for the control messages.
+ *
+ * (07/11/2000) Version 0.2 gkh
+ *	Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe 
+ *	function.
+ *
+ * (07/09/2000) Version 0.1 gkh
+ *	Initial release. Has support for sending ACL data (which is really just
+ *	a HCI frame.) Raw HCI commands and HCI events are not supported.
+ *	A ioctl will probably be needed for the HCI commands and events in the
+ *	future. All isoch endpoints are ignored at this time also.
+ *	This driver should work for all currently shipping USB Bluetooth 
+ *	devices at this time :)
+ * 
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/devfs_fs_kernel.h>
+
+#define DEBUG
+#include <linux/usb.h>
+
+/* Module information */
+MODULE_AUTHOR("Greg Kroah-Hartman, Mark Douglas Corner");
+MODULE_DESCRIPTION("USB Bluetooth driver");
+
+/* define this if you have hardware that is not good */
+/*#define	BTBUGGYHARDWARE */
+
+/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
+#define WIRELESS_CLASS_CODE			0xe0
+#define RF_SUBCLASS_CODE			0x01
+#define BLUETOOTH_PROGRAMMING_PROTOCOL_CODE	0x01
+
+
+#define BLUETOOTH_TTY_MAJOR	240	/* Prototype number for now */
+#define BLUETOOTH_TTY_MINORS	8
+
+#define USB_BLUETOOTH_MAGIC	0x6d02	/* magic number for bluetooth struct */
+
+#define BLUETOOTH_CONTROL_REQUEST_TYPE	0x20
+
+/* Bluetooth packet types */
+#define CMD_PKT			0x01
+#define ACL_PKT			0x02
+#define SCO_PKT			0x03
+#define EVENT_PKT		0x04
+#define ERROR_PKT		0x05
+#define NEG_PKT			0x06
+
+/* Message sizes */
+#define MAX_EVENT_SIZE		0xFF
+#define EVENT_HDR_SIZE		3	/* 2 for the header + 1 for the type indicator */
+#define EVENT_BUFFER_SIZE	(MAX_EVENT_SIZE + EVENT_HDR_SIZE)
+
+#define MAX_ACL_SIZE		0xFFFF
+#define ACL_HDR_SIZE		5	/* 4 for the header + 1 for the type indicator */
+#define ACL_BUFFER_SIZE		(MAX_ACL_SIZE + ACL_HDR_SIZE)
+
+/* parity check flag */
+#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+#define CHAR2INT16(c1,c0)	(((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff))
+#define MIN(a,b)		(((a)<(b))?(a):(b))
+
+#define NUM_BULK_URBS		24
+#define NUM_CONTROL_URBS	16
+
+struct usb_bluetooth {
+	int			magic;
+	struct usb_device *	dev;
+	struct tty_driver *	tty_driver;	/* the tty_driver for this device */
+	struct tty_struct *	tty;		/* the coresponding tty for this port */
+
+	unsigned char		minor;		/* the starting minor number for this device */
+	char			active;		/* someone has this device open */
+	int			throttle;	/* throttled by tty layer */
+	
+	__u8			control_out_bInterfaceNum;
+	struct urb *		control_urb_pool[NUM_CONTROL_URBS];
+	devrequest		dr[NUM_CONTROL_URBS];
+
+	unsigned char *		interrupt_in_buffer;
+	struct urb *		interrupt_in_urb;
+
+	unsigned char *		bulk_in_buffer;
+	struct urb *		read_urb;
+
+	int			bulk_out_size;
+	struct urb *		write_urb_pool[NUM_BULK_URBS];
+	__u8			bulk_out_endpointAddress;
+
+	wait_queue_head_t	write_wait;
+
+	struct tq_struct	tqueue;		/* task queue for line discipline waking up */
+	
+	unsigned int		int_packet_pos;
+	unsigned char		int_buffer[EVENT_BUFFER_SIZE];
+	unsigned int		bulk_packet_pos;
+	unsigned char		bulk_buffer[ACL_BUFFER_SIZE];	/* 64k preallocated, fix? */
+};
+
+
+/* local function prototypes */
+static int  bluetooth_open		(struct tty_struct *tty, struct file *filp);
+static void bluetooth_close		(struct tty_struct *tty, struct file *filp);
+static int  bluetooth_write		(struct tty_struct *tty, int from_user, const unsigned char *buf, int count);
+static int  bluetooth_write_room	(struct tty_struct *tty);
+static int  bluetooth_chars_in_buffer	(struct tty_struct *tty);
+static void bluetooth_throttle		(struct tty_struct *tty);
+static void bluetooth_unthrottle	(struct tty_struct *tty);
+static int  bluetooth_ioctl		(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
+static void bluetooth_set_termios	(struct tty_struct *tty, struct termios *old);
+
+static void bluetooth_int_callback		(struct urb *urb);
+static void bluetooth_ctrl_callback		(struct urb *urb);
+static void bluetooth_read_bulk_callback	(struct urb *urb);
+static void bluetooth_write_bulk_callback	(struct urb *urb);
+
+static void * usb_bluetooth_probe	(struct usb_device *dev, unsigned int ifnum);
+static void usb_bluetooth_disconnect	(struct usb_device *dev, void *ptr);
+
+
+static struct usb_driver usb_bluetooth_driver = {
+	name:		"bluetooth",
+	probe:		usb_bluetooth_probe,
+	disconnect:	usb_bluetooth_disconnect,
+};
+
+static int			bluetooth_refcount;
+static struct tty_driver	bluetooth_tty_driver;
+static struct tty_struct *	bluetooth_tty[BLUETOOTH_TTY_MINORS];
+static struct termios *		bluetooth_termios[BLUETOOTH_TTY_MINORS];
+static struct termios *		bluetooth_termios_locked[BLUETOOTH_TTY_MINORS];
+static struct usb_bluetooth	*bluetooth_table[BLUETOOTH_TTY_MINORS] = {NULL, };
+
+
+
+static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function)
+{
+	if (!bluetooth) {
+		dbg("%s - bluetooth == NULL", function);
+		return -1;
+	}
+	if (bluetooth->magic != USB_BLUETOOTH_MAGIC) {
+		dbg("%s - bad magic number for bluetooth", function);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function)
+{
+	if (!bluetooth || 
+	    bluetooth_paranoia_check (bluetooth, function)) { 
+		/* then say that we dont have a valid usb_bluetooth thing, which will
+		 * end up generating -ENODEV return values */
+		return NULL;
+	}
+
+	return bluetooth;
+}
+
+
+static inline struct usb_bluetooth *get_bluetooth_by_minor (int minor)
+{
+	return bluetooth_table[minor];
+}
+
+
+static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, void *buf, int len)
+{
+	struct urb *urb = NULL;
+	devrequest *dr = NULL;
+	int i;
+	int status;
+
+	dbg (__FUNCTION__);
+
+	/* try to find a free urb in our list */
+	for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+		if (bluetooth->control_urb_pool[i]->status != -EINPROGRESS) {
+			urb = bluetooth->control_urb_pool[i];
+			dr = &bluetooth->dr[i];
+			break;
+		}
+	}
+	if (urb == NULL) {
+		dbg (__FUNCTION__ " - no free urbs");
+		return -ENOMEM;
+	}
+
+	/* free up the last buffer that this urb used */
+	if (urb->transfer_buffer != NULL) {
+		kfree(urb->transfer_buffer);
+		urb->transfer_buffer = NULL;
+	}
+
+	dr->requesttype = BLUETOOTH_CONTROL_REQUEST_TYPE;
+	dr->request = request;
+	dr->value = cpu_to_le16p(&value);
+	dr->index = cpu_to_le16p(&bluetooth->control_out_bInterfaceNum);
+	dr->length = cpu_to_le16p(&len);
+	
+	FILL_CONTROL_URB (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
+			  (unsigned char*)dr, buf, len, bluetooth_ctrl_callback, bluetooth);
+
+	/* send it down the pipe */
+	status = usb_submit_urb(urb);
+	if (status)
+		dbg(__FUNCTION__ " - usb_submit_urb(control) failed with status = %d", status);
+	
+	return 0;
+}
+
+
+
+
+
+/*****************************************************************************
+ * Driver tty interface functions
+ *****************************************************************************/
+static int bluetooth_open (struct tty_struct *tty, struct file * filp)
+{
+	struct usb_bluetooth *bluetooth;
+	int result;
+
+	dbg(__FUNCTION__);
+
+	/* initialize the pointer incase something fails */
+	tty->driver_data = NULL;
+
+	/* get the bluetooth object associated with this tty pointer */
+	bluetooth = get_bluetooth_by_minor (MINOR(tty->device));
+
+	if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) {
+		return -ENODEV;
+	}
+
+	if (bluetooth->active) {
+		dbg (__FUNCTION__ " - device already open");
+		return -EINVAL;
+	}
+
+	/* set up our structure making the tty driver remember our object, and us it */
+	tty->driver_data = bluetooth;
+	bluetooth->tty = tty;
+
+	bluetooth->active = 1;
+
+	/* Reset the packet position counters */
+	bluetooth->int_packet_pos = 0;
+	bluetooth->bulk_packet_pos = 0;
+
+#ifndef BTBUGGYHARDWARE
+	/* Start reading from the device */
+	result = usb_submit_urb(bluetooth->read_urb);
+	if (result)
+		dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed with status %d", result);
+#endif
+	result = usb_submit_urb(bluetooth->interrupt_in_urb);
+	if (result)
+		dbg(__FUNCTION__ " - usb_submit_urb(interrupt in) failed with status %d", result);
+
+	return 0;
+}
+
+
+static void bluetooth_close (struct tty_struct *tty, struct file * filp)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+	int i;
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not opened");
+		return;
+	}
+
+	/* shutdown any bulk reads and writes that might be going on */
+	for (i = 0; i < NUM_BULK_URBS; ++i)
+		usb_unlink_urb (bluetooth->write_urb_pool[i]);
+	usb_unlink_urb (bluetooth->read_urb);
+
+	bluetooth->active = 0;
+}
+
+
+static int bluetooth_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+	struct urb *urb = NULL;
+	unsigned char *new_buffer;
+	const unsigned char *current_position;
+	int status;
+	int bytes_sent;
+	int buffer_size;
+	int i;
+
+	if (!bluetooth) {
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__ " - %d byte(s)", count);
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not opened");
+		return -EINVAL;
+	}
+
+	if (count == 0) {
+		dbg(__FUNCTION__ " - write request of 0 bytes");
+		return 0;
+	}
+	if (count == 1) {
+		dbg(__FUNCTION__ " - write request only included type %d", buf[0]);
+		return 1;
+	}
+
+#ifdef DEBUG
+	printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
+	for (i = 0; i < count; ++i) {
+		printk ("%.2x ", buf[i]);
+	}
+	printk ("\n");
+#endif
+
+	switch (*buf) {
+		/* First byte indicates the type of packet */
+		case CMD_PKT:
+			/* dbg(__FUNCTION__ "- Send cmd_pkt len:%d", count);*/
+
+			if (in_interrupt()){
+				printk("cmd_pkt from interrupt!\n");
+				return count;
+			}
+
+			new_buffer = kmalloc (count-1, GFP_KERNEL);
+
+			if (!new_buffer) {
+				err (__FUNCTION__ "- out of memory.");
+				return -ENOMEM;
+			}
+
+			if (from_user)
+				copy_from_user (new_buffer, buf+1, count-1);
+			else
+				memcpy (new_buffer, buf+1, count-1);
+
+			if (bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, new_buffer, count-1) != 0) {
+				kfree (new_buffer);
+				return 0;
+			}
+
+			/* need to free new_buffer somehow... FIXME */
+			return count;
+
+		case ACL_PKT:
+			current_position = buf;
+			++current_position;
+			--count;
+			bytes_sent = 0;
+
+			while (count > 0) {
+				urb = NULL;
+
+				/* try to find a free urb in our list */
+				for (i = 0; i < NUM_BULK_URBS; ++i) {
+					if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
+						urb = bluetooth->write_urb_pool[i];
+						break;
+					}
+				}
+				if (urb == NULL) {
+					dbg (__FUNCTION__ " - no free urbs");
+					return bytes_sent;
+				}
+				
+				/* free up the last buffer that this urb used */
+				if (urb->transfer_buffer != NULL) {
+					kfree(urb->transfer_buffer);
+					urb->transfer_buffer = NULL;
+				}
+
+				buffer_size = MIN (count, bluetooth->bulk_out_size);
+				
+				new_buffer = kmalloc (buffer_size, GFP_KERNEL);
+				if (new_buffer == NULL) {
+					err(__FUNCTION__" no more kernel memory...");
+					return bytes_sent;
+				}
+
+				if (from_user)
+					copy_from_user(new_buffer, current_position, buffer_size);
+				else
+					memcpy (new_buffer, current_position, buffer_size);
+
+				/* build up our urb */
+				FILL_BULK_URB (urb, bluetooth->dev, usb_sndbulkpipe(bluetooth->dev, bluetooth->bulk_out_endpointAddress),
+						new_buffer, buffer_size, bluetooth_write_bulk_callback, bluetooth);
+				urb->transfer_flags |= USB_QUEUE_BULK;
+
+				/* send it down the pipe */
+				status = usb_submit_urb(urb);
+				if (status)
+					dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+#ifdef BTBUGGYHARDWARE
+				/* A workaround for the stalled data bug */
+				/* May or may not be needed...*/
+				if (count != 0) {
+					udelay(500);
+				}
+#endif
+				current_position += buffer_size;
+				bytes_sent += buffer_size;
+				count -= buffer_size;
+			}
+
+			return bytes_sent + 1;
+		
+		default :
+			dbg(__FUNCTION__" - unsupported (at this time) write type");
+	}
+
+	return 0;
+} 
+
+
+static int bluetooth_write_room (struct tty_struct *tty) 
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+	int room = 0;
+	int i;
+
+	if (!bluetooth) {
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not open");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < NUM_BULK_URBS; ++i) {
+		if (bluetooth->write_urb_pool[i]->status != -EINPROGRESS) {
+			room += bluetooth->bulk_out_size;
+		}
+	}
+
+	dbg(__FUNCTION__ " - returns %d", room);
+	return room;
+}
+
+
+static int bluetooth_chars_in_buffer (struct tty_struct *tty) 
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+	int chars = 0;
+	int i;
+
+	if (!bluetooth) {
+		return -ENODEV;
+	}
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not open");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < NUM_BULK_URBS; ++i) {
+		if (bluetooth->write_urb_pool[i]->status == -EINPROGRESS) {
+			chars += bluetooth->write_urb_pool[i]->transfer_buffer_length;
+		}
+	}
+
+	dbg (__FUNCTION__ " - returns %d", chars);
+	return chars;
+}
+
+
+static void bluetooth_throttle (struct tty_struct * tty)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+	
+	dbg(__FUNCTION__ " unsupported (at this time)");
+
+	return;
+}
+
+
+static void bluetooth_unthrottle (struct tty_struct * tty)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+
+	dbg(__FUNCTION__ " unsupported (at this time)");
+}
+
+
+static int bluetooth_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__ " - cmd 0x%.4x", cmd);
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not open");
+		return -ENODEV;
+	}
+
+	/* FIXME!!! */
+	return -ENOIOCTLCMD;
+}
+
+
+static void bluetooth_set_termios (struct tty_struct *tty, struct termios * old)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+
+	/* FIXME!!! */
+
+	return;
+}
+
+
+#ifdef BTBUGGYHARDWARE
+void btusb_enable_bulk_read(struct tty_struct *tty){
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+
+	if (bluetooth->read_urb)
+		if (usb_submit_urb(bluetooth->read_urb))
+			dbg (__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+}
+
+void btusb_disable_bulk_read(struct tty_struct *tty){
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth->active) {
+		dbg (__FUNCTION__ " - device not open");
+		return;
+	}
+
+	if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length))
+		usb_unlink_urb(bluetooth->read_urb);
+}
+#endif
+
+
+/*****************************************************************************
+ * urb callback functions
+ *****************************************************************************/
+
+
+static void bluetooth_int_callback (struct urb *urb)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+	unsigned char *data = urb->transfer_buffer;
+	unsigned int i;
+	unsigned int count = urb->actual_length;
+	unsigned int packet_size;
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero int status received: %d", urb->status);
+		return;
+	}
+
+	if (!count) {
+		dbg(__FUNCTION__ " - zero length int");
+		return;
+	}
+
+
+#ifdef DEBUG
+	if (count) {
+		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+		for (i = 0; i < count; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+#ifdef BTBUGGYHARDWARE
+	if ((count >= 2) && (data[0] == 0xFF) && (data[1] == 0x00)) {
+		data += 2;
+		count -= 2;
+	}
+	if (count == 0) {
+		urb->actual_length = 0;
+		return;
+	}
+#endif
+	/* We add  a packet type identifier to the beginning of each
+	   HCI frame.  This makes the data in the tty look like a
+	   serial USB devices.  Each HCI frame can be broken across
+	   multiple URBs so we buffer them until we have a full hci
+	   packet */
+
+	if (!bluetooth->int_packet_pos) {
+		bluetooth->int_buffer[0] = EVENT_PKT;
+		bluetooth->int_packet_pos++;
+	}
+	
+	if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) {
+		err(__FUNCTION__ " - exceeded EVENT_BUFFER_SIZE");
+		bluetooth->int_packet_pos = 0;
+		return;
+	}
+
+	memcpy (&bluetooth->int_buffer[bluetooth->int_packet_pos],
+		urb->transfer_buffer, count);
+	bluetooth->int_packet_pos += count;
+	urb->actual_length = 0;
+
+	if (bluetooth->int_packet_pos >= EVENT_HDR_SIZE)
+		packet_size = bluetooth->int_buffer[2];
+	else
+		return;
+
+	if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) {
+		err(__FUNCTION__ " - packet was too long");
+		bluetooth->int_packet_pos = 0;
+		return;
+	}
+
+	if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos){
+		for (i = 0; i < bluetooth->int_packet_pos; ++i)
+			tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0);
+		tty_flip_buffer_push(bluetooth->tty);
+
+		bluetooth->int_packet_pos = 0;
+	}
+}
+
+
+static void bluetooth_ctrl_callback (struct urb *urb)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+}
+
+
+static void bluetooth_read_bulk_callback (struct urb *urb)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+	unsigned char *data = urb->transfer_buffer;
+	unsigned int count = urb->actual_length;
+	unsigned int i;
+	uint packet_size;
+
+#ifdef BTBUGGYHARDWARE
+	if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00)
+	    && (data[2] == 0x00) && (data[3] == 0x00)) {
+		urb->actual_length = 0;
+		if (usb_submit_urb(urb))
+			dbg(__FUNCTION__ " - failed resubmitting read urb");
+
+		return;
+	}
+#endif
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		goto exit;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		goto exit;
+	}
+
+	if (!count) {
+		dbg(__FUNCTION__ " - zero length read bulk");
+		goto exit;
+	}
+
+#ifdef DEBUG
+	if (count) {
+		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", count);
+		for (i = 0; i < count; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+	/* We add  a packet type identifier to the beginning of each
+	   HCI frame.  This makes the data in the tty look like a
+	   serial USB devices.  Each HCI frame can be broken across
+	   multiple URBs so we buffer them until we have a full hci
+	   packet */
+	
+	if (!bluetooth->bulk_packet_pos) {
+		bluetooth->bulk_buffer[0] = ACL_PKT;
+		bluetooth->bulk_packet_pos++;
+	}
+
+	if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) {
+		err(__FUNCTION__ " - exceeded ACL_BUFFER_SIZE");
+		bluetooth->bulk_packet_pos = 0;
+		goto exit;
+	}
+
+	memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos],
+		urb->transfer_buffer, count);
+	bluetooth->bulk_packet_pos += count;
+	urb->actual_length = 0;
+
+	if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) {
+		packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]);
+	} else {
+		goto exit;
+	}
+
+	if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) {
+		err(__FUNCTION__ " - packet was too long");
+		bluetooth->bulk_packet_pos = 0;
+		goto exit;
+	}
+
+	if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
+		for (i = 0; i < bluetooth->bulk_packet_pos; ++i)
+			tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0);
+		tty_flip_buffer_push(bluetooth->tty);
+		bluetooth->bulk_packet_pos = 0;
+	}	
+
+exit:
+	if (usb_submit_urb(urb))
+		dbg(__FUNCTION__ " - failed resubmitting read urb");
+
+	return;
+}
+
+
+static void bluetooth_write_bulk_callback (struct urb *urb)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		dbg(__FUNCTION__ " - bad bluetooth pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	/* wake up our little function to let the tty layer know that something happened */
+	queue_task(&bluetooth->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	return;
+}
+
+
+static void bluetooth_softint(void *private)
+{
+	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__);
+	struct tty_struct *tty;
+
+	dbg(__FUNCTION__);
+
+	if (!bluetooth) {
+		return;
+	}
+
+	tty = bluetooth->tty;
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+		dbg(__FUNCTION__ " - write wakeup call.");
+		(tty->ldisc.write_wakeup)(tty);
+	}
+
+	wake_up_interruptible(&tty->write_wait);
+}
+
+
+static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_bluetooth *bluetooth = NULL;
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_endpoint_descriptor *interrupt_in_endpoint[8];
+	struct usb_endpoint_descriptor *bulk_in_endpoint[8];
+	struct usb_endpoint_descriptor *bulk_out_endpoint[8];
+	int control_out_endpoint;
+
+	int minor;
+	int buffer_size;
+	int i;
+	int num_interrupt_in = 0;
+	int num_bulk_in = 0;
+	int num_bulk_out = 0;
+
+	/* see if this device has the proper class signature */
+	if ((dev->descriptor.bDeviceClass != WIRELESS_CLASS_CODE) || 
+	    (dev->descriptor.bDeviceSubClass != RF_SUBCLASS_CODE) ||
+	    (dev->descriptor.bDeviceProtocol != BLUETOOTH_PROGRAMMING_PROTOCOL_CODE)) {
+		dbg (__FUNCTION__ " - class signature %d, %d, %d did not match", 
+		     dev->descriptor.bDeviceClass, dev->descriptor.bDeviceSubClass,
+		     dev->descriptor.bDeviceProtocol);
+		return NULL;
+	}
+
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	control_out_endpoint = interface->bInterfaceNumber;
+
+	/* find the endpoints that we need */
+	for (i = 0; i < interface->bNumEndpoints; ++i) {
+		endpoint = &interface->endpoint[i];
+
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk in endpoint */
+			dbg("found bulk in");
+			bulk_in_endpoint[num_bulk_in] = endpoint;
+			++num_bulk_in;
+		}
+
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk out endpoint */
+			dbg("found bulk out");
+			bulk_out_endpoint[num_bulk_out] = endpoint;
+			++num_bulk_out;
+		}
+
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x03)) {
+			/* we found a interrupt in endpoint */
+			dbg("found interrupt in");
+			interrupt_in_endpoint[num_interrupt_in] = endpoint;
+			++num_interrupt_in;
+		}
+	}
+
+	/* according to the spec, we can only have 1 bulk_in, 1 bulk_out, and 1 interrupt_in endpoints */
+	if ((num_bulk_in != 1) ||
+	    (num_bulk_out != 1) ||
+	    (num_interrupt_in != 1)) {
+		dbg (__FUNCTION__ " - improper number of endpoints. Bluetooth driver not bound.");
+		return NULL;
+	}
+
+	MOD_INC_USE_COUNT;
+	info("USB Bluetooth converter detected");
+
+	for (minor = 0; minor < BLUETOOTH_TTY_MINORS && bluetooth_table[minor]; ++minor)
+		;
+	if (bluetooth_table[minor]) {
+		err("No more free Bluetooth devices");
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+
+	if (!(bluetooth = kmalloc(sizeof(struct usb_bluetooth), GFP_KERNEL))) {
+		err("Out of memory");
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+
+	memset(bluetooth, 0, sizeof(struct usb_bluetooth));
+
+	bluetooth->magic = USB_BLUETOOTH_MAGIC;
+	bluetooth->dev = dev;
+	bluetooth->minor = minor;
+	bluetooth->tqueue.routine = bluetooth_softint;
+	bluetooth->tqueue.data = bluetooth;
+
+	/* record the interface number for the control out */
+	bluetooth->control_out_bInterfaceNum = control_out_endpoint;
+	
+	/* create our control out urb pool */ 
+	for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+		struct urb  *urb = usb_alloc_urb(0);
+		if (urb == NULL) {
+			err("No free urbs available");
+			goto probe_error;
+		}
+		urb->transfer_buffer = NULL;
+		bluetooth->control_urb_pool[i] = urb;
+	}
+
+	/* set up the endpoint information */
+	endpoint = bulk_in_endpoint[0];
+	bluetooth->read_urb = usb_alloc_urb (0);
+	if (!bluetooth->read_urb) {
+		err("No free urbs available");
+		goto probe_error;
+	}
+	buffer_size = endpoint->wMaxPacketSize;
+	bluetooth->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+	if (!bluetooth->bulk_in_buffer) {
+		err("Couldn't allocate bulk_in_buffer");
+		goto probe_error;
+	}
+	FILL_BULK_URB(bluetooth->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+		      bluetooth->bulk_in_buffer, buffer_size, bluetooth_read_bulk_callback, bluetooth);
+
+	endpoint = bulk_out_endpoint[0];
+	bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress;
+	
+	/* create our write urb pool */ 
+	for (i = 0; i < NUM_BULK_URBS; ++i) {
+		struct urb  *urb = usb_alloc_urb(0);
+		if (urb == NULL) {
+			err("No free urbs available");
+			goto probe_error;
+		}
+		urb->transfer_buffer = NULL;
+		bluetooth->write_urb_pool[i] = urb;
+	}
+	
+	bluetooth->bulk_out_size = endpoint->wMaxPacketSize * 2;
+
+	endpoint = interrupt_in_endpoint[0];
+	bluetooth->interrupt_in_urb = usb_alloc_urb(0);
+	if (!bluetooth->interrupt_in_urb) {
+		err("No free urbs available");
+		goto probe_error;
+	}
+	buffer_size = endpoint->wMaxPacketSize;
+	bluetooth->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+	if (!bluetooth->interrupt_in_buffer) {
+		err("Couldn't allocate interrupt_in_buffer");
+		goto probe_error;
+	}
+	FILL_INT_URB(bluetooth->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+		     bluetooth->interrupt_in_buffer, buffer_size, bluetooth_int_callback,
+		     bluetooth, endpoint->bInterval);
+
+	/* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */
+	tty_register_devfs (&bluetooth_tty_driver, 0, minor);
+	info("Bluetooth converter now attached to ttyBLUE%d (or usb/ttblue/%d for devfs)", minor, minor);
+
+	bluetooth_table[minor] = bluetooth;
+
+	return bluetooth; /* success */
+
+probe_error:
+	if (bluetooth->read_urb)
+		usb_free_urb (bluetooth->read_urb);
+	if (bluetooth->bulk_in_buffer)
+		kfree (bluetooth->bulk_in_buffer);
+	if (bluetooth->interrupt_in_urb)
+		usb_free_urb (bluetooth->interrupt_in_urb);
+	if (bluetooth->interrupt_in_buffer)
+		kfree (bluetooth->interrupt_in_buffer);
+	for (i = 0; i < NUM_BULK_URBS; ++i)
+		if (bluetooth->write_urb_pool[i])
+			usb_free_urb (bluetooth->write_urb_pool[i]);
+	for (i = 0; i < NUM_CONTROL_URBS; ++i) 
+		if (bluetooth->control_urb_pool[i])
+			usb_free_urb (bluetooth->control_urb_pool[i]);
+
+	bluetooth_table[minor] = NULL;
+
+	/* free up any memory that we allocated */
+	kfree (bluetooth);
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+
+static void usb_bluetooth_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_bluetooth *bluetooth = (struct usb_bluetooth *) ptr;
+	int i;
+
+	if (bluetooth) {
+		if ((bluetooth->active) && (bluetooth->tty))
+			tty_hangup(bluetooth->tty);
+
+		bluetooth->active = 0;
+
+		if (bluetooth->read_urb) {
+			usb_unlink_urb (bluetooth->read_urb);
+			usb_free_urb (bluetooth->read_urb);
+		}
+		if (bluetooth->bulk_in_buffer)
+			kfree (bluetooth->bulk_in_buffer);
+
+		if (bluetooth->interrupt_in_urb) {
+			usb_unlink_urb (bluetooth->interrupt_in_urb);
+			usb_free_urb (bluetooth->interrupt_in_urb);
+		}
+		if (bluetooth->interrupt_in_buffer)
+			kfree (bluetooth->interrupt_in_buffer);
+
+		tty_unregister_devfs (&bluetooth_tty_driver, bluetooth->minor);
+
+		for (i = 0; i < NUM_BULK_URBS; ++i) {
+			if (bluetooth->write_urb_pool[i]) {
+				usb_unlink_urb (bluetooth->write_urb_pool[i]);
+				if (bluetooth->write_urb_pool[i]->transfer_buffer)
+					kfree (bluetooth->write_urb_pool[i]->transfer_buffer);
+				usb_free_urb (bluetooth->write_urb_pool[i]);
+			}
+		}
+		for (i = 0; i < NUM_CONTROL_URBS; ++i) {
+			if (bluetooth->control_urb_pool[i]) {
+				usb_unlink_urb (bluetooth->control_urb_pool[i]);
+				if (bluetooth->control_urb_pool[i]->transfer_buffer)
+					kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
+				usb_free_urb (bluetooth->control_urb_pool[i]);
+			}
+		}
+		
+		info("Bluetooth converter now disconnected from ttyBLUE%d", bluetooth->minor);
+
+		bluetooth_table[bluetooth->minor] = NULL;
+
+		/* free up any memory that we allocated */
+		kfree (bluetooth);
+
+	} else {
+		info("device disconnected");
+	}
+
+	MOD_DEC_USE_COUNT;
+}
+
+
+static struct tty_driver bluetooth_tty_driver = {
+	magic:			TTY_DRIVER_MAGIC,
+	driver_name:		"usb-bluetooth",
+	name:			"usb/ttblue/%d",
+	major:			BLUETOOTH_TTY_MAJOR,
+	minor_start:		0,
+	num:			BLUETOOTH_TTY_MINORS,
+	type:			TTY_DRIVER_TYPE_SERIAL,
+	subtype:		SERIAL_TYPE_NORMAL,
+	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+
+	refcount:		&bluetooth_refcount,
+	table:			bluetooth_tty,
+	termios:		bluetooth_termios,
+	termios_locked:		bluetooth_termios_locked,
+
+	open:			bluetooth_open,
+	close:			bluetooth_close,
+	write:			bluetooth_write,
+	write_room:		bluetooth_write_room,
+	ioctl:			bluetooth_ioctl,
+	set_termios:		bluetooth_set_termios,
+	throttle:		bluetooth_throttle,
+	unthrottle:		bluetooth_unthrottle,
+	chars_in_buffer:	bluetooth_chars_in_buffer,
+};
+
+
+int usb_bluetooth_init(void)
+{
+	int i;
+	int result;
+
+	/* Initalize our global data */
+	for (i = 0; i < BLUETOOTH_TTY_MINORS; ++i) {
+		bluetooth_table[i] = NULL;
+	}
+
+	info ("USB Bluetooth support registered");
+
+	/* register the tty driver */
+	bluetooth_tty_driver.init_termios          = tty_std_termios;
+	bluetooth_tty_driver.init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	if (tty_register_driver (&bluetooth_tty_driver)) {
+		err(__FUNCTION__ " - failed to register tty driver");
+		return -1;
+	}
+
+	/* register the USB driver */
+	result = usb_register(&usb_bluetooth_driver);
+	if (result < 0) {
+		tty_unregister_driver(&bluetooth_tty_driver);
+		err("usb_register failed for the USB bluetooth driver. Error number %d", result);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void usb_bluetooth_exit(void)
+{
+	usb_deregister(&usb_bluetooth_driver);
+	tty_unregister_driver(&bluetooth_tty_driver);
+}
+
+
+module_init(usb_bluetooth_init);
+module_exit(usb_bluetooth_exit);
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/dabfirmware.h linux.18p8/drivers/usb/dabfirmware.h
--- linux.vanilla/drivers/usb/dabfirmware.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/dabfirmware.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,1408 @@
+/*
+ * dabdata.h - dab usb firmware and bitstream data
+ */
+
+static INTEL_HEX_RECORD firmware[] = {
+
+{  2, 0x0000, 0, {0x21,0x57} },
+{  3, 0x0003, 0, {0x02,0x01,0x66} },
+{  3, 0x000b, 0, {0x02,0x01,0x66} },
+{  3, 0x0013, 0, {0x02,0x01,0x66} },
+{  3, 0x001b, 0, {0x02,0x01,0x66} },
+{  3, 0x0023, 0, {0x02,0x01,0x66} },
+{  3, 0x002b, 0, {0x02,0x01,0x66} },
+{  3, 0x0033, 0, {0x02,0x03,0x0f} },
+{  3, 0x003b, 0, {0x02,0x01,0x66} },
+{  3, 0x0043, 0, {0x02,0x01,0x00} },
+{  3, 0x004b, 0, {0x02,0x01,0x66} },
+{  3, 0x0053, 0, {0x02,0x01,0x66} },
+{  3, 0x005b, 0, {0x02,0x04,0xbd} },
+{  3, 0x0063, 0, {0x02,0x01,0x67} },
+{  3, 0x0100, 0, {0x02,0x0c,0x5a} },
+{  3, 0x0104, 0, {0x02,0x01,0xed} },
+{  3, 0x0108, 0, {0x02,0x02,0x51} },
+{  3, 0x010c, 0, {0x02,0x02,0x7c} },
+{  3, 0x0110, 0, {0x02,0x02,0xe4} },
+{  1, 0x0114, 0, {0x32} },
+{  1, 0x0118, 0, {0x32} },
+{  3, 0x011c, 0, {0x02,0x05,0xfd} },
+{  3, 0x0120, 0, {0x02,0x00,0x00} },
+{  3, 0x0124, 0, {0x02,0x00,0x00} },
+{  3, 0x0128, 0, {0x02,0x04,0x3c} },
+{  3, 0x012c, 0, {0x02,0x04,0x6a} },
+{  3, 0x0130, 0, {0x02,0x00,0x00} },
+{  3, 0x0134, 0, {0x02,0x00,0x00} },
+{  3, 0x0138, 0, {0x02,0x00,0x00} },
+{  3, 0x013c, 0, {0x02,0x00,0x00} },
+{  3, 0x0140, 0, {0x02,0x00,0x00} },
+{  3, 0x0144, 0, {0x02,0x00,0x00} },
+{  3, 0x0148, 0, {0x02,0x00,0x00} },
+{  3, 0x014c, 0, {0x02,0x00,0x00} },
+{  3, 0x0150, 0, {0x02,0x00,0x00} },
+{  3, 0x0154, 0, {0x02,0x00,0x00} },
+{ 10, 0x0157, 0, {0x75,0x81,0x7f,0xe5,0x82,0x60,0x03,0x02,0x01,0x61} },
+{  5, 0x0161, 0, {0x12,0x07,0x6f,0x21,0x64} },
+{  1, 0x0166, 0, {0x32} },
+{ 14, 0x0167, 0, {0xc0,0xd0,0xc0,0x86,0xc0,0x82,0xc0,0x83,0xc0,0xe0,0x90,0x7f,0x97,0xe0} },
+{ 14, 0x0175, 0, {0x44,0x80,0xf0,0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x0183, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x0191, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x90,0x7f,0x97,0xe0} },
+{  3, 0x019f, 0, {0x55,0x7f,0xf0} },
+{ 14, 0x01a2, 0, {0x90,0x7f,0x9a,0xe0,0x30,0xe4,0x23,0x90,0x7f,0x68,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x01b0, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x01be, 0, {0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0} },
+{ 14, 0x01cc, 0, {0xe5,0xd8,0xc2,0xe3,0xf5,0xd8,0xd0,0xe0,0xd0,0x83,0xd0,0x82,0xd0,0x86} },
+{  3, 0x01da, 0, {0xd0,0xd0,0x32} },
+{  8, 0x01dd, 0, {0x75,0x86,0x00,0x90,0xff,0xc3,0x7c,0x05} },
+{  7, 0x01e5, 0, {0xa3,0xe5,0x82,0x45,0x83,0x70,0xf9} },
+{  1, 0x01ec, 0, {0x22} },
+{ 14, 0x01ed, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0xd0} },
+{ 14, 0x01fb, 0, {0x75,0xd0,0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91} },
+{ 13, 0x0209, 0, {0x90,0x88,0x00,0xe0,0xf5,0x41,0x90,0x7f,0xab,0x74,0x02,0xf0,0x90} },
+{  9, 0x0216, 0, {0x7f,0xab,0x74,0x02,0xf0,0xe5,0x32,0x60,0x21} },
+{  4, 0x021f, 0, {0x7a,0x00,0x7b,0x00} },
+{ 11, 0x0223, 0, {0xc3,0xea,0x94,0x18,0xeb,0x64,0x80,0x94,0x80,0x50,0x12} },
+{ 14, 0x022e, 0, {0x90,0x7f,0x69,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0x0a,0xba,0x00} },
+{  2, 0x023c, 0, {0x01,0x0b} },
+{  2, 0x023e, 0, {0x80,0xe3} },
+{  2, 0x0240, 0, {0xd0,0x86} },
+{ 14, 0x0242, 0, {0xd0,0xd0,0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0} },
+{  1, 0x0250, 0, {0x32} },
+{ 14, 0x0251, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x025f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
+{  4, 0x026d, 0, {0x04,0xf0,0xd0,0x86} },
+{ 11, 0x0271, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x027c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x028a, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 13, 0x0298, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
+{ 12, 0x02a5, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0x6e,0x00,0x75,0x6f,0x02,0x12} },
+{  6, 0x02b1, 0, {0x11,0x44,0x75,0x70,0x39,0x75} },
+{  6, 0x02b7, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
+{ 12, 0x02bd, 0, {0x11,0x75,0x90,0x7f,0xd6,0xe4,0xf0,0x75,0xd8,0x20,0xd0,0x86} },
+{ 14, 0x02c9, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x02d7, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x02e4, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x02f2, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xab,0x74} },
+{  4, 0x0300, 0, {0x10,0xf0,0xd0,0x86} },
+{ 11, 0x0304, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x030f, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x031d, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 12, 0x032b, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0x75,0x6e,0x00,0x75,0x6f,0x02} },
+{  7, 0x0337, 0, {0x12,0x11,0x44,0x75,0x70,0x40,0x75} },
+{  6, 0x033e, 0, {0x71,0x0c,0x75,0x72,0x02,0x12} },
+{ 14, 0x0344, 0, {0x11,0x75,0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0} },
+{  5, 0x0352, 0, {0x75,0xd8,0x10,0xd0,0x86} },
+{ 14, 0x0357, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x0365, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 13, 0x0372, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
+{ 12, 0x037f, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x42,0xf0,0x12,0x10,0x1b,0x90} },
+{ 13, 0x038b, 0, {0x7f,0xa6,0xe5,0x43,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40} },
+{  1, 0x0398, 0, {0xf0} },
+{  1, 0x0399, 0, {0x22} },
+{ 13, 0x039a, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x90,0x7f,0xa6,0x74,0x9a,0xf0,0x12} },
+{ 12, 0x03a7, 0, {0x10,0x1b,0x90,0x7f,0xa6,0xe5,0x44,0xf0,0x12,0x10,0x1b,0x90} },
+{ 12, 0x03b3, 0, {0x7f,0xa6,0xe5,0x45,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0xe5} },
+{ 11, 0x03bf, 0, {0x46,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa5,0x74,0x40,0xf0} },
+{  1, 0x03ca, 0, {0x22} },
+{ 10, 0x03cb, 0, {0x75,0x44,0x02,0x75,0x45,0x00,0x75,0x46,0x00,0x12} },
+{  9, 0x03d5, 0, {0x03,0x9a,0x75,0x42,0x03,0x75,0x43,0x00,0x12} },
+{  2, 0x03de, 0, {0x03,0x72} },
+{  1, 0x03e0, 0, {0x22} },
+{ 12, 0x03e1, 0, {0x90,0x88,0x00,0xe5,0x36,0xf0,0x90,0x88,0x00,0x74,0x10,0x25} },
+{  9, 0x03ed, 0, {0x36,0xf0,0x12,0x01,0xdd,0x75,0x42,0x01,0x75} },
+{  9, 0x03f6, 0, {0x43,0x18,0x12,0x03,0x72,0x75,0x44,0x02,0x75} },
+{  9, 0x03ff, 0,{0x45,0x00,0x75,0x46,0x00,0x12,0x03,0x9a,0x75} },
+{  8, 0x0408, 0,{0x42,0x03,0x75,0x43,0x44,0x12,0x03,0x72} },
+{  1, 0x0410, 0,{0x22} },
+{ 14, 0x0411, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x041f, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
+{  4, 0x042d, 0, {0x02,0xf0,0xd0,0x86} },
+{ 11, 0x0431, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x043c, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x044a, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xa9,0x74} },
+{  7, 0x0458, 0, {0x04,0xf0,0x75,0x30,0x01,0xd0,0x86} },
+{ 11, 0x045f, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x046a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 14, 0x0478, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90,0x7f,0xaa,0x74} },
+{  7, 0x0486, 0, {0x04,0xf0,0x75,0x31,0x01,0xd0,0x86} },
+{ 11, 0x048d, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x0498, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 12, 0x04a6, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe5,0xf5,0x91,0xd0,0x86} },
+{ 11, 0x04b2, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x04bd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0xd0,0x75,0xd0,0x00,0xc0} },
+{ 12, 0x04cb, 0, {0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe7,0xf5,0x91,0xd0,0x86} },
+{ 11, 0x04d7, 0, {0xd0,0xd0,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 12, 0x04e2, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x20,0x90,0x7f,0x96,0xe4,0xf0} },
+{  1, 0x04ee, 0, {0x22} },
+{  7, 0x04ef, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x8a,0x21} },
+{  1, 0x04f6, 0, {0x22} },
+{ 14, 0x04f7, 0, {0x90,0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xe0,0xfb,0x74,0x80,0x2a,0xfa} },
+{ 14, 0x0505, 0, {0x74,0x80,0x2b,0xfb,0xea,0x03,0x03,0x54,0x3f,0xfc,0xea,0xc4,0x23,0x54} },
+{ 14, 0x0513, 0, {0x1f,0xfa,0x2c,0xfa,0xeb,0x03,0x03,0x54,0x3f,0xfc,0xeb,0xc4,0x23,0x54} },
+{ 11, 0x0521, 0, {0x1f,0xfb,0x2c,0xfb,0x90,0x17,0x0a,0xe0,0xfc,0x60,0x02} },
+{  2, 0x052c, 0, {0x7a,0x00} },
+{  7, 0x052e, 0, {0x90,0x17,0x0c,0xe0,0xfc,0x60,0x02} },
+{  2, 0x0535, 0, {0x7b,0x00} },
+{ 11, 0x0537, 0, {0xea,0x2b,0xfc,0xc3,0x13,0xf5,0x3a,0x75,0x44,0x02,0x8b} },
+{  7, 0x0542, 0, {0x45,0x8a,0x46,0x12,0x03,0x9a,0x75} },
+{  9, 0x0549, 0, {0x6e,0x08,0x75,0x6f,0x00,0x12,0x11,0x44,0x75} },
+{  4, 0x0552, 0, {0x70,0x47,0x75,0x71} },
+{  8, 0x0556, 0, {0x0c,0x75,0x72,0x02,0x12,0x11,0x75,0x85} },
+{  5, 0x055e, 0, {0x3a,0x73,0x12,0x11,0xa0} },
+{  1, 0x0563, 0, {0x22} },
+{ 14, 0x0564, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
+{ 14, 0x0572, 0, {0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xef,0xe0,0xfc} },
+{ 14, 0x0580, 0, {0x33,0x95,0xe0,0xfd,0x8c,0x05,0x7c,0x00,0x90,0x7f,0xee,0xe0,0xfe,0x33} },
+{ 14, 0x058e, 0, {0x95,0xe0,0xff,0xec,0x2e,0xfc,0xed,0x3f,0xfd,0x90,0x7f,0xe9,0xe0,0xfe} },
+{  5, 0x059c, 0, {0xbe,0x01,0x02,0x80,0x03} },
+{  3, 0x05a1, 0, {0x02,0x05,0xf9} },
+{  6, 0x05a4, 0, {0xbc,0x01,0x21,0xbd,0x00,0x1e} },
+{ 14, 0x05aa, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfc,0xeb,0x25,0xe0,0xfd,0x2c,0x24,0x00,0xfc} },
+{ 14, 0x05b8, 0, {0xe4,0x34,0x17,0xfd,0x90,0x7e,0xc0,0xe0,0xfe,0x8c,0x82,0x8d,0x83,0xf0} },
+{  2, 0x05c6, 0, {0x80,0x31} },
+{ 14, 0x05c8, 0, {0xea,0xc4,0x03,0x54,0xf8,0xfa,0xeb,0x25,0xe0,0xfb,0x2a,0xfa,0x24,0x00} },
+{ 14, 0x05d6, 0, {0xfb,0xe4,0x34,0x17,0xfc,0x90,0x7e,0xc0,0xe0,0xfd,0x8b,0x82,0x8c,0x83} },
+{ 14, 0x05e4, 0, {0xf0,0x74,0x01,0x2a,0x24,0x00,0xfa,0xe4,0x34,0x17,0xfb,0x90,0x7e,0xc1} },
+{  7, 0x05f2, 0, {0xe0,0xfc,0x8a,0x82,0x8b,0x83,0xf0} },
+{  3, 0x05f9, 0, {0x75,0x38,0x01} },
+{  1, 0x05fc, 0, {0x22} },
+{ 14, 0x05fd, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x060b, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 13, 0x0619, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
+{ 13, 0x0626, 0, {0x7f,0xaa,0x74,0x01,0xf0,0x12,0x05,0x64,0x75,0x37,0x00,0xd0,0x86} },
+{ 14, 0x0633, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x0641, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 14, 0x064e, 0, {0x90,0x7f,0xeb,0xe0,0xfa,0x90,0x7f,0xea,0xe0,0xfb,0x90,0x7f,0xee,0xe0} },
+{ 14, 0x065c, 0, {0xfc,0x33,0x95,0xe0,0xfd,0x90,0x7f,0x96,0xe0,0xfe,0x90,0x7f,0x96,0x74} },
+{ 14, 0x066a, 0, {0x80,0x65,0x06,0xf0,0x90,0x7f,0x00,0x74,0x01,0xf0,0xea,0xc4,0x03,0x54} },
+{ 14, 0x0678, 0, {0xf8,0xfe,0xeb,0x25,0xe0,0xfb,0x2e,0xfe,0x24,0x00,0xfb,0xe4,0x34,0x17} },
+{ 14, 0x0686, 0, {0xff,0x8b,0x82,0x8f,0x83,0xe0,0xfb,0x74,0x01,0x2e,0x24,0x00,0xfe,0xe4} },
+{ 14, 0x0694, 0, {0x34,0x17,0xff,0x8e,0x82,0x8f,0x83,0xe0,0xfe,0x90,0x7f,0xe9,0xe0,0xff} },
+{  3, 0x06a2, 0, {0xbf,0x81,0x0a} },
+{ 10, 0x06a5, 0, {0x90,0x7f,0x00,0xeb,0xf0,0x90,0x7f,0x01,0xee,0xf0} },
+{  8, 0x06af, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x82,0x1a} },
+{  3, 0x06b7, 0, {0xba,0x01,0x0c} },
+{ 12, 0x06ba, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
+{ 11, 0x06c6, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0xb5,0xf0} },
+{  8, 0x06d1, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x83,0x1b} },
+{  3, 0x06d9, 0, {0xba,0x01,0x0d} },
+{ 13, 0x06dc, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0b} },
+{ 11, 0x06e9, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0x74,0x12,0xf0} },
+{  8, 0x06f4, 0, {0x90,0x7f,0xe9,0xe0,0xfb,0xbb,0x84,0x1c} },
+{  3, 0x06fc, 0, {0xba,0x01,0x0d} },
+{ 13, 0x06ff, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x80,0x0c} },
+{ 12, 0x070c, 0, {0x90,0x7f,0x00,0x74,0x80,0xf0,0x90,0x7f,0x01,0x74,0x01,0xf0} },
+{  5, 0x0718, 0, {0x90,0x7f,0xb5,0xec,0xf0} },
+{  1, 0x071d, 0, {0x22} },
+{ 12, 0x071e, 0, {0x75,0x36,0x0d,0x90,0x88,0x00,0x74,0x1d,0xf0,0x75,0x6b,0x80} },
+{ 10, 0x072a, 0, {0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
+{  9, 0x0734, 0, {0x6c,0x0f,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
+{  9, 0x073d, 0, {0x6c,0x06,0x12,0x10,0xe2,0x75,0x6b,0x80,0x75} },
+{  7, 0x0746, 0, {0x6c,0x01,0x12,0x10,0xe2,0x7a,0x00} },
+{  3, 0x074d, 0, {0xba,0xff,0x00} },
+{  2, 0x0750, 0, {0x50,0x0a} },
+{ 10, 0x0752, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
+{ 10, 0x075c, 0, {0x75,0x6b,0x80,0x75,0x6c,0x3c,0x12,0x10,0xe2,0x75} },
+{  8, 0x0766, 0, {0x6b,0x80,0x75,0x6c,0x0f,0x12,0x10,0xe2} },
+{  1, 0x076e, 0, {0x22} },
+{ 14, 0x076f, 0, {0x90,0x7f,0xa1,0xe4,0xf0,0x90,0x7f,0xaf,0x74,0x01,0xf0,0x90,0x7f,0x92} },
+{ 14, 0x077d, 0, {0x74,0x02,0xf0,0x75,0x8e,0x31,0x75,0x89,0x21,0x75,0x88,0x00,0x75,0xc8} },
+{ 14, 0x078b, 0, {0x00,0x75,0x8d,0x40,0x75,0x98,0x40,0x75,0xc0,0x40,0x75,0x87,0x00,0x75} },
+{  9, 0x0799, 0, {0x20,0x00,0x75,0x21,0x00,0x75,0x22,0x00,0x75} },
+{  5, 0x07a2, 0, {0x23,0x00,0x75,0x47,0x00} },
+{  7, 0x07a7, 0, {0xc3,0xe5,0x47,0x94,0x20,0x50,0x11} },
+{ 13, 0x07ae, 0, {0xe5,0x47,0x24,0x00,0xf5,0x82,0xe4,0x34,0x17,0xf5,0x83,0xe4,0xf0} },
+{  4, 0x07bb, 0, {0x05,0x47,0x80,0xe8} },
+{  9, 0x07bf, 0, {0xe4,0xf5,0x40,0xf5,0x3f,0xe4,0xf5,0x3c,0xf5} },
+{  7, 0x07c8, 0, {0x3b,0xe4,0xf5,0x3e,0xf5,0x3d,0x75} },
+{ 11, 0x07cf, 0, {0x32,0x00,0x75,0x37,0x00,0x75,0x39,0x00,0x90,0x7f,0x93} },
+{ 14, 0x07da, 0, {0x74,0x3c,0xf0,0x90,0x7f,0x9c,0x74,0xff,0xf0,0x90,0x7f,0x96,0x74,0x80} },
+{ 14, 0x07e8, 0, {0xf0,0x90,0x7f,0x94,0x74,0x70,0xf0,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
+{ 14, 0x07f6, 0, {0x7f,0x97,0xe4,0xf0,0x90,0x7f,0x95,0x74,0xc2,0xf0,0x90,0x7f,0x98,0x74} },
+{ 14, 0x0804, 0, {0x28,0xf0,0x90,0x7f,0x9e,0x74,0x28,0xf0,0x90,0x7f,0xf0,0xe4,0xf0,0x90} },
+{ 14, 0x0812, 0, {0x7f,0xf1,0xe4,0xf0,0x90,0x7f,0xf2,0xe4,0xf0,0x90,0x7f,0xf3,0xe4,0xf0} },
+{ 14, 0x0820, 0, {0x90,0x7f,0xf4,0xe4,0xf0,0x90,0x7f,0xf5,0xe4,0xf0,0x90,0x7f,0xf6,0xe4} },
+{ 14, 0x082e, 0, {0xf0,0x90,0x7f,0xf7,0xe4,0xf0,0x90,0x7f,0xf8,0xe4,0xf0,0x90,0x7f,0xf9} },
+{ 14, 0x083c, 0, {0x74,0x38,0xf0,0x90,0x7f,0xfa,0x74,0xa0,0xf0,0x90,0x7f,0xfb,0x74,0xa0} },
+{ 14, 0x084a, 0, {0xf0,0x90,0x7f,0xfc,0x74,0xa0,0xf0,0x90,0x7f,0xfd,0x74,0xa0,0xf0,0x90} },
+{ 14, 0x0858, 0, {0x7f,0xfe,0x74,0xa0,0xf0,0x90,0x7f,0xff,0x74,0xa0,0xf0,0x90,0x7f,0xe0} },
+{ 14, 0x0866, 0, {0x74,0x03,0xf0,0x90,0x7f,0xe1,0x74,0x01,0xf0,0x90,0x7f,0xdd,0x74,0x80} },
+{ 11, 0x0874, 0, {0xf0,0x12,0x12,0x43,0x12,0x07,0x1e,0x7a,0x00,0x7b,0x00} },
+{  9, 0x087f, 0, {0xc3,0xea,0x94,0x1e,0xeb,0x94,0x00,0x50,0x17} },
+{ 12, 0x0888, 0, {0x90,0x88,0x00,0xe0,0xf5,0x47,0x90,0x88,0x0b,0xe0,0xf5,0x47} },
+{  9, 0x0894, 0, {0x90,0x7f,0x68,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x089d, 0, {0x80,0xe0} },
+{ 12, 0x089f, 0, {0x12,0x03,0xe1,0x90,0x7f,0xd6,0xe4,0xf0,0x7a,0x00,0x7b,0x00} },
+{ 13, 0x08ab, 0, {0x8a,0x04,0x8b,0x05,0xc3,0xea,0x94,0xe0,0xeb,0x94,0x2e,0x50,0x1a} },
+{ 14, 0x08b8, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
+{ 10, 0x08c6, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x08d0, 0, {0x80,0xd9} },
+{ 13, 0x08d2, 0, {0x90,0x7f,0xd6,0x74,0x02,0xf0,0x90,0x7f,0xd6,0x74,0x06,0xf0,0x90} },
+{ 14, 0x08df, 0, {0x7f,0xde,0x74,0x05,0xf0,0x90,0x7f,0xdf,0x74,0x05,0xf0,0x90,0x7f,0xac} },
+{ 14, 0x08ed, 0, {0xe4,0xf0,0x90,0x7f,0xad,0x74,0x05,0xf0,0x75,0xa8,0x80,0x75,0xf8,0x10} },
+{ 13, 0x08fb, 0, {0x90,0x7f,0xae,0x74,0x0b,0xf0,0x90,0x7f,0xe2,0x74,0x88,0xf0,0x90} },
+{ 12, 0x0908, 0, {0x7f,0xab,0x74,0x08,0xf0,0x75,0xe8,0x11,0x75,0x32,0x01,0x75} },
+{ 12, 0x0914, 0, {0x31,0x00,0x75,0x30,0x00,0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7} },
+{ 10, 0x0920, 0, {0xd0,0x05,0xd0,0x04,0x75,0x34,0x00,0x75,0x35,0x01} },
+{ 13, 0x092a, 0, {0x90,0x7f,0xae,0x74,0x03,0xf0,0x8c,0x02,0xba,0x00,0x02,0x80,0x03} },
+{  3, 0x0937, 0, {0x02,0x0a,0x3f} },
+{ 12, 0x093a, 0, {0x85,0x33,0x34,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90,0x7f,0x97} },
+{ 14, 0x0946, 0, {0x74,0x08,0xf0,0x90,0x7f,0x9d,0x74,0x88,0xf0,0x90,0x7f,0x9a,0xe0,0xfa} },
+{ 12, 0x0954, 0, {0x74,0x05,0x5a,0xf5,0x33,0x90,0x7f,0x9d,0x74,0x8f,0xf0,0x90} },
+{ 13, 0x0960, 0, {0x7f,0x97,0x74,0x02,0xf0,0x90,0x7f,0x9d,0x74,0x82,0xf0,0xe5,0x33} },
+{ 13, 0x096d, 0, {0x25,0xe0,0xfa,0x90,0x7f,0x9a,0xe0,0x54,0x05,0xfb,0x4a,0xf5,0x33} },
+{  2, 0x097a, 0, {0x60,0x0c} },
+{ 12, 0x097c, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x4a,0xf0} },
+{ 11, 0x0988, 0, {0x75,0x6e,0x00,0x75,0x6f,0x00,0xc0,0x04,0xc0,0x05,0x12} },
+{ 14, 0x0993, 0, {0x11,0x44,0xd0,0x05,0xd0,0x04,0x90,0x17,0x13,0xe0,0xfa,0x74,0x80,0x2a} },
+{  6, 0x09a1, 0, {0xfa,0xe5,0x33,0xb4,0x04,0x29} },
+{  3, 0x09a7, 0, {0xba,0xa0,0x00} },
+{  2, 0x09aa, 0, {0x50,0x24} },
+{ 13, 0x09ac, 0, {0x90,0x17,0x13,0xe0,0x04,0xfb,0x0b,0x90,0x17,0x13,0xeb,0xf0,0x90} },
+{ 14, 0x09b9, 0, {0x17,0x13,0xe0,0xfb,0x90,0x17,0x15,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05} },
+{  9, 0x09c7, 0, {0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
+{  5, 0x09d0, 0, {0xe5,0x33,0xb4,0x02,0x26} },
+{  6, 0x09d5, 0, {0xc3,0x74,0x04,0x9a,0x50,0x20} },
+{ 13, 0x09db, 0, {0x90,0x17,0x13,0xe0,0xfa,0x1a,0x1a,0x90,0x17,0x13,0xea,0xf0,0x90} },
+{ 13, 0x09e8, 0, {0x17,0x13,0xe0,0xfa,0x90,0x17,0x15,0xf0,0xc0,0x04,0xc0,0x05,0x12} },
+{  6, 0x09f5, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04} },
+{  5, 0x09fb, 0, {0xe5,0x33,0xb4,0x08,0x1d} },
+{  4, 0x0a00, 0, {0xe5,0x34,0x70,0x19} },
+{ 10, 0x0a04, 0, {0x74,0x01,0x25,0x35,0x54,0x0f,0xf5,0x35,0x85,0x35} },
+{ 12, 0x0a0e, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
+{  3, 0x0a1a, 0, {0x05,0xd0,0x04} },
+{  5, 0x0a1d, 0, {0xe5,0x33,0xb4,0x01,0x1d} },
+{  4, 0x0a22, 0, {0xe5,0x34,0x70,0x19} },
+{ 10, 0x0a26, 0, {0xe5,0x35,0x24,0xff,0x54,0x0f,0xf5,0x35,0x85,0x35} },
+{ 12, 0x0a30, 0, {0x75,0x75,0x76,0x00,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0} },
+{  3, 0x0a3c, 0, {0x05,0xd0,0x04} },
+{ 14, 0x0a3f, 0, {0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0,0x04,0x90,0x7f,0x96} },
+{ 14, 0x0a4d, 0, {0xe0,0xfa,0x90,0x7f,0x96,0x74,0x7f,0x5a,0xf0,0x90,0x7f,0x97,0x74,0x08} },
+{ 10, 0x0a5b, 0, {0xf0,0xc3,0xec,0x94,0x00,0xed,0x94,0x02,0x40,0x08} },
+{  8, 0x0a65, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x20,0xe6,0x08} },
+{  8, 0x0a6d, 0, {0xc3,0xe4,0x9c,0x74,0x08,0x9d,0x50,0x13} },
+{ 14, 0x0a75, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x40,0x65,0x02,0xf0,0x7c} },
+{  5, 0x0a83, 0, {0x00,0x7d,0x00,0x80,0x05} },
+{  5, 0x0a88, 0, {0x0c,0xbc,0x00,0x01,0x0d} },
+{  5, 0x0a8d, 0, {0xe5,0x38,0xb4,0x01,0x0e} },
+{ 13, 0x0a92, 0, {0xc0,0x04,0xc0,0x05,0x12,0x04,0xf7,0xd0,0x05,0xd0,0x04,0x75,0x38} },
+{  1, 0x0a9f, 0, {0x00} },
+{  7, 0x0aa0, 0, {0xe5,0x31,0x70,0x03,0x02,0x09,0x2a} },
+{ 10, 0x0aa7, 0, {0x90,0x7f,0xc9,0xe0,0xfa,0x70,0x03,0x02,0x0c,0x2d} },
+{ 14, 0x0ab1, 0, {0x90,0x7f,0x96,0xe0,0xfa,0x90,0x7f,0x96,0x74,0x80,0x65,0x02,0xf0,0x90} },
+{  9, 0x0abf, 0, {0x7d,0xc0,0xe0,0xfa,0xba,0x2c,0x02,0x80,0x03} },
+{  3, 0x0ac8, 0, {0x02,0x0b,0x36} },
+{  5, 0x0acb, 0, {0x75,0x32,0x00,0x7b,0x00} },
+{  3, 0x0ad0, 0, {0xbb,0x64,0x00} },
+{  2, 0x0ad3, 0, {0x50,0x1c} },
+{ 14, 0x0ad5, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
+{ 13, 0x0ae3, 0, {0x04,0xd0,0x03,0xd0,0x02,0x90,0x88,0x0f,0xe0,0xf5,0x47,0x0b,0x80} },
+{  1, 0x0af0, 0, {0xdf} },
+{ 13, 0x0af1, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x07,0x1e,0x12,0x03,0xe1,0x12} },
+{ 12, 0x0afe, 0, {0x04,0xf7,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x75,0x6e,0x00,0x75} },
+{ 13, 0x0b0a, 0, {0x6f,0x01,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0x44,0xd0,0x05} },
+{  9, 0x0b17, 0, {0xd0,0x04,0xd0,0x02,0x75,0x70,0x4d,0x75,0x71} },
+{ 11, 0x0b20, 0, {0x0c,0x75,0x72,0x02,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
+{ 11, 0x0b2b, 0, {0x11,0x75,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x02,0x0c,0x2d} },
+{  3, 0x0b36, 0, {0xba,0x2a,0x3b} },
+{ 13, 0x0b39, 0, {0x90,0x7f,0x98,0x74,0x20,0xf0,0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12} },
+{ 14, 0x0b46, 0, {0x01,0xdd,0xd0,0x05,0xd0,0x04,0xd0,0x02,0x90,0x7f,0x98,0x74,0x28,0xf0} },
+{  2, 0x0b54, 0, {0x7b,0x00} },
+{  3, 0x0b56, 0, {0xbb,0x0a,0x00} },
+{  5, 0x0b59, 0, {0x40,0x03,0x02,0x0c,0x2d} },
+{ 14, 0x0b5e, 0, {0xc0,0x02,0xc0,0x03,0xc0,0x04,0xc0,0x05,0x12,0x01,0xdd,0xd0,0x05,0xd0} },
+{  8, 0x0b6c, 0, {0x04,0xd0,0x03,0xd0,0x02,0x0b,0x80,0xe2} },
+{  3, 0x0b74, 0, {0xba,0x2b,0x1a} },
+{  8, 0x0b77, 0, {0x90,0x7f,0xc9,0xe0,0xfb,0xbb,0x40,0x12} },
+{ 14, 0x0b7f, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x12,0x05,0xd0,0x05,0xd0,0x04,0xd0} },
+{  4, 0x0b8d, 0, {0x02,0x02,0x0c,0x2d} },
+{  3, 0x0b91, 0, {0xba,0x10,0x1f} },
+{ 14, 0x0b94, 0, {0x90,0x7f,0x96,0xe0,0xfb,0x90,0x7f,0x96,0x74,0x80,0x65,0x03,0xf0,0xc0} },
+{ 14, 0x0ba2, 0, {0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x3d,0xd0,0x05,0xd0,0x04,0xd0,0x02} },
+{  3, 0x0bb0, 0, {0x02,0x0c,0x2d} },
+{  3, 0x0bb3, 0, {0xba,0x11,0x12} },
+{ 14, 0x0bb6, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x6a,0xd0,0x05,0xd0,0x04,0xd0} },
+{  4, 0x0bc4, 0, {0x02,0x02,0x0c,0x2d} },
+{  3, 0x0bc8, 0, {0xba,0x12,0x12} },
+{ 14, 0x0bcb, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x10,0x8f,0xd0,0x05,0xd0,0x04,0xd0} },
+{  4, 0x0bd9, 0, {0x02,0x02,0x0c,0x2d} },
+{  3, 0x0bdd, 0, {0xba,0x13,0x0b} },
+{ 11, 0x0be0, 0, {0x90,0x7d,0xc1,0xe0,0xfb,0x90,0x88,0x00,0xf0,0x80,0x42} },
+{  3, 0x0beb, 0, {0xba,0x14,0x11} },
+{ 14, 0x0bee, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x11,0xdd,0xd0,0x05,0xd0,0x04,0xd0} },
+{  3, 0x0bfc, 0, {0x02,0x80,0x2e} },
+{  3, 0x0bff, 0, {0xba,0x15,0x1d} },
+{ 12, 0x0c02, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x75,0x90,0x7d,0xc2,0xe0,0xf5,0x76} },
+{ 14, 0x0c0e, 0, {0xc0,0x02,0xc0,0x04,0xc0,0x05,0x12,0x13,0xfe,0xd0,0x05,0xd0,0x04,0xd0} },
+{  3, 0x0c1c, 0, {0x02,0x80,0x0e} },
+{  3, 0x0c1f, 0, {0xba,0x16,0x0b} },
+{ 11, 0x0c22, 0, {0xc0,0x04,0xc0,0x05,0x12,0x13,0xa3,0xd0,0x05,0xd0,0x04} },
+{ 11, 0x0c2d, 0, {0x90,0x7f,0xc9,0xe4,0xf0,0x75,0x31,0x00,0x02,0x09,0x2a} },
+{  1, 0x0c38, 0, {0x22} },
+{  7, 0x0c39, 0, {0x53,0x55,0x50,0x45,0x4e,0x44,0x00} },
+{  7, 0x0c40, 0, {0x52,0x45,0x53,0x55,0x4d,0x45,0x00} },
+{  6, 0x0c47, 0, {0x20,0x56,0x6f,0x6c,0x20,0x00} },
+{ 13, 0x0c4d, 0, {0x44,0x41,0x42,0x55,0x53,0x42,0x20,0x76,0x31,0x2e,0x30,0x30,0x00} },
+{ 14, 0x0c5a, 0, {0xc0,0xe0,0xc0,0xf0,0xc0,0x82,0xc0,0x83,0xc0,0x02,0xc0,0x03,0xc0,0x04} },
+{ 14, 0x0c68, 0, {0xc0,0x05,0xc0,0x06,0xc0,0x07,0xc0,0x00,0xc0,0x01,0xc0,0xd0,0x75,0xd0} },
+{ 13, 0x0c76, 0, {0x00,0xc0,0x86,0x75,0x86,0x00,0xe5,0x91,0xc2,0xe4,0xf5,0x91,0x90} },
+{ 14, 0x0c83, 0, {0x7f,0xab,0x74,0x01,0xf0,0x90,0x7f,0xe8,0xe0,0xfa,0x90,0x7f,0xe9,0xe0} },
+{  6, 0x0c91, 0, {0xfb,0xbb,0x00,0x02,0x80,0x03} },
+{  3, 0x0c97, 0, {0x02,0x0d,0x38} },
+{  3, 0x0c9a, 0, {0xba,0x80,0x14} },
+{ 14, 0x0c9d, 0, {0x90,0x7f,0x00,0x74,0x01,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5} },
+{  6, 0x0cab, 0, {0x74,0x02,0xf0,0x02,0x0e,0xcd} },
+{  5, 0x0cb1, 0, {0xba,0x82,0x02,0x80,0x03} },
+{  3, 0x0cb6, 0, {0x02,0x0d,0x1d} },
+{  8, 0x0cb9, 0, {0x90,0x7f,0xec,0xe0,0xfc,0xbc,0x01,0x00} },
+{  2, 0x0cc1, 0, {0x40,0x21} },
+{  6, 0x0cc3, 0, {0xc3,0x74,0x07,0x9c,0x40,0x1b} },
+{ 14, 0x0cc9, 0, {0xec,0x24,0xff,0x25,0xe0,0xfd,0x24,0xc6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
+{ 13, 0x0cd7, 0, {0x83,0xe0,0xfd,0x53,0x05,0x01,0x90,0x7f,0x00,0xed,0xf0,0x80,0x2b} },
+{  3, 0x0ce4, 0, {0xbc,0x81,0x00} },
+{  2, 0x0ce7, 0, {0x40,0x21} },
+{  6, 0x0ce9, 0, {0xc3,0x74,0x87,0x9c,0x40,0x1b} },
+{ 14, 0x0cef, 0, {0xec,0x24,0x7f,0x25,0xe0,0xfc,0x24,0xb6,0xf5,0x82,0xe4,0x34,0x7f,0xf5} },
+{ 13, 0x0cfd, 0, {0x83,0xe0,0xfc,0x53,0x04,0x01,0x90,0x7f,0x00,0xec,0xf0,0x80,0x05} },
+{  5, 0x0d0a, 0, {0x90,0x7f,0x00,0xe4,0xf0} },
+{ 14, 0x0d0f, 0, {0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74,0x02,0xf0,0x02,0x0e,0xcd} },
+{  5, 0x0d1d, 0, {0xba,0x81,0x02,0x80,0x03} },
+{  3, 0x0d22, 0, {0x02,0x0e,0xc5} },
+{ 14, 0x0d25, 0, {0x90,0x7f,0x00,0xe4,0xf0,0x90,0x7f,0x01,0xe4,0xf0,0x90,0x7f,0xb5,0x74} },
+{  5, 0x0d33, 0, {0x02,0xf0,0x02,0x0e,0xcd} },
+{  3, 0x0d38, 0, {0xbb,0x01,0x2d} },
+{  6, 0x0d3b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
+{  3, 0x0d41, 0, {0xba,0x02,0x11} },
+{ 13, 0x0d44, 0, {0x75,0x59,0x00,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
+{  4, 0x0d51, 0, {0x02,0x02,0x0e,0xcd} },
+{  5, 0x0d55, 0, {0xba,0x21,0x02,0x80,0x03} },
+{  3, 0x0d5a, 0, {0x02,0x0e,0xcd} },
+{ 11, 0x0d5d, 0, {0x75,0x37,0x01,0x90,0x7f,0xc5,0xe4,0xf0,0x02,0x0e,0xcd} },
+{  3, 0x0d68, 0, {0xbb,0x03,0x1f} },
+{  6, 0x0d6b, 0, {0xba,0x00,0x03,0x02,0x0e,0xcd} },
+{  5, 0x0d71, 0, {0xba,0x02,0x02,0x80,0x03} },
+{  3, 0x0d76, 0, {0x02,0x0e,0xcd} },
+{ 13, 0x0d79, 0, {0x75,0x59,0x01,0xc0,0x02,0xc0,0x03,0x12,0x0e,0xf0,0xd0,0x03,0xd0} },
+{  4, 0x0d86, 0, {0x02,0x02,0x0e,0xcd} },
+{  3, 0x0d8a, 0, {0xbb,0x06,0x54} },
+{  5, 0x0d8d, 0, {0xba,0x80,0x02,0x80,0x03} },
+{  3, 0x0d92, 0, {0x02,0x0e,0xc5} },
+{  8, 0x0d95, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x01,0x15} },
+{ 12, 0x0d9d, 0, {0x7c,0xfb,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
+{  9, 0x0da9, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
+{ 10, 0x0db2, 0, {0x90,0x7f,0xeb,0xe0,0xfc,0xbc,0x02,0x02,0x80,0x03} },
+{  3, 0x0dbc, 0, {0x02,0x0e,0xc5} },
+{ 10, 0x0dbf, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x02,0x80,0x03} },
+{  3, 0x0dc9, 0, {0x02,0x0e,0xc5} },
+{ 12, 0x0dcc, 0, {0x7c,0x3b,0x7d,0x0f,0x8d,0x06,0x7f,0x00,0x90,0x7f,0xd4,0xee} },
+{  9, 0x0dd8, 0, {0xf0,0x90,0x7f,0xd5,0xec,0xf0,0x02,0x0e,0xcd} },
+{  6, 0x0de1, 0, {0xbb,0x07,0x03,0x02,0x0e,0xc5} },
+{  3, 0x0de7, 0, {0xbb,0x08,0x10} },
+{ 13, 0x0dea, 0, {0xac,0x48,0x90,0x7f,0x00,0xec,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
+{  3, 0x0df7, 0, {0x02,0x0e,0xcd} },
+{  3, 0x0dfa, 0, {0xbb,0x09,0x31} },
+{  5, 0x0dfd, 0, {0xba,0x00,0x02,0x80,0x03} },
+{  3, 0x0e02, 0, {0x02,0x0e,0xc5} },
+{ 14, 0x0e05, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xc3,0x74,0x01,0x9c,0x50,0x03,0x02,0x0e,0xc5} },
+{  8, 0x0e13, 0, {0x90,0x7f,0xea,0xe0,0xfc,0xbc,0x00,0x0a} },
+{ 10, 0x0e1b, 0, {0x90,0x17,0x21,0xe4,0xf0,0x90,0x17,0x22,0xe4,0xf0} },
+{  9, 0x0e25, 0, {0x90,0x7f,0xea,0xe0,0xf5,0x48,0x02,0x0e,0xcd} },
+{  3, 0x0e2e, 0, {0xbb,0x0a,0x27} },
+{  5, 0x0e31, 0, {0xba,0x81,0x02,0x80,0x03} },
+{  3, 0x0e36, 0, {0x02,0x0e,0xc5} },
+{ 14, 0x0e39, 0, {0x90,0x7f,0xec,0xe0,0xfa,0x24,0x20,0xfa,0xe4,0x34,0x17,0xfc,0x8a,0x82} },
+{ 14, 0x0e47, 0, {0x8c,0x83,0xe0,0xfa,0x90,0x7f,0x00,0xf0,0x90,0x7f,0xb5,0x74,0x01,0xf0} },
+{  3, 0x0e55, 0, {0x02,0x0e,0xcd} },
+{  5, 0x0e58, 0, {0xbb,0x0b,0x02,0x80,0x03} },
+{  3, 0x0e5d, 0, {0x02,0x0e,0xa9} },
+{ 13, 0x0e60, 0, {0x90,0x17,0x20,0xe4,0xf0,0x90,0x7f,0xec,0xe0,0xfa,0xba,0x01,0x1a} },
+{  8, 0x0e6d, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x12} },
+{ 14, 0x0e75, 0, {0x90,0x7f,0xea,0xe0,0xfa,0x90,0x17,0x21,0xf0,0xc0,0x03,0x12,0x04,0xe2} },
+{  4, 0x0e83, 0, {0xd0,0x03,0x80,0x46} },
+{  8, 0x0e87, 0, {0x90,0x7f,0xec,0xe0,0xfa,0xba,0x02,0x3e} },
+{  8, 0x0e8f, 0, {0x90,0x7f,0xed,0xe0,0xfa,0xba,0x00,0x36} },
+{ 13, 0x0e97, 0, {0xc0,0x03,0x12,0x04,0xef,0xd0,0x03,0x90,0x7f,0xea,0xe0,0xfa,0x90} },
+{  5, 0x0ea4, 0, {0x17,0x22,0xf0,0x80,0x24} },
+{  5, 0x0ea9, 0, {0xbb,0x12,0x02,0x80,0x17} },
+{  5, 0x0eae, 0, {0xbb,0x81,0x02,0x80,0x0d} },
+{  5, 0x0eb3, 0, {0xbb,0x83,0x02,0x80,0x08} },
+{  5, 0x0eb8, 0, {0xbb,0x82,0x02,0x80,0x03} },
+{  3, 0x0ebd, 0, {0xbb,0x84,0x05} },
+{  5, 0x0ec0, 0, {0x12,0x06,0x4e,0x80,0x08} },
+{  8, 0x0ec5, 0, {0x90,0x7f,0xb4,0x74,0x03,0xf0,0x80,0x06} },
+{  6, 0x0ecd, 0, {0x90,0x7f,0xb4,0x74,0x02,0xf0} },
+{  2, 0x0ed3, 0, {0xd0,0x86} },
+{ 14, 0x0ed5, 0, {0xd0,0xd0,0xd0,0x01,0xd0,0x00,0xd0,0x07,0xd0,0x06,0xd0,0x05,0xd0,0x04} },
+{ 13, 0x0ee3, 0, {0xd0,0x03,0xd0,0x02,0xd0,0x83,0xd0,0x82,0xd0,0xf0,0xd0,0xe0,0x32} },
+{ 11, 0x0ef0, 0, {0x90,0x7f,0xec,0xe0,0xf5,0x5a,0xc3,0x94,0x01,0x40,0x1d} },
+{  7, 0x0efb, 0, {0xc3,0x74,0x07,0x95,0x5a,0x40,0x16} },
+{ 13, 0x0f02, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xc6,0xf5,0x82,0xe4,0x34} },
+{  9, 0x0f0f, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0,0x80,0x22} },
+{  7, 0x0f18, 0, {0xc3,0xe5,0x5a,0x94,0x81,0x40,0x1b} },
+{  7, 0x0f1f, 0, {0xc3,0x74,0x87,0x95,0x5a,0x40,0x14} },
+{ 13, 0x0f26, 0, {0xe5,0x5a,0x24,0xff,0x25,0xe0,0xfa,0x24,0xb6,0xf5,0x82,0xe4,0x34} },
+{  7, 0x0f33, 0, {0x7f,0xf5,0x83,0xaa,0x59,0xea,0xf0} },
+{  1, 0x0f3a, 0, {0x22} },
+{ 14, 0x0f3b, 0, {0x09,0x02,0xba,0x00,0x03,0x01,0x00,0x40,0x00,0x09,0x04,0x00,0x00,0x00} },
+{ 14, 0x0f49, 0, {0x01,0x01,0x00,0x00,0x09,0x24,0x01,0x00,0x01,0x3d,0x00,0x01,0x01,0x0c} },
+{ 14, 0x0f57, 0, {0x24,0x02,0x01,0x10,0x07,0x00,0x02,0x03,0x00,0x00,0x00,0x0d,0x24,0x06} },
+{ 14, 0x0f65, 0, {0x03,0x01,0x02,0x15,0x00,0x03,0x00,0x03,0x00,0x00,0x09,0x24,0x03,0x02} },
+{ 14, 0x0f73, 0, {0x01,0x01,0x00,0x01,0x00,0x09,0x24,0x03,0x04,0x02,0x03,0x00,0x03,0x00} },
+{ 14, 0x0f81, 0, {0x09,0x24,0x03,0x05,0x03,0x06,0x00,0x01,0x00,0x09,0x04,0x01,0x00,0x00} },
+{ 14, 0x0f8f, 0, {0x01,0x02,0x00,0x00,0x09,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00,0x07} },
+{ 14, 0x0f9d, 0, {0x24,0x01,0x02,0x01,0x01,0x00,0x0b,0x24,0x02,0x01,0x02,0x02,0x10,0x01} },
+{ 14, 0x0fab, 0, {0x80,0xbb,0x00,0x09,0x05,0x88,0x05,0x00,0x01,0x01,0x00,0x00,0x07,0x25} },
+{ 14, 0x0fb9, 0, {0x01,0x00,0x00,0x00,0x00,0x09,0x04,0x02,0x00,0x02,0x00,0x00,0x00,0x00} },
+{ 14, 0x0fc7, 0, {0x07,0x05,0x82,0x02,0x40,0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00} },
+{ 14, 0x0fd5, 0, {0x09,0x04,0x02,0x01,0x03,0x00,0x00,0x00,0x00,0x07,0x05,0x82,0x02,0x40} },
+{ 14, 0x0fe3, 0, {0x00,0x00,0x07,0x05,0x02,0x02,0x40,0x00,0x00,0x09,0x05,0x89,0x05,0xa0} },
+{ 10, 0x0ff1, 0, {0x01,0x01,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00} },
+{ 14, 0x0ffb, 0, {0x12,0x01,0x00,0x01,0x00,0x00,0x00,0x40,0x47,0x05,0x99,0x99,0x00,0x01} },
+{ 14, 0x1009, 0, {0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x02,0xba} },
+{  4, 0x1017, 0, {0x00,0x03,0x01,0x00} },
+{  2, 0x101b, 0, {0x7a,0x00} },
+{  3, 0x101d, 0, {0xba,0x05,0x00} },
+{  2, 0x1020, 0, {0x50,0x17} },
+{  8, 0x1022, 0, {0x90,0x7f,0xa5,0xe0,0xfb,0x30,0xe0,0x05} },
+{  5, 0x102a, 0, {0x90,0x00,0x01,0x80,0x0d} },
+{ 10, 0x102f, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xe4} },
+{  3, 0x1039, 0, {0x90,0x00,0x01} },
+{  1, 0x103c, 0, {0x22} },
+{ 14, 0x103d, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0x00,0x7d} },
+{  4, 0x104b, 0, {0x7e,0xeb,0x60,0x12} },
+{ 14, 0x104f, 0, {0x89,0x82,0x8a,0x83,0xe0,0xa3,0xa9,0x82,0xaa,0x83,0x8c,0x82,0x8d,0x83} },
+{  4, 0x105d, 0, {0xf0,0x0c,0xdb,0xee} },
+{  8, 0x1061, 0, {0x90,0x7d,0xc3,0xe0,0x90,0x7f,0xb9,0xf0} },
+{  1, 0x1069, 0, {0x22} },
+{ 14, 0x106a, 0, {0x90,0x7d,0xc1,0xe0,0xf9,0xa3,0xe0,0xfa,0xa3,0xe0,0xfb,0x7c,0xc4,0x7d} },
+{  4, 0x1078, 0, {0x7d,0xeb,0x60,0xe5} },
+{ 14, 0x107c, 0, {0x8c,0x82,0x8d,0x83,0xe0,0x0c,0x89,0x82,0x8a,0x83,0xf0,0xa3,0xa9,0x82} },
+{  4, 0x108a, 0, {0xaa,0x83,0xdb,0xee} },
+{  1, 0x108e, 0, {0x22} },
+{ 14, 0x108f, 0, {0x90,0x7f,0xa5,0x74,0x80,0xf0,0x05,0x86,0x90,0x7d,0xc1,0xe0,0x05,0x86} },
+{ 14, 0x109d, 0, {0xa3,0xf0,0x12,0x10,0x1b,0x90,0x7f,0xa6,0x05,0x86,0xa3,0xa3,0xe0,0xf9} },
+{  5, 0x10ab, 0, {0x60,0x16,0xa3,0x05,0x86} },
+{ 13, 0x10b0, 0, {0x90,0x7f,0xa6,0x05,0x86,0xe0,0xa3,0x05,0x86,0xf0,0xc0,0x01,0x12} },
+{  6, 0x10bd, 0, {0x10,0x1b,0xd0,0x01,0xd9,0xed} },
+{  6, 0x10c3, 0, {0x90,0x7f,0xa5,0x74,0x40,0xf0} },
+{  1, 0x10c9, 0, {0x22} },
+{  8, 0x10ca, 0, {0x90,0x88,0x02,0x74,0x01,0xf0,0x7a,0x00} },
+{  3, 0x10d2, 0, {0xba,0xff,0x00} },
+{  2, 0x10d5, 0, {0x50,0x0a} },
+{ 10, 0x10d7, 0, {0xc0,0x02,0x12,0x01,0xdd,0xd0,0x02,0x0a,0x80,0xf1} },
+{  1, 0x10e1, 0, {0x22} },
+{  5, 0x10e2, 0, {0xe5,0x6b,0xb4,0xc0,0x08} },
+{  8, 0x10e7, 0, {0x90,0x88,0x03,0xe5,0x6c,0xf0,0x80,0x06} },
+{  6, 0x10ef, 0, {0x90,0x88,0x02,0xe5,0x6c,0xf0} },
+{  4, 0x10f5, 0, {0x7a,0x00,0x7b,0x00} },
+{ 11, 0x10f9, 0, {0xc3,0xea,0x94,0x32,0xeb,0x64,0x80,0x94,0x80,0x50,0x07} },
+{  5, 0x1104, 0, {0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x1109, 0, {0x80,0xee} },
+{  1, 0x110b, 0, {0x22} },
+{ 10, 0x110c, 0, {0x90,0x88,0x03,0xe5,0x6d,0xf0,0x05,0x39,0x7a,0x00} },
+{  3, 0x1116, 0, {0xba,0x28,0x00} },
+{  2, 0x1119, 0, {0x50,0x03} },
+{  3, 0x111b, 0, {0x0a,0x80,0xf8} },
+{  5, 0x111e, 0, {0xe5,0x39,0xb4,0x10,0x08} },
+{  8, 0x1123, 0, {0x90,0x88,0x02,0x74,0xc0,0xf0,0x80,0x0e} },
+{  5, 0x112b, 0, {0xe5,0x39,0xb4,0x20,0x09} },
+{  9, 0x1130, 0, {0x90,0x88,0x02,0x74,0x80,0xf0,0x75,0x39,0x00} },
+{  2, 0x1139, 0, {0x7a,0x00} },
+{  3, 0x113b, 0, {0xba,0x28,0x00} },
+{  2, 0x113e, 0, {0x50,0x03} },
+{  3, 0x1140, 0, {0x0a,0x80,0xf8} },
+{  1, 0x1143, 0, {0x22} },
+{  4, 0x1144, 0, {0xe5,0x6f,0x60,0x02} },
+{  2, 0x1148, 0, {0x80,0x07} },
+{  7, 0x114a, 0, {0x7a,0x00,0x75,0x39,0x00,0x80,0x05} },
+{  5, 0x1151, 0, {0x7a,0x40,0x75,0x39,0x10} },
+{  9, 0x1156, 0, {0xe5,0x6e,0x2a,0xfa,0xe5,0x6e,0x25,0x39,0xf5} },
+{ 10, 0x115f, 0, {0x39,0x90,0x88,0x02,0x74,0x80,0x2a,0xf0,0x7a,0x00} },
+{  8, 0x1169, 0, {0xc3,0xea,0x64,0x80,0x94,0xa8,0x50,0x03} },
+{  3, 0x1171, 0, {0x0a,0x80,0xf5} },
+{  1, 0x1174, 0, {0x22} },
+{  6, 0x1175, 0, {0xaa,0x70,0xab,0x71,0xac,0x72} },
+{ 12, 0x117b, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x12,0x14,0xee,0xfd,0x60,0x18} },
+{ 13, 0x1187, 0, {0x8d,0x6d,0xc0,0x02,0xc0,0x03,0xc0,0x04,0x12,0x11,0x0c,0xd0,0x04} },
+{  9, 0x1194, 0, {0xd0,0x03,0xd0,0x02,0x0a,0xba,0x00,0x01,0x0b} },
+{  2, 0x119d, 0, {0x80,0xdc} },
+{  1, 0x119f, 0, {0x22} },
+{ 13, 0x11a0, 0, {0xe5,0x73,0xc4,0x54,0x0f,0xfa,0x53,0x02,0x0f,0xc3,0x74,0x09,0x9a} },
+{  2, 0x11ad, 0, {0x50,0x06} },
+{  6, 0x11af, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
+{  4, 0x11b5, 0, {0x74,0x30,0x2a,0xfb} },
+{ 12, 0x11b9, 0, {0x8b,0x6d,0xc0,0x03,0x12,0x11,0x0c,0xd0,0x03,0xaa,0x73,0x53} },
+{  8, 0x11c5, 0, {0x02,0x0f,0xc3,0x74,0x09,0x9a,0x50,0x06} },
+{  6, 0x11cd, 0, {0x74,0x37,0x2a,0xfb,0x80,0x04} },
+{  4, 0x11d3, 0, {0x74,0x30,0x2a,0xfb} },
+{  5, 0x11d7, 0, {0x8b,0x6d,0x12,0x11,0x0c} },
+{  1, 0x11dc, 0, {0x22} },
+{  7, 0x11dd, 0, {0x90,0x7d,0xc3,0xe0,0xfa,0x60,0x0f} },
+{ 12, 0x11e4, 0, {0x90,0x7d,0xc1,0xe0,0xf5,0x6e,0x90,0x7d,0xc2,0xe0,0xf5,0x6f} },
+{  3, 0x11f0, 0, {0x12,0x11,0x44} },
+{ 12, 0x11f3, 0, {0x90,0x7d,0xff,0xe4,0xf0,0x75,0x70,0xc4,0x75,0x71,0x7d,0x75} },
+{  5, 0x11ff, 0, {0x72,0x01,0x12,0x11,0x75} },
+{  1, 0x1204, 0, {0x22} },
+{  2, 0x1205, 0, {0x7a,0x04} },
+{  3, 0x1207, 0, {0xba,0x40,0x00} },
+{  2, 0x120a, 0, {0x50,0x36} },
+{ 14, 0x120c, 0, {0xea,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfb,0x7c,0x00} },
+{  3, 0x121a, 0, {0xbc,0x08,0x00} },
+{  2, 0x121d, 0, {0x50,0x20} },
+{  6, 0x121f, 0, {0x8b,0x05,0xed,0x30,0xe7,0x0b} },
+{ 11, 0x1225, 0, {0x90,0x7f,0x96,0x74,0x42,0xf0,0x74,0xc3,0xf0,0x80,0x08} },
+{  8, 0x1230, 0, {0x90,0x7f,0x96,0xe4,0xf0,0x74,0x81,0xf0} },
+{  7, 0x1238, 0, {0xeb,0x25,0xe0,0xfb,0x0c,0x80,0xdb} },
+{  3, 0x123f, 0, {0x0a,0x80,0xc5} },
+{  1, 0x1242, 0, {0x22} },
+{  4, 0x1243, 0, {0x7a,0x00,0x7b,0xef} },
+{  3, 0x1247, 0, {0xba,0x10,0x00} },
+{  2, 0x124a, 0, {0x50,0x20} },
+{ 14, 0x124c, 0, {0x74,0x11,0x2b,0xfb,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0x8c,0x82,0x8d} },
+{ 14, 0x125a, 0, {0x83,0xe4,0xf0,0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe4} },
+{  4, 0x1268, 0, {0xf0,0x0a,0x80,0xdb} },
+{  1, 0x126c, 0, {0x22} },
+{ 14, 0x126d, 0, {0x74,0xf8,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x127b, 0, {0x74,0xf9,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x1289, 0, {0x74,0xfa,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x1297, 0, {0x74,0xfb,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{ 14, 0x12a5, 0, {0x74,0xff,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0xe4,0xf0} },
+{  1, 0x12b3, 0, {0x22} },
+{ 14, 0x12b4, 0, {0x12,0x03,0xcb,0x12,0x12,0x6d,0x7a,0xc0,0x7b,0x87,0x7c,0x01,0x74,0x01} },
+{ 14, 0x12c2, 0, {0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74} },
+{ 14, 0x12d0, 0, {0x01,0x12,0x14,0xbf,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e} },
+{ 14, 0x12de, 0, {0x83,0x8f,0xf0,0x74,0x06,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b} },
+{ 14, 0x12ec, 0, {0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74} },
+{ 14, 0x12fa, 0, {0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0} },
+{ 14, 0x1308, 0, {0x74,0x0b,0x12,0x14,0xbf,0x74,0x01,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07} },
+{ 14, 0x1316, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x74,0x08,0x12,0x14,0xbf,0x74,0x01,0x2d} },
+{ 14, 0x1324, 0, {0xfa,0xe4,0x3e,0xfb,0x8f,0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x01} },
+{ 14, 0x1332, 0, {0x12,0x14,0xbf,0x2a,0xfd,0xe4,0x3b,0xfe,0x8c,0x07,0x8a,0x82,0x8b,0x83} },
+{ 14, 0x1340, 0, {0x8c,0xf0,0xe4,0x12,0x14,0xbf,0x74,0x01,0x2d,0xfa,0xe4,0x3e,0xfb,0x8f} },
+{ 14, 0x134e, 0, {0x04,0x8d,0x82,0x8e,0x83,0x8f,0xf0,0x74,0x03,0x12,0x14,0xbf,0x7d,0x00} },
+{  3, 0x135c, 0, {0xbd,0x06,0x00} },
+{  2, 0x135f, 0, {0x50,0x12} },
+{ 11, 0x1361, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0x0a,0xba,0x00,0x01,0x0b} },
+{  7, 0x136c, 0, {0xe4,0x12,0x14,0xbf,0x0d,0x80,0xe9} },
+{ 13, 0x1373, 0, {0x8a,0x82,0x8b,0x83,0x8c,0xf0,0xe5,0x74,0x12,0x14,0xbf,0x74,0xf9} },
+{ 14, 0x1380, 0, {0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x0f,0xf0,0x74} },
+{ 14, 0x138e, 0, {0xfe,0x24,0x00,0xf5,0x82,0x74,0x03,0x34,0x84,0xf5,0x83,0x74,0x01,0xf0} },
+{  6, 0x139c, 0, {0x12,0x03,0xe1,0x12,0x04,0xf7} },
+{  1, 0x13a2, 0, {0x22} },
+{ 13, 0x13a3, 0, {0x90,0x7d,0xc1,0xe0,0xfa,0x24,0x00,0xfb,0xe4,0x34,0x19,0xfc,0x90} },
+{ 14, 0x13b0, 0, {0x7d,0xc2,0xe0,0xfd,0x8b,0x82,0x8c,0x83,0xf0,0x75,0xf0,0x11,0xea,0xa4} },
+{  3, 0x13be, 0, {0xfa,0x7b,0x00} },
+{  3, 0x13c1, 0, {0xbb,0x10,0x00} },
+{  2, 0x13c4, 0, {0x50,0x24} },
+{ 14, 0x13c6, 0, {0xea,0x24,0x00,0xfc,0xe4,0x34,0x18,0xfd,0xeb,0x2c,0xfc,0xe4,0x3d,0xfd} },
+{ 14, 0x13d4, 0, {0x74,0x04,0x2b,0x24,0xc0,0xf5,0x82,0xe4,0x34,0x7d,0xf5,0x83,0xe0,0xfe} },
+{  8, 0x13e2, 0, {0x8c,0x82,0x8d,0x83,0xf0,0x0b,0x80,0xd7} },
+{ 14, 0x13ea, 0, {0xea,0x24,0x00,0xfa,0xe4,0x34,0x18,0xfb,0x74,0x10,0x2a,0xf5,0x82,0xe4} },
+{  5, 0x13f8, 0, {0x3b,0xf5,0x83,0xe4,0xf0} },
+{  1, 0x13fd, 0, {0x22} },
+{  4, 0x13fe, 0, {0xe5,0x76,0x60,0x02} },
+{  2, 0x1402, 0, {0x80,0x16} },
+{ 12, 0x1404, 0, {0x74,0x0f,0x55,0x75,0xfa,0x8a,0x75,0x24,0x00,0xf5,0x82,0xe4} },
+{ 10, 0x1410, 0, {0x34,0x19,0xf5,0x83,0xe0,0xf5,0x74,0x12,0x12,0xb4} },
+{ 10, 0x141a, 0, {0x12,0x10,0xca,0x75,0x6e,0x00,0x75,0x6f,0x00,0x12} },
+{  6, 0x1424, 0, {0x11,0x44,0x75,0x70,0xb9,0x75} },
+{  6, 0x142a, 0, {0x71,0x14,0x75,0x72,0x02,0x12} },
+{ 11, 0x1430, 0, {0x11,0x75,0xe5,0x76,0xb4,0x02,0x04,0x74,0x01,0x80,0x01} },
+{  1, 0x143b, 0, {0xe4} },
+{  3, 0x143c, 0, {0xfa,0x70,0x0f} },
+{ 12, 0x143f, 0, {0x74,0x01,0x25,0x75,0xf5,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0} },
+{  3, 0x144b, 0, {0x02,0x80,0x0a} },
+{ 10, 0x144e, 0, {0x85,0x75,0x73,0xc0,0x02,0x12,0x11,0xa0,0xd0,0x02} },
+{ 12, 0x1458, 0, {0x75,0x6e,0x00,0x75,0x6f,0x01,0xc0,0x02,0x12,0x11,0x44,0xd0} },
+{  4, 0x1464, 0, {0x02,0xea,0x70,0x1a} },
+{ 13, 0x1468, 0, {0x75,0xf0,0x11,0xe5,0x75,0xa4,0xfa,0x24,0x00,0xfa,0xe4,0x34,0x18} },
+{  9, 0x1475, 0, {0xfb,0x8a,0x70,0x8b,0x71,0x75,0x72,0x01,0x12} },
+{  4, 0x147e, 0, {0x11,0x75,0x80,0x36} },
+{  2, 0x1482, 0, {0x7a,0x00} },
+{  3, 0x1484, 0, {0xba,0x10,0x00} },
+{  2, 0x1487, 0, {0x50,0x2f} },
+{ 13, 0x1489, 0, {0xea,0x24,0x00,0xf5,0x82,0xe4,0x34,0x19,0xf5,0x83,0xe0,0xfb,0xe5} },
+{  4, 0x1496, 0, {0x75,0xb5,0x03,0x1b} },
+{ 14, 0x149a, 0, {0x75,0xf0,0x11,0xea,0xa4,0xfb,0x24,0x00,0xfb,0xe4,0x34,0x18,0xfc,0x8b} },
+{  9, 0x14a8, 0, {0x70,0x8c,0x71,0x75,0x72,0x01,0xc0,0x02,0x12} },
+{  4, 0x14b1, 0, {0x11,0x75,0xd0,0x02} },
+{  3, 0x14b5, 0, {0x0a,0x80,0xcc} },
+{  1, 0x14b8, 0, {0x22} },
+{  6, 0x14b9, 0, {0x50,0x72,0x6f,0x67,0x20,0x00} },
+{ 14, 0x14bf, 0, {0xc8,0xc0,0xe0,0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0b,0x14,0x60,0x0f,0x14} },
+{  7, 0x14cd, 0, {0x60,0x11,0x14,0x60,0x12,0x80,0x15} },
+{  7, 0x14d4, 0, {0xd0,0xe0,0xa8,0x82,0xf6,0x80,0x0e} },
+{  5, 0x14db, 0, {0xd0,0xe0,0xf0,0x80,0x09} },
+{  4, 0x14e0, 0, {0xd0,0xe0,0x80,0x05} },
+{  5, 0x14e4, 0, {0xd0,0xe0,0xa8,0x82,0xf2} },
+{  4, 0x14e9, 0, {0xc8,0xd0,0xe0,0xc8} },
+{  1, 0x14ed, 0, {0x22} },
+{ 14, 0x14ee, 0, {0xc8,0xc0,0xe0,0xe5,0xf0,0x60,0x0d,0x14,0x60,0x0f,0x14,0x60,0x0f,0x14} },
+{  6, 0x14fc, 0, {0x60,0x10,0x74,0xff,0x80,0x0f} },
+{  5, 0x1502, 0, {0xa8,0x82,0xe6,0x80,0x0a} },
+{  3, 0x1507, 0, {0xe0,0x80,0x07} },
+{  4, 0x150a, 0, {0xe4,0x93,0x80,0x03} },
+{  3, 0x150e, 0, {0xa8,0x82,0xe2} },
+{  4, 0x1511, 0, {0xf8,0xd0,0xe0,0xc8} },
+{  1, 0x1515, 0, {0x22} },
+{  0, 0x0000, 1, {0} }
+
+};
+
+static unsigned char bitstream[] = {
+
+0x00,0x09,0x0F,0xF0,0x0F,0xF0,0x0F,0xF0, 0x0F,0xF0,0x00,0x00,0x01,0x61,0x00,0x0D,
+0x64,0x61,0x62,0x75,0x73,0x62,0x74,0x72, 0x2E,0x6E,0x63,0x64,0x00,0x62,0x00,0x0B,
+0x73,0x31,0x30,0x78,0x6C,0x76,0x71,0x31, 0x30,0x30,0x00,0x63,0x00,0x0B,0x31,0x39,
+0x39,0x39,0x2F,0x30,0x39,0x2F,0x32,0x34, 0x00,0x64,0x00,0x09,0x31,0x30,0x3A,0x34,
+0x32,0x3A,0x34,0x36,0x00,0x65,0x00,0x00, 0x2E,0xC0,0xFF,0x20,0x17,0x5F,0x9F,0x5B,
+0xFE,0xFB,0xBB,0xB7,0xBB,0xBB,0xFB,0xBF, 0xAF,0xEF,0xFB,0xDF,0xB7,0xFB,0xFB,0x7F,
+0xBF,0xB7,0xEF,0xF2,0xFF,0xFB,0xFE,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xBF,0xFF,0xFF,
+0xFF,0xFF,0xAF,0xFF,0xFA,0xFF,0xFF,0xFF, 0xC9,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xA3,0xFF,0xFB,
+0xFE,0xFF,0xBF,0xEF,0xE3,0xFE,0xFF,0xBF, 0xE3,0xFE,0xFF,0xBF,0x6F,0xFB,0xF6,0xFF,
+0xBF,0xFF,0x47,0xFF,0xFF,0x9F,0xEE,0xF9, 0xFE,0xCF,0x9F,0xEF,0xFB,0xCF,0x9B,0xEE,
+0xF8,0xFE,0xEF,0x8F,0xEE,0xFB,0xFE,0x0B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xBF,0xFF,0xFF,0xFB,0xFF,0xFF, 0xBF,0xFF,0xFF,0xFC,0x17,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFB,0xFF,0xFF,0x7F,0xFF,0xFF,
+0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x5F,0xFF, 0xFF,0xFD,0xFF,0xFF,0xDB,0xFF,0xFD,0xFF,
+0x77,0xFF,0xFD,0xFF,0xFF,0xDF,0xFE,0xFD, 0xFF,0xFF,0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE1,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xE3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,
+0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x67,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x7F,0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xDF,0xFF,0xFF,0xFF,0x2F,0xFF,
+0xF3,0xFD,0xFF,0x7F,0xDE,0xF7,0xFD,0xFF, 0x7F,0xF7,0x7D,0xFF,0x7F,0xDF,0xF7,0xBD,
+0xFF,0x7F,0xFF,0x1F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xEF,0xFB,
+0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF, 0x3F,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,
+0x9F,0xE7,0xFA,0x7F,0x9F,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xFF,0xFC,0x7F,0xBF,0xBF,
+0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xB7, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
+0xFF,0xE0,0xFD,0xF9,0xFE,0x7F,0x9F,0xE7, 0xF9,0xFE,0x7F,0x9D,0xF9,0xFE,0x7D,0x9D,
+0xE7,0xF9,0xFE,0x7F,0x9F,0xED,0xED,0xFF, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
+0xDF,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF, 0x7F,0xDF,0xFF,0x9B,0xFF,0xEF,0xFB,0xFE,
+0xFB,0xBF,0xEF,0xBB,0xFE,0xFF,0xAF,0xBB, 0xBE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFF,
+0xB7,0xBF,0xDB,0xF6,0xBD,0xBF,0x6B,0xDB, 0xF6,0xF9,0xBF,0x5B,0xD6,0xF9,0xBF,0x6F,
+0xDB,0xF6,0xFD,0xBF,0xFF,0x0E,0xFF,0xFF, 0xFF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0x7F,
+0xF7,0xBD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xDF,0x9F,0xFF,0xFF,0xFF,0xFE,0xFF,
+0xFF,0xEF,0xFE,0xFE,0xFF,0xFF,0x77,0xFF, 0xFB,0xFB,0xFF,0xFF,0xFF,0xFF,0xF8,0x3F,
+0xFF,0xFD,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xF4,0x7F,0xFF,0xFE,0xFD, 0xBE,0xFF,0xDF,0xFE,0xFF,0xFF,0xEF,0x7F,
+0xFF,0xCF,0xFF,0xCF,0xFF,0xFF,0xFF,0xDF, 0xE6,0xFF,0xFF,0x7F,0xDF,0xF7,0xDD,0x7F,
+0x7F,0xDF,0xF7,0xFF,0x7F,0xDF,0xD7,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFF,0xCD,0xFF,0xF2,
+0xFF,0xFF,0x4F,0x7F,0xF4,0xFF,0xFF,0xFF, 0xE7,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xBB,0xFF,0xEF,0xFF,0xFE,0xFF, 0xFF,0xFF,0xEF,0xFF,0xFF,0xEF,0xFF,0xFB,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x65, 0xEF,0xFF,0xFF,0x7F,0xFF,0xFD,0xEF,0xFF,
+0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xCF,0xDF,0xFE,0xFF,
+0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xF3,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFE,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xEF,0xEB,0xFF,0xFE,0xBF,0xFF, 0xEB,0xFF,0xFC,0x7F,0xFF,0xFF,0xFF,0xEE,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xD6,0xFF,0xFD,0xBF,0xFF,0xFB,0xFF,0xFE,
+0xFD,0xFF,0xFF,0xFD,0xEF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xDE,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0x7F,0xBF, 0xFF,0x5F,0xDF,0xFF,0xFF,0xBF,0x77,0xFF,
+0xFF,0xFF,0x7F,0xD7,0xFF,0xFF,0xFF,0xFF, 0xFF,0xC3,0xFF,0xFF,0xFF,0xFF,0xDF,0xEF,
+0xFF,0xFF,0xFE,0xFB,0xFF,0xFF,0xDF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xB7,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xAF,0x7F,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xBF,0xDF,0xF3,0xFD,0xFB,0xFF,0x5B,
+0xFD,0xFF,0xBF,0xEF,0xF7,0xFF,0xFF,0x7D, 0xFF,0xFF,0xFF,0xFF,0xF8,0x3B,0xFF,0xBF,
+0x6F,0xFF,0xFE,0xFF,0xBF,0xFF,0xEB,0x7D, 0xFF,0xEF,0xFB,0xFE,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xF2,0x7F,0xFC,0xFF,0x3F,0xDF,0xED, 0xFE,0xFF,0xFF,0xFF,0xFF,0xEF,0x5F,0xF7,
+0xB5,0xFF,0xEF,0xFF,0xFF,0xFF,0xE0,0x3F, 0x9F,0x9E,0xFF,0xFF,0xEF,0xFF,0xDF,0xFF,
+0xBF,0x5F,0xBF,0xCF,0xF3,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x69,0xAF,0x33,0xFD,0xFF,
+0xFB,0xFF,0xFF,0xFF,0xFF,0xFC,0xFF,0x7F, 0xD9,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xF5,
+0xA3,0xDF,0x6E,0xDE,0xFF,0xFF,0xBD,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFE,0xE7,0xFD,
+0xFF,0xFF,0xFF,0xF9,0xEF,0xC6,0xFE,0xB7, 0xAD,0xE5,0xF9,0xFF,0xFF,0xFF,0xCF,0xFF,
+0xFF,0xFF,0xCD,0xFB,0x7F,0xFF,0xFF,0xFF, 0xF9,0xF6,0x0F,0xDF,0xEC,0xCF,0x7F,0xFF,
+0xFB,0x7F,0xFF,0xFF,0xFF,0xFD,0xFF,0xFE, 0xF9,0xFD,0x7F,0xFF,0x7F,0xFF,0xF9,0x5B,
+0xFF,0x73,0xDC,0xFD,0x7B,0xDF,0xFF,0xFF, 0xFF,0x7B,0xFF,0xFF,0xF7,0x53,0xD6,0xFF,
+0xFF,0xFF,0xFF,0xD8,0x9F,0xFE,0xFF,0xEF, 0x7F,0xEE,0xFF,0xFF,0xFF,0xFB,0xED,0xED,
+0xFD,0xFF,0xFE,0xFF,0xFF,0xFB,0x7F,0xFF, 0xE2,0x7F,0xFF,0x6F,0xD8,0x57,0xF7,0xFF,
+0xFF,0xFF,0xDF,0xFF,0xE8,0xFF,0xFF,0xFD, 0xFF,0xFF,0xFC,0x7F,0xFF,0xE4,0xFF,0xFB,
+0xEF,0xFB,0xFE,0xDF,0xB7,0xED,0xFF,0xFE, 0xDF,0x7F,0xFF,0xFE,0x7F,0xB7,0xFF,0xFF,
+0xFF,0xFF,0x89,0xFF,0xFF,0xCF,0xF3,0xFE, 0x7F,0xFF,0xEF,0xFF,0xFE,0x7E,0x7F,0xFB,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF1, 0xFF,0xEB,0x7A,0xD5,0xBF,0x6F,0xDB,0xBE,
+0xFD,0xB7,0xD8,0xF6,0xE5,0xBF,0x6F,0xFB, 0xFE,0xF5,0xBD,0x7E,0x06,0xFF,0xDF,0xF7,
+0xFB,0xF6,0xFF,0x3F,0xFF,0xDB,0xFF,0xFF, 0x6F,0xFB,0xF7,0xFF,0xFF,0xFF,0xFB,0xFE,
+0xF7,0xAF,0xFF,0xB7,0xED,0xEF,0xF7,0xFE, 0xFF,0xFF,0xDF,0xFF,0xFE,0xFF,0xEF,0xFF,
+0xFF,0xFF,0xFF,0xBF,0xF7,0xFC,0x1F,0xEE, 0xFB,0xFE,0xBD,0xFF,0x7F,0x5F,0xD7,0xFD,
+0xFB,0x43,0xFF,0xFF,0xFD,0xFF,0x5F,0xFF, 0xF7,0xFF,0xF9,0x3F,0xFF,0xCF,0xF3,0xFD,
+0xF7,0x7E,0xEF,0xA7,0xF9,0xFE,0x8F,0xA7, 0xE9,0xF3,0x7E,0x9F,0xFB,0xF8,0xFF,0xFF,
+0x3F,0xFD,0x7F,0x5F,0xDF,0xFD,0xFF,0xFF, 0x5F,0xFF,0xFD,0x5F,0xFF,0xFF,0x7F,0xFD,
+0x7F,0xFD,0x9F,0xFF,0xE0,0xFF,0xFA,0xF8, 0xBE,0x6F,0x9F,0xE6,0xF8,0xBE,0x3F,0x9A,
+0xF9,0xBE,0x6F,0x9F,0xE2,0xF9,0xFE,0x6F, 0x9F,0xF9,0xFF,0xF5,0xFD,0x7F,0xCF,0xDF,
+0xFD,0xFD,0x7F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xF7,0xF5,0xFD,0x0F,0xDB,0xFF,0xD3,0xFF,
+0xEB,0xFA,0xFF,0xFF,0xBF,0xFF,0xFA,0xFF, 0xFF,0xCB,0xFB,0xFE,0xFF,0xFF,0xEB,0xFA,
+0xFE,0xFF,0xFF,0xB7,0xFF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xDF,0xF5,0xFF,0xFF,0xD7,0xFF,
+0xFF,0xFF,0xDF,0xD7,0xF5,0xFF,0x7F,0xFE, 0x4F,0xFF,0xFD,0xFF,0x7F,0x7F,0xFF,0xAD,
+0xEB,0xFB,0xFF,0xAD,0xFF,0xFF,0xFF,0xFF, 0xAF,0xEB,0xFB,0xFF,0xFC,0x0D,0xFF,0xFF,
+0xDF,0xD2,0xFD,0xFF,0xFF,0xFD,0xF6,0xFF, 0xFF,0x7F,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF,
+0xFF,0xFB,0x3F,0x7D,0xEB,0x32,0xFE,0xBF, 0x2F,0xEB,0xFA,0xAE,0xBD,0xE0,0xFA,0x7E,
+0xBF,0xAD,0xEB,0xFA,0xFE,0xBF,0xF5,0x7F, 0xFF,0xDE,0xFE,0xE3,0xFB,0xFF,0xFF,0xFF,
+0xDF,0xEF,0x4F,0xDF,0xFF,0x7F,0xDF,0xFF, 0xF7,0xFF,0xFF,0xF8,0x7F,0xFF,0xFF,0xEF,
+0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xFF,0xDF, 0xED,0xFB,0xDF,0xFF,0xBF,0xFF,0xFF,0xFF,
+0x81,0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFF,0xFE,0xDD,0xFE,0xEF,0xFD,0xFF,
+0xFF,0xFB,0xFE,0xF7,0xFF,0x93,0xFD,0xFB, 0x7E,0xFF,0xFE,0x87,0xE9,0xFF,0x7F,0xB3,
+0x9F,0xFE,0xFE,0xFF,0xAF,0xFD,0xFE,0x7E, 0x3F,0xFE,0x67,0xFF,0xFF,0xF7,0xFF,0xFF,
+0xFC,0xF7,0xDF,0xFD,0xFF,0x7F,0xFF,0xFF, 0x7F,0x6D,0xFF,0xFF,0xFE,0xFF,0xFF,0x2F,
+0xFF,0xBF,0xFF,0xFF,0xEE,0xFF,0xBE,0xFF, 0xFF,0xFE,0xFF,0xEF,0xFF,0xFF,0xFE,0xFF,
+0xEF,0xFF,0xFF,0xFA,0x5F,0xFF,0xFF,0xFB, 0xFF,0xFF,0xEF,0xFF,0xFB,0xFE,0xFD,0xFF,
+0xFE,0xFF,0xFB,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFE,0xBF,0xDF,0xFF,0xFB,0xFF,0xFF,0xF7,
+0xFC,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,0x7F,0xFF,
+0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xF3,0xFF,0xFF,0xFF,0xEF,0xFB,0xFF,0xFF,
+0xFF,0xDF,0xE2,0xFF,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xE7,0xFF,0xFD,
+0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xED, 0xEF,0xFD,0xFF,0xFF,0xDF,0xD7,0xF5,0xFD,
+0x7F,0x5D,0xFD,0xFF,0x7F,0xDF,0x97,0xF4, 0xFD,0x7B,0x5F,0xFF,0xC9,0xFF,0xFB,0xFE,
+0xFF,0xBF,0xFF,0x5F,0xFF,0xFF,0xF7,0xFF, 0xEF,0xFD,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xF7,0xFF,0xD7,0xFD,0x7D,0x7F,0xFF, 0xFF,0xFF,0xFF,0xEF,0xDF,0xF7,0xFD,0xFF,
+0xBB,0xFF,0xFF,0x7F,0xFF,0xFE,0xE3,0xFF, 0xF9,0xFE,0x7F,0xBF,0xEF,0xFB,0xFE,0xFF,
+0xBF,0xF9,0xFE,0xFF,0x9F,0xEF,0xF9,0xFE, 0xFF,0xBF,0xF3,0xDA,0xFF,0x37,0xCD,0xF3,
+0x7C,0xDF,0x37,0xCD,0xF3,0x7F,0x37,0xCD, 0xF3,0x7C,0xDF,0x37,0xCC,0xF3,0x7F,0x5A,
+0xBD,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFD, 0xBF,0x6F,0xDE,0xFD,0xBF,0x6F,0xDB,0xF6,
+0xFD,0xBF,0x6F,0xFE,0xF1,0x6F,0xEB,0x7A, 0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7,0xAF,
+0x7A,0xDE,0xB7,0xAD,0xEB,0x7A,0xDE,0xB7, 0xFF,0x7E,0xFF,0xFE,0xCD,0xB3,0x6C,0xDB,
+0x36,0xCD,0xB3,0x6C,0xDE,0xCD,0xB3,0x6C, 0xDB,0x36,0xCD,0xB3,0x6C,0xDF,0xC9,0xBF,
+0xF7,0xBD,0xEF,0x7A,0x9E,0xA7,0xA9,0xEA, 0x7A,0xB7,0xBD,0xEA,0x7B,0xDE,0xA7,0xBD,
+0xCA,0x72,0x8D,0x91,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFE,0xF7,0xEF,0xFB,
+0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFE, 0x87,0xFF,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,
+0xFD,0xBF,0x6F,0xF6,0xFD,0xBF,0x6F,0xDB, 0xF6,0xFD,0xBF,0x6F,0xFE,0x4F,0xFF,0xBF,
+0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,0xEF, 0xBE,0xEF,0xBB,0xEE,0xFB,0xBE,0xEF,0xBB,
+0xEF,0xFC,0x5F,0xFF,0xFF,0xFF,0x3F,0xCF, 0xF3,0xFC,0xFF,0x3F,0xCF,0xFC,0xFF,0x3F,
+0xCF,0xF3,0xFC,0xFF,0x3F,0xCF,0xFD,0x9F, 0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
+0xEB,0xFE,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFF,0xE1,0x6F,0xFD,0xFF,0x7F,
+0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFD,0xFF, 0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
+0x7A,0xBF,0xFB,0xFE,0xDF,0xB7,0xED,0xFB, 0x7E,0xDF,0xB7,0xFB,0x7E,0xDF,0xB7,0xED,
+0xFB,0x7E,0xDF,0xB7,0xFF,0xC9,0xFF,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,
+0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEE, 0xFB,0xFE,0xBB,0xFF,0xFE,0xFF,0xBF,0xEF,
+0xFB,0xFE,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0x3F,0xCF,0xFF,0xE7,
+0xFE,0xFF,0xF5,0xFD,0x77,0x5D,0xD7,0x35, 0xDD,0x77,0xD7,0xF5,0xCD,0x7B,0x5D,0xD7,
+0xF5,0xDD,0x77,0xFE,0x27,0xFF,0xFF,0x8B, 0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9,0xAF,
+0x8B,0xE2,0xF8,0xBE,0x2F,0x8B,0xE2,0xF9, 0xFE,0x1F,0xFF,0x5F,0xD7,0xF5,0xFD,0x7F,
+0x5F,0xD7,0xF5,0xFF,0x5F,0xD7,0xF5,0xFD, 0x7F,0x5F,0xD7,0xF5,0xFF,0xFA,0x3F,0xFE,
+0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xEB, 0xEC,0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,
+0xEB,0xFF,0xFE,0x7F,0xFD,0x7F,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE6, 0xFF,0xFA,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
+0xF7,0xFC,0xFF,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFD,0xFF,0xF5,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0x02,0xFF,0xFE,0xBF,0xAB,0xEB,0xFA, 0xBE,0xBF,0x23,0xEB,0xDE,0x1F,0xAF,0xEA,
+0xFA,0xFE,0xAF,0xAF,0xEB,0xFD,0x97,0xFF, 0xF3,0xFC,0x7B,0x1F,0xCF,0xF1,0xFC,0x7F,
+0x1F,0xF1,0xFC,0x77,0x1F,0xCD,0xF1,0xFC, 0xFF,0x1F,0xFE,0x87,0xFF,0xAF,0xEF,0xFA,
+0xFE,0xFF,0xAF,0xEF,0xFA,0xFD,0xBF,0x2B, 0xFB,0x7E,0xBF,0xBF,0xEB,0xFB,0xFB,0xFB,
+0xDF,0xFF,0xFB,0xF7,0xFF,0xFF,0x7F,0xF7, 0xF7,0xFF,0xFD,0xDF,0xFE,0xFC,0xDF,0xFF,
+0xDF,0xFF,0xFD,0xFF,0xDA,0xBF,0xFF,0xBB, 0xEF,0xFB,0xF9,0xFF,0xBE,0xEF,0xFB,0xFB,
+0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xF7,0x7F,0xFD,0xD7,0xFF,0xFF,0x7F,
+0xFF,0xFF,0xFF,0xFE,0xF7,0xFF,0xFE,0xFF, 0xF7,0xFF,0xFF,0x7F,0xFF,0xFF,0xEC,0xFF,
+0xFF,0xFE,0xDF,0xBF,0xFF,0xFB,0xFE,0xFF, 0xBB,0x68,0xAE,0x1F,0xAE,0xFB,0xFB,0xFF,
+0xFF,0xBF,0xFF,0xD5,0xFF,0x7F,0xFF,0xFF, 0xF7,0xFE,0xFE,0xFF,0xBF,0xEF,0x9F,0xFD,
+0x7F,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,0xFF, 0xBB,0xF7,0xBF,0xFF,0xFF,0xFF,0xFF,0xDF,
+0xFF,0xBF,0xFB,0xFF,0xFF,0xFF,0xDE,0x3F, 0xFF,0xFF,0xFF,0xFF,0xFF,0xA7,0xFF,0xFF,
+0xFF,0xFF,0xEF,0xFF,0x7F,0xFB,0xFD,0xFB, 0x7F,0xFF,0xFF,0xFF,0xFF,0xCF,0xF3,0x7C,
+0xFF,0x7F,0x8D,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFB,0xFF,0xF7,0xFB,0xFE,0xFD,0xFF,0xFF,
+0xFF,0xFF,0xF7,0xFD,0xFF,0x7F,0xFD,0x1F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xBF,0xDF,0xFF,
+0xFF,0xFE,0x5C,0xFF,0x6D,0xFF,0x7F,0xAB, 0xE7,0xF1,0xFF,0xFD,0x9F,0xFF,0xFF,0xAD,
+0xEB,0x7A,0x3F,0x1F,0xFF,0xFF,0xFE,0xBF, 0xAF,0xF3,0xDE,0xF5,0xFF,0x8F,0xFB,0xDF,
+0xE6,0x7F,0xFF,0xDF,0xF3,0xFD,0xFF,0x7E, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xF7,0xF3,
+0x7F,0xDF,0xF7,0xEF,0xFF,0xF6,0x3F,0x9F, 0xDF,0xFF,0xFF,0xEE,0xFF,0xFF,0xEF,0xFB,
+0xFF,0xFF,0xF9,0xFB,0xFE,0x4F,0xBF,0xEF, 0xBB,0xFF,0x69,0xAF,0xAF,0xFC,0xFF,0x3F,
+0xDD,0xFF,0xFC,0xBF,0x8F,0xFF,0xFD,0xF3, 0xBF,0xED,0x9E,0xFC,0xBF,0x6F,0xF5,0xD3,
+0xDF,0xFF,0xDB,0xD6,0xF5,0xEF,0xFD,0xFE, 0xFF,0xB9,0xFF,0x1F,0xD2,0xA9,0xAF,0xFF,
+0xDB,0xF7,0xBF,0xEF,0x46,0xFF,0xFF,0xAD, 0xEB,0x7A,0xDF,0xEF,0xF7,0xFF,0x7F,0xF7,
+0x9F,0xED,0xFF,0x7F,0xFF,0xAD,0xEB,0x7F, 0xF5,0x6F,0xFF,0xFD,0xFB,0xD6,0xF4,0xF7,
+0xFB,0xF9,0x7E,0x7F,0xFF,0x5F,0xC2,0xFE, 0xBF,0xFD,0xFB,0x33,0xDF,0xF9,0x5B,0xFF,
+0xFF,0xDD,0x67,0x7D,0xCF,0xEF,0xDB,0xEC, 0xFF,0x77,0xDD,0xF7,0xFD,0xFF,0xFF,0xDE,
+0xA7,0xBF,0xD4,0x9F,0xFF,0xFF,0xBF,0xEF, 0xFE,0xFF,0xDF,0xEF,0xBB,0xFF,0xFF,0xEF,
+0xEB,0xFA,0xFF,0xEF,0xBD,0xFB,0xFF,0xE2, 0x7F,0xFF,0xDF,0xDF,0xF7,0xFD,0xBF,0xBB,
+0x73,0xF7,0xFD,0x7F,0xDF,0xDE,0xF7,0xBF, 0xEA,0xDB,0xF6,0xFF,0xD6,0xFF,0xFF,0x66,
+0xFF,0xBE,0xFF,0xBF,0x6B,0xD9,0xF6,0xDF, 0xFF,0xFB,0x7E,0x7F,0xB7,0x7E,0xFF,0xFE,
+0xFF,0xCD,0xFF,0xFE,0x7F,0xFF,0xFC,0xFD, 0x3F,0xFB,0xFB,0xF7,0xFF,0xFF,0xFB,0xF6,
+0x7D,0xFE,0x7F,0xFF,0xFC,0xFF,0xB9,0xFF, 0xF9,0xFA,0xFE,0xBF,0xAF,0x5B,0xD6,0xED,
+0xAD,0x7B,0xF6,0xF9,0xBF,0xEF,0xF8,0xFA, 0xFE,0xBF,0xFE,0xE6,0xFF,0xFF,0xF7,0xFD,
+0xFF,0x7F,0xBF,0xEF,0xF3,0xFF,0xFF,0x6F, 0xF7,0xFE,0xFF,0xFF,0xF7,0xFD,0xFE,0xF7,
+0xEF,0xFF,0xFB,0xEF,0xFB,0x7E,0xDE,0xFE, 0xFF,0xBF,0xFF,0xFE,0xFF,0xFF,0xFB,0xFF,
+0xFF,0xEF,0xFB,0x6F,0xFC,0x1F,0xFE,0xE7, 0xFF,0xFF,0xFF,0xEF,0xFF,0xD3,0xB4,0xBB,
+0xFF,0xFF,0xFD,0xBF,0x6F,0xE3,0xFE,0xFF, 0xBF,0xFC,0xBF,0xF7,0xCF,0xF7,0xFD,0xFF,
+0x2F,0xDF,0xAB,0xEA,0xFF,0xDF,0xE7,0xEA, 0x9A,0xAF,0xEF,0xFB,0xFE,0xFF,0xF5,0x3F,
+0xFD,0x7E,0xFF,0xD7,0xF5,0xFB,0xFF,0xFD, 0xF7,0xFF,0x7F,0xFE,0xF7,0xFD,0xFF,0xD7,
+0xFF,0xD7,0x7F,0xEE,0x7F,0xFA,0x79,0xFE, 0x2F,0x8B,0xE6,0xF9,0xFE,0x3F,0x9E,0xF9,
+0xBE,0x2F,0x0B,0xE7,0xF9,0xFE,0x2F,0x9F, 0xFD,0xFF,0xFE,0x7D,0x7F,0x5F,0xD7,0xFF,
+0xFF,0x7F,0xFF,0xFD,0xFF,0x7F,0x5F,0x97, 0xFF,0xFD,0x7F,0x5F,0xFF,0xE3,0xFF,0xFF,
+0xFA,0xFE,0xBF,0xAF,0xFB,0xFB,0xFF,0xFF, 0xCF,0xEB,0xFE,0xBF,0xAF,0xFF,0xFA,0xFE,
+0xBF,0xFF,0x87,0xFF,0xFF,0xF5,0xFF,0xFF, 0xFF,0xFF,0xFD,0xFF,0x7F,0xFF,0xFF,0xFF,
+0xFB,0xFF,0xFF,0xF5,0xFF,0xFF,0xFE,0x0F, 0xFF,0xFD,0xEB,0xFF,0xFF,0xF7,0xFF,0xEF,
+0x7B,0xDF,0xFE,0xFF,0xFF,0xDF,0xF7,0xFD, 0xEB,0x7F,0xDF,0xFF,0x5F,0xFF,0xFF,0xFF,
+0xFF,0xFD,0xBF,0xFF,0x7E,0xFA,0xBF,0xC7, 0xDB,0xF7,0xBD,0x3F,0xFB,0xFF,0xF6,0xFF,
+0xFA,0xAF,0xFF,0xEB,0xFA,0xFE,0x3F,0x2F, 0xEA,0xFA,0x3E,0xAD,0xC9,0xBA,0xF6,0xAD,
+0xAF,0xEB,0xFA,0xF6,0xBF,0xFE,0x7F,0xFF, 0xFF,0xFD,0xFF,0xF1,0x7F,0x3F,0xCF,0xF1,
+0xEF,0xFF,0x7F,0xFF,0xBC,0xDF,0xDF,0xF7, 0xDD,0xFF,0xE0,0x7F,0xFF,0xFF,0xFE,0xFF,
+0xFA,0xEC,0xBB,0x7F,0x5F,0xFF,0xFB,0xEC, 0xFF,0xEF,0xB7,0xFF,0xF7,0xFF,0xFF,0xB5,
+0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xEE,0xDF, 0x5F,0xDF,0xDE,0xFF,0xAE,0xE7,0x77,0xFF,
+0xFF,0xDF,0xF7,0xFF,0xE3,0xFF,0xFA,0xBB, 0xFE,0xFF,0xAF,0xFD,0xFB,0xFE,0xBF,0xAB,
+0xF9,0xFE,0xFF,0xBF,0x7F,0xBF,0xFE,0xBD, 0xFE,0xD7,0xFF,0x9F,0xFD,0xFF,0xBE,0xEF,
+0xFF,0xEE,0xFD,0xBB,0x5B,0xEF,0xFF,0x7F, 0xEF,0xFF,0xEF,0xFF,0x7F,0xFF,0x4F,0xFF,
+0xEF,0xFB,0xBC,0xFC,0xFF,0xFF,0xFF,0xFE, 0xFE,0xFD,0xFA,0xFE,0xFB,0xFF,0xFD,0xF3,
+0xFB,0xFF,0xF8,0x5F,0xFF,0xFF,0xD7,0xF5, 0xFD,0xDF,0xEF,0xFF,0xF3,0xDC,0x5F,0xCE,
+0xF5,0xBD,0xFF,0xFF,0xD7,0xFF,0xFF,0xF9, 0x3F,0xFF,0xDF,0xF7,0xFF,0xFE,0xFF,0xFD,
+0xFF,0xFB,0xFF,0xF7,0xB9,0x7D,0xFE,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF9,0x7F,0xFF,0xFE,
+0xFF,0xFF,0x7F,0xFF,0xFE,0xFF,0xFF,0xF7, 0xF6,0xFF,0xBF,0xF1,0xF8,0xFF,0xFF,0xFF,
+0xFF,0xE0,0xFF,0xFF,0xFF,0xFF,0xF9,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEF,0xEF,0xFF,0xFF,
+0x9B,0xFB,0x7F,0xFF,0xFF,0xFF,0xC1,0xFF, 0xDF,0xFF,0x3F,0x5F,0xD7,0xBF,0xEF,0xBB,
+0xDE,0xEE,0xFF,0x7F,0xDF,0xFF,0xFE,0xF5, 0x7F,0xDF,0xFF,0x99,0xFF,0xFF,0xFA,0xFF,
+0xBF,0xFD,0xEB,0x7A,0xFF,0xB7,0xFE,0xFE, 0xFF,0xFF,0xEF,0xFF,0xFF,0xFD,0xBF,0xFF,
+0x97,0xFF,0xFD,0xF7,0xFF,0x7F,0xF7,0xFF, 0xFF,0xFD,0x5F,0xFE,0xF3,0xF9,0xDF,0xDF,
+0xFF,0xFF,0xFC,0xFF,0xFF,0x83,0xFF,0xFF, 0xFE,0xFF,0x9E,0xEC,0xFB,0xEE,0xFF,0x9F,
+0xBF,0xEF,0xFF,0xFE,0xED,0x7B,0xFF,0xFF, 0xFF,0xF1,0x5A,0xFF,0xFF,0xFD,0xFF,0x7C,
+0x69,0x3B,0xDF,0xFF,0x7F,0x1F,0xDF,0xFF, 0xFD,0xBA,0xFF,0xFF,0xFB,0xFF,0x5B,0xBD,
+0xFF,0xFF,0xFF,0xFF,0xD7,0xB6,0xED,0xE9, 0xFF,0xD6,0xBD,0x6F,0x5F,0xFB,0xFF,0xEF,
+0xFF,0x5F,0xFE,0xF6,0x6F,0xFF,0xFF,0xFF, 0xFF,0xF7,0xEB,0x7A,0xDF,0xFF,0x9F,0x7F,
+0x7F,0xFF,0xB7,0xFF,0xFF,0xFE,0xDF,0xFF, 0x6C,0xFF,0xFB,0xFF,0xBB,0x6F,0xEB,0xFE,
+0xCC,0xF7,0xA5,0xFA,0x5C,0xF5,0x75,0xBB, 0xB7,0xDF,0xFE,0x6F,0x5F,0xC5,0xBF,0xFD,
+0x7B,0xFE,0xFF,0x95,0xE7,0x29,0xCF,0x4F, 0xF5,0x91,0xEE,0x6B,0xDF,0xEF,0xFD,0x54,
+0xF5,0xBD,0xB1,0xFF,0xEF,0xEE,0xFB,0xBE, 0xBF,0xAF,0xFE,0xDE,0xBD,0x6F,0xDA,0xF2,
+0xFF,0xAF,0xBE,0xFF,0xFF,0xFD,0x7E,0xA7, 0xFF,0xF7,0xFF,0xBF,0xEF,0x7B,0xF6,0xFD,
+0xBD,0x4A,0xF2,0x85,0x85,0xBF,0x5B,0xFE, 0xB5,0xFD,0xFA,0xFF,0x4F,0xFF,0xFE,0xDF,
+0xFF,0xED,0xFF,0xBF,0xFF,0xBF,0x7F,0xFE, 0xFF,0xB7,0x6D,0xFF,0xF7,0xBF,0xBF,0xEF,
+0xFD,0x1F,0xFF,0xFE,0x7D,0xFF,0x67,0xFF, 0xFF,0xFF,0x3F,0x7F,0xFE,0xBF,0xFF,0xE7,
+0xDF,0xE7,0xFF,0xEF,0x6B,0xFC,0x1F,0xFF, 0xBF,0xEF,0xFB,0xFE,0xDE,0xBF,0xAF,0xFA,
+0xFF,0xB6,0xEF,0xF9,0xFE,0xFF,0x8F,0xEF, 0xDB,0xEF,0xAB,0x6F,0xFB,0xFE,0xFF,0xFF,
+0xEF,0xFD,0xFF,0x7F,0xFF,0xFF,0xDE,0xFF, 0xFF,0xEF,0xFF,0xFF,0xFF,0x3F,0xFF,0x6C,
+0xFF,0xBF,0xFB,0xFF,0xFE,0xFF,0xFB,0xFE, 0xDF,0xFF,0xFF,0xEF,0xFF,0xFF,0xBF,0xFF,
+0xFF,0xFE,0xFB,0xFF,0xD5,0x7F,0xFF,0xFF, 0xEF,0xFB,0xFF,0xFF,0xBF,0xEF,0x43,0xB5,
+0xFD,0x6F,0xCF,0xD6,0xBE,0x3F,0x7F,0xDB, 0xFE,0xC3,0xFF,0xFD,0xFF,0xAF,0xEB,0xFB,
+0xFC,0xFF,0x3E,0xEF,0xE8,0xFA,0xBD,0xCD, 0xAA,0xFE,0xFE,0x7D,0xCF,0xFF,0xB7,0xFF,
+0xF7,0xFF,0xFF,0xFF,0xFD,0xFF,0x75,0xCD, 0x52,0xD7,0xFD,0xFB,0xF7,0xDD,0xFB,0xEF,
+0xEB,0xFF,0xFF,0x4F,0xFF,0xBF,0x9F,0xE7, 0xF9,0xFC,0x7F,0x8B,0xC3,0xF9,0xAF,0x8F,
+0xE7,0xE9,0xBE,0x7F,0x9F,0xE6,0xF9,0xFC, 0x5F,0xFF,0xFF,0xF7,0xFD,0xFF,0x7A,0x5F,
+0xD7,0xED,0xFF,0xFF,0xD7,0xFF,0xDD,0x7F, 0xE7,0xFF,0xFC,0xFF,0xFC,0x3F,0xFF,0xFF,
+0xFF,0xFB,0xFF,0xFE,0xBF,0xAF,0xFF,0xFD, 0xFF,0xEF,0xFF,0xEB,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xF7,0x7F,0xFF,0x7F,0xDF,0xFF,0xFD, 0xFD,0x7F,0xFE,0xF7,0xFD,0x7F,0xDF,0xFF,
+0xFD,0xFF,0xFF,0xDF,0xFB,0xFF,0xEE,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7A,0xDF,0xF5,
+0xFD,0xFA,0xDF,0xF7,0xFC,0xFF,0x7F,0xDF, 0xBF,0xED,0xFF,0xC9,0xFF,0xDF,0xFF,0xBF,
+0x2F,0xFB,0xFF,0xBC,0xAD,0xFF,0xF7,0xFF, 0xFF,0xEF,0xD3,0xFF,0x7D,0xBF,0x6F,0xFF,
+0xFA,0xFF,0xFE,0xBF,0xAE,0xEA,0xFA,0xBE, 0xAD,0xA5,0xEB,0xCE,0xBF,0xA7,0xEB,0x5A,
+0xDE,0xBD,0xAF,0x6B,0xFD,0x57,0xFF,0xFF, 0xF4,0x7F,0x1F,0x7F,0xFD,0xFF,0x7F,0x36,
+0xF0,0xDF,0x79,0xFF,0xFF,0xFF,0xF7,0xFD, 0xBF,0xFF,0x87,0xFF,0xFB,0xF3,0xFC,0xFF,
+0xFF,0xFF,0xFF,0x7E,0xFF,0xBF,0xDF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xF8,0x9F,
+0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFD, 0xF7,0xFC,0xBD,0xFF,0xFE,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFB,0xF9,0xBF,0xFF,0xFF,0xEB, 0xE2,0xFE,0xFF,0xBF,0xEF,0xA9,0xBA,0x2F,
+0xEB,0xF9,0xFE,0x77,0xDF,0xF7,0xFF,0xFF, 0xF9,0x7F,0xFF,0xFF,0x7F,0xEF,0xD7,0xFF,
+0xFD,0xFF,0xFB,0xF5,0xFF,0xBF,0x6F,0xDF, 0xFF,0xFF,0xFD,0xFF,0xFF,0xF0,0xFF,0xFF,
+0xFF,0x3F,0xCF,0xFF,0xBA,0xEE,0x9B,0xBF, 0xEE,0xD7,0xFE,0xCD,0xEF,0xFF,0xDF,0xBF,
+0xFF,0xFF,0xC5,0xFF,0xFF,0xFD,0x7F,0x4F, 0xFD,0xF6,0xD9,0xFF,0x4F,0xD6,0xFD,0xBF,
+0x6E,0xFF,0xFF,0xF4,0x7F,0xFF,0x7F,0x8B, 0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xF9,0xFE,
+0x37,0xFF,0xD9,0xFB,0xF5,0xAF,0xFD,0xFF, 0xFF,0xFB,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,
+0xFB,0xF7,0xFF,0xFD,0xFF,0x7C,0xFA,0x7E, 0x4F,0xFC,0xDF,0x1D,0xC7,0xFF,0xFF,0xFF,
+0xFF,0xAE,0xFF,0xFF,0xFF,0xFF,0xFD,0xFB, 0xFF,0xFF,0xFE,0xFE,0xFC,0xFF,0x7F,0x7F,
+0xBF,0xEF,0xFE,0xFF,0xFF,0xFF,0x5F,0xFD, 0xFF,0xFF,0xFF,0xFD,0x6F,0x5A,0xD7,0x7B,
+0xBE,0x5F,0xFE,0x39,0xFF,0xF7,0xFF,0xF7, 0xFD,0xFE,0xAA,0x1F,0xFF,0xFF,0xFF,0xFF,
+0xFE,0xFE,0xAB,0xAF,0xFD,0xFE,0xBF,0xFF, 0xF7,0xFF,0x7F,0xFE,0x8F,0xE3,0xFB,0xEE,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xEB,0xFB,0xFF, 0xFD,0xBF,0xEF,0xDF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFB,0xE4,0x3F,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xF3,0xEF,0xBB,0xFB,
+0xBF,0xEF,0xBB,0xFF,0xD7,0xBF,0xFF,0xFF, 0xFF,0x29,0xAF,0xF7,0xFF,0xFF,0xFB,0xFF,
+0xFB,0xE6,0xFF,0x0F,0xFB,0x3F,0xDF,0x0F, 0xFF,0xAF,0xFF,0xFF,0xFF,0xF5,0xC3,0xDF,
+0x5F,0xFF,0xFF,0xFF,0xFE,0x6B,0xCA,0xBE, 0xBC,0xFF,0x9F,0xF2,0xBF,0xFF,0xFE,0xFA,
+0xFF,0xFF,0xEF,0x16,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFC,0xDF,0x97,0xFD,0x79,0xFF,0x37,
+0xE7,0x7F,0xFF,0xFF,0xB5,0xFF,0xFF,0xF6, 0x2F,0xFF,0xFD,0xFB,0xFE,0xFF,0xFF,0xFD,
+0x5F,0x57,0x5F,0xFF,0xDB,0x52,0xDF,0xFF, 0xFD,0xBF,0xFF,0xFF,0xFC,0xDB,0xFF,0x7B,
+0xB5,0xFD,0x7F,0xFF,0x71,0x9C,0x6E,0xFF, 0xF6,0x35,0xA5,0x9B,0xFF,0xFF,0xFD,0xFF,
+0xFF,0xDB,0x9E,0x7F,0xFE,0xEF,0xFB,0xFF, 0xFF,0xBD,0xEF,0xFF,0xDE,0xB7,0xF9,0x4B,
+0xFF,0xF5,0xEF,0xFF,0xFF,0xFF,0xE8,0x7E, 0xFF,0xEA,0xDF,0xF7,0xFF,0xFD,0x69,0x5B,
+0xFC,0x9F,0xEF,0x78,0xD6,0xFF,0xEB,0xEF, 0xFF,0xFF,0xFF,0xE8,0xFF,0xFF,0xED,0xFF,
+0xFF,0xFF,0xFF,0xE3,0xF9,0xF6,0xBF,0xFF, 0xFF,0xFE,0xDF,0xFF,0x7F,0xFF,0xFF,0xFF,
+0xD1,0xFF,0xFF,0xE7,0xFF,0xFF,0xFF,0xFF, 0xE7,0xF9,0xFF,0xBF,0x7F,0xD9,0xFF,0xFD,
+0xFE,0x7F,0xFF,0xFE,0xFF,0xF9,0xFF,0xFB, 0xD6,0xDF,0xBF,0xEF,0x5B,0xD6,0xFF,0xBF,
+0xFB,0xF6,0xFF,0xBF,0xEF,0xF8,0xF6,0xDD, 0xBE,0xFE,0x16,0xFF,0xBF,0xEF,0xFF,0xFE,
+0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0x6F,0xFB, 0xFF,0xFF,0xFF,0x6F,0xF3,0xFF,0xF7,0xEF,
+0xFB,0xFF,0xBF,0xFF,0xEF,0xFE,0xFF,0xBF, 0xFF,0xFF,0xFF,0xBE,0xBF,0xFF,0xEF,0xFF,
+0x7F,0xEF,0xFF,0xFD,0x17,0xFB,0x7B,0xFF, 0xFF,0xFD,0x7F,0xDB,0xF6,0xF4,0x7F,0xFA,
+0xFE,0xF5,0xBF,0xEB,0xE3,0xF7,0xFF,0xFF, 0xE9,0xBF,0xFF,0xAF,0xF7,0xFD,0xF3,0x7E,
+0x8F,0xA3,0xEA,0xFF,0xCB,0xF3,0xEE,0xFF, 0xBF,0xEF,0xF7,0xF9,0xFF,0xFE,0x7F,0xFF,
+0xFF,0xFF,0xFF,0xF5,0xFB,0xF6,0xFF,0xF5, 0x2F,0xFE,0xFB,0xD7,0xBF,0xFF,0xBE,0xDF,
+0x9F,0xFF,0xF0,0xFF,0xFF,0xF9,0xFE,0x7F, 0x8F,0xA3,0xF8,0xFE,0x6F,0x9F,0xF9,0xF6,
+0x2F,0x9F,0xE7,0xF9,0xFE,0x2F,0x9F,0xE1, 0xFF,0xFF,0xFF,0x7F,0xDF,0xF7,0xF5,0xFD,
+0x7F,0x7F,0xF5,0xFF,0x9F,0x5F,0xFB,0xFE, 0xFF,0x7F,0xFF,0xFF,0xCB,0xFF,0xFF,0xFB,
+0xFE,0xFF,0xBF,0xAF,0xFB,0xFE,0xFF,0xDF, 0xFE,0xFE,0xBF,0xF7,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xC7,0xFF,0xFF,0xFD,0xFF,0x7F,0xDD, 0xF7,0xFD,0xFF,0xFF,0xD7,0xFF,0xFD,0x7F,
+0xFF,0xFB,0xFD,0xFF,0xFF,0xFE,0xEF,0x7F, 0xFD,0xEF,0xFB,0xFE,0xFB,0xFD,0xFF,0x7F,
+0xDF,0xFD,0xFF,0x7A,0xDF,0xF7,0xFD,0xFF, 0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xD3,0xF7,
+0xFF,0xFF,0x6F,0xDB,0xFF,0xFF,0xEF,0xCB, 0xF4,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
+0x29,0xFF,0xE8,0xDA,0x76,0x9F,0xAF,0x6A, 0xDA,0xFE,0x35,0xEB,0xDA,0xD6,0xBF,0xAB,
+0xEB,0x7A,0xDE,0xBF,0xD7,0x7F,0xFF,0xFE, 0xFF,0xBF,0xEF,0xFD,0xDF,0x77,0xBF,0xFD,
+0x37,0xEF,0xFF,0xEF,0xFF,0x3F,0xFF,0xFF, 0xFF,0xFE,0x7F,0xFF,0xFF,0xFF,0xF7,0x7E,
+0xDF,0xFF,0xFF,0xFF,0xFA,0xB7,0x7F,0xFF, 0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x89,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0x9F,0xFB,0xFF,0xFF,0xFF,0xE7,0xFF,
+0xFF,0xFF,0xFF,0xAA,0xFF,0xAB,0xFB,0xFA, 0xEF,0xBF,0xFF,0xDF,0xFA,0x7B,0xB9,0xFE,
+0xFE,0xFF,0xFD,0xFF,0xF7,0xFE,0x3F,0xFF, 0xB7,0xFF,0xF7,0xEE,0xFF,0x7F,0xEF,0xFF,
+0xFF,0x7F,0xFF,0x1F,0xFB,0xFF,0xBF,0xFB, 0xFE,0xFF,0xBD,0xFF,0xFF,0x2F,0xFF,0xBF,
+0xFF,0x7F,0xDF,0xFA,0xFF,0xFF,0xFC,0xEE, 0xF5,0xF3,0xBE,0xFB,0x0F,0xEF,0xF3,0xBE,
+0xEF,0xFC,0x5F,0xFF,0x5A,0xFF,0xF7,0xDF, 0xFF,0xFF,0xFE,0xD5,0xFC,0x5F,0xFB,0xF2,
+0xFF,0xFF,0x2F,0xBB,0xF3,0xFF,0xFF,0xBF, 0xFF,0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
+0xBF,0xFF,0xFF,0xFD,0x7B,0xFF,0xDF,0xB9, 0xFF,0xFB,0xFF,0xD8,0x7F,0xFF,0xFF,0xFF,
+0xFB,0xFF,0xFC,0x7F,0x1F,0xBF,0xE0,0xDF, 0xF7,0xEF,0xFF,0xFD,0x7F,0xFE,0xDF,0xFF,
+0xE0,0xFF,0xFF,0xFD,0xEF,0xFB,0xFF,0xFE, 0xF7,0xDF,0xFF,0xEB,0x5F,0xFF,0xF7,0xFF,
+0xFF,0xFF,0xFF,0xBF,0xFF,0xFD,0xFF,0xFD, 0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,0x3B,0xDC,
+0xFD,0x6D,0x7B,0x5F,0x57,0xF5,0xFD,0x7F, 0x5F,0xFF,0xB1,0xFF,0xEB,0xFF,0xFF,0xFF,
+0xFB,0xFB,0xFE,0xFF,0xBF,0xFB,0xBE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFF,0xAF,0xFE,0xF7,
+0xDF,0xDF,0xFF,0xFF,0xFF,0x7F,0xCF,0xF3, 0xF8,0xFF,0xD7,0xFB,0xFF,0x5F,0xBF,0xF7,
+0xFB,0xFF,0x7F,0xFE,0x23,0xFF,0xFF,0xFE, 0x7F,0xF3,0xFF,0xFB,0xFE,0xFF,0xFF,0xF3,
+0xFF,0xFF,0xF5,0xF9,0xFF,0x3F,0xFF,0xFF, 0xF0,0x9A,0xFF,0xBE,0x7F,0xFF,0xFC,0xF9,
+0xFF,0xFD,0xAF,0xEB,0xFE,0xBF,0xFF,0xCF, 0xF3,0xFE,0x7F,0xFF,0xFF,0x5B,0xBD,0xFF,
+0xBC,0xEB,0xFF,0xD7,0xD4,0xAF,0xAF,0xFD, 0xFF,0xCF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,
+0xFD,0xFE,0xFF,0x6F,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFD,0x7F,0x5E,0xFD,0xBF,0xDB,0xF6,
+0xFD,0xBF,0x6F,0xFB,0xEE,0xFD,0xFF,0x7A, 0xFF,0xFA,0xFB,0xFF,0x3F,0xFB,0xB7,0x5F,
+0xD6,0xF7,0x1F,0x71,0xDC,0x77,0x1D,0xC7, 0x31,0xDC,0x77,0xDF,0xF9,0xBF,0xF5,0x5B,
+0xF4,0xD7,0x9D,0xAE,0xFF,0xBF,0xFD,0xBF, 0xDB,0xF6,0xFD,0xBF,0x6F,0xDB,0xF6,0xFE,
+0x3D,0x81,0xFF,0xEB,0xFE,0xFE,0xFE,0xFF, 0xEB,0x7A,0xDF,0x7D,0x77,0x7D,0xF5,0x79,
+0xDF,0x57,0xDD,0xF5,0x7D,0x7E,0xE6,0xFF, 0xD6,0x3F,0xBF,0x7F,0xFF,0xD4,0xF5,0x3F,
+0xBF,0xFB,0xBE,0xEF,0xB3,0xEE,0xFB,0x9E, 0xEF,0xBB,0xFE,0x8B,0xFF,0xFE,0xDF,0xB7,
+0xED,0xFF,0xF7,0xFD,0xFE,0xFF,0xEF,0xBB, 0xEE,0xFF,0xBE,0xEF,0xBB,0xEE,0xEB,0xFC,
+0x1F,0xFF,0xFF,0xFD,0xFF,0xE7,0xFF,0xF7, 0xFD,0xFF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB,
+0xFE,0xFF,0xBF,0xEB,0xFA,0x1F,0xFF,0xB7, 0xEF,0x5B,0xFE,0xFF,0xAF,0xEB,0xDD,0xE7,
+0xDE,0x77,0x9D,0xE7,0x79,0xDE,0x77,0x9D, 0xBF,0xE6,0x6F,0xFF,0xFE,0xFF,0xBF,0xEF,
+0xFB,0xFE,0xFD,0xBF,0x6F,0xF6,0xFD,0xBF, 0x6F,0xDB,0xF6,0xFD,0xBF,0xFF,0x7E,0xFF,
+0xFF,0xFB,0xFE,0xFE,0xFF,0xEF,0xFB,0xFD, 0xEF,0x7E,0xF7,0xBD,0xEF,0x7B,0xDE,0xF7,
+0xBD,0xEF,0xFF,0xD5,0xFF,0xBF,0xFF,0xEF, 0xFE,0xFF,0xFC,0x3F,0x0F,0xE7,0xFE,0x7F,
+0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFE, 0xF3,0xFF,0xFE,0xDF,0xAD,0xDF,0x67,0xEE,
+0xFB,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFF,0x23,0xFF,0xFF,
+0xFF,0xFF,0x7F,0xFF,0xF3,0xBC,0xDB,0xFE, 0xFB,0xFF,0xFB,0xBE,0xF7,0xFB,0xFF,0x7F,
+0xDF,0xFF,0xCF,0xFB,0xFF,0x9F,0xE3,0xF9, 0xBE,0x3F,0x8F,0xE7,0x79,0xFF,0x9D,0xE7,
+0xF9,0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x5F, 0xFF,0xCF,0xF7,0xFF,0xFF,0xFF,0xDF,0xF7,
+0xFE,0x7F,0xE7,0xF9,0xFE,0x7F,0xFF,0xFF, 0xFB,0xFE,0xFF,0xFF,0xBF,0xFF,0xBF,0xBF,
+0xFF,0xFE,0xFF,0xBF,0xEF,0xFF,0xFD,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFD,0xFF,
+0xFF,0x3F,0xFF,0xBF,0xFF,0xF7,0xFF,0xFF, 0x7F,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xE8,0xEF,0xFF, 0x5F,0xF7,0xBF,0xF9,0xFE,0xDF,0xB7,0xFD,
+0xFF,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xDD,0xFF,0xF2,0xFF,0xBF,0xFF,
+0xFF,0xBF,0xFF,0xFF,0x2F,0xF2,0xFF,0xBF, 0x2F,0x7B,0xD2,0xF7,0xBF,0x2F,0xFF,0xBB,
+0xFF,0xEE,0x8F,0xAF,0xEB,0xFA,0xFE,0x3F, 0xA7,0x69,0xCE,0x8F,0xA4,0xEA,0xFA,0xEE,
+0xB7,0xAE,0xEB,0xFD,0xC7,0xFF,0xF7,0xF7, 0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x3E,0xF3,
+0x74,0xFF,0x3F,0x4F,0xFF,0xE7,0xFF,0x3F, 0xFE,0xA7,0xFF,0xFF,0xDF,0xF7,0xB7,0xFF,
+0xF7,0xFF,0xBA,0xEF,0x37,0xEB,0xFB,0xFE, 0xBF,0xFB,0xFE,0xF3,0xFF,0xF9,0xDF,0xFF,
+0xBF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFD,0xDF,0xFF,0xFD,0xFF,0xFF,0xFB,0xFE,
+0xFD,0xFF,0xFB,0xBF,0xFE,0x3F,0xED,0xFF, 0xDF,0xBE,0x3D,0xA7,0xFB,0xFA,0x3F,0xE6,
+0xE1,0xFE,0xFE,0x3F,0xEF,0xE3,0xDF,0xF5, 0x7F,0xFE,0xFF,0x7E,0xFF,0xFF,0xFF,0xFF,
+0xEF,0x6F,0xF6,0xFF,0x7D,0xEF,0xD7,0xDE, 0xFF,0x7D,0xEF,0xFF,0xF2,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0x7B,0xDE,0xFB,0xE6,0xEE, 0xEF,0x37,0x6E,0xF3,0x7E,0xEB,0x37,0xEF,
+0xFF,0xC1,0xFF,0xFE,0xFF,0xF7,0xEF,0xFF, 0xFF,0xFF,0xBF,0x3F,0xD2,0xDF,0xBF,0x2F,
+0x7B,0xE2,0xFF,0xFE,0x3B,0xBD,0xDB,0xFF, 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFE,
+0xFF,0xFB,0xFF,0xFF,0xBF,0xFF,0xFB,0xDF, 0xFF,0xBF,0xFF,0xB7,0xFF,0xFF,0xBF,0xEF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF, 0x7F,0xFF,0x1F,0xEF,0xF1,0xFD,0xFF,0xF6,
+0xAF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF, 0xFF,0xFF,0xFE,0x9F,0xFF,0xFF,0xFF,0x77,
+0xEF,0xF7,0xFB,0xFF,0xFE,0x5F,0xFF,0xFF, 0xBF,0xCF,0xFB,0xF7,0xDD,0xF7,0xF5,0xFF,
+0x5F,0xD5,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5, 0xFF,0xFB,0x0F,0xFF,0xFF,0xA9,0xEA,0x7A,
+0xFF,0xAF,0x8F,0xFE,0xDF,0xAF,0xEF,0xFB, 0xFE,0xFF,0xBF,0xEF,0xFB,0xDF,0xE5,0x5F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xBD,0x57,0xFF, 0xFF,0x6F,0x77,0xBF,0xF7,0xFB,0xFF,0x7F,
+0xBF,0xF7,0xFF,0xFC,0xBF,0xFF,0x9F,0xFF, 0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF,0x1F,
+0xCF,0xFF,0xFC,0xFF,0xFF,0xFF,0xFF,0xFB, 0x65,0xAF,0xF3,0x7C,0xFF,0x3F,0xDF,0xFF,
+0xFD,0xE9,0xFE,0x7F,0xE7,0xFF,0xFE,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFD,0xE3,0xDF,0xFB,
+0xDB,0xF6,0xFD,0xEF,0x5B,0xFB,0xFF,0xDF, 0xFC,0xFF,0x3F,0xDF,0xF3,0xFD,0xFF,0x7F,
+0xDF,0xEF,0x66,0xFF,0xDF,0xAD,0xEB,0x7A, 0xDE,0xF7,0xF7,0xE7,0xD9,0xFD,0x9F,0x67,
+0xD9,0xF6,0x7D,0x9F,0xE7,0xDF,0xF5,0x47, 0xFD,0x65,0x5B,0xD6,0xF4,0xFE,0xFF,0xEF,
+0xFF,0x6D,0xF6,0xDD,0xB7,0x6D,0xDB,0x76, 0xDC,0xB7,0x7D,0xFA,0x9B,0xF6,0x6D,0x9D,
+0x67,0x59,0xDF,0xF7,0xDD,0xFF,0xEB,0xFE, 0xBF,0xAF,0xEB,0xFA,0xFE,0xBF,0xAF,0xE3,
+0xD1,0x9F,0xFF,0xBD,0xBF,0xEF,0xFE,0xF7, 0xBF,0xBF,0xF7,0xD7,0x7F,0xDD,0xF7,0x9D,
+0xDF,0x7F,0xDF,0xF7,0xFF,0xE0,0x7F,0xFD, 0xC1,0xDF,0xF7,0xFD,0xC7,0x7F,0x7F,0xFB,
+0xFF,0xBB,0xEC,0xFB,0x3E,0xFF,0xBF,0xEC, 0xFB,0xFF,0xD8,0x7F,0xBF,0x6C,0xFF,0xBE,
+0xFF,0xBF,0xED,0xFF,0xEF,0xFE,0xFB,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEE,0xFF,0xC5,
+0xFF,0xAF,0x6F,0xFF,0xFC,0xFD,0x3F,0xE7, 0xFF,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,
+0xEF,0xFB,0xFE,0xBF,0x89,0xFE,0xFA,0xBA, 0xFE,0xBF,0xAF,0xFB,0xF6,0xF5,0xD9,0x7D,
+0x97,0x65,0xD9,0x74,0x5D,0x97,0x65,0xD3, 0xFE,0xD6,0xFF,0xBF,0xF7,0xFD,0xFF,0x7F,
+0xBF,0xCF,0xFB,0xFE,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xEF,0xFB,0xFF,0xF6,0x8F,0xFB,
+0xFF,0xEF,0xFB,0x7E,0xDB,0xFE,0xFF,0xBE, 0xEF,0xEE,0xFB,0xBE,0xEF,0xBB,0xEE,0xFB,
+0xBE,0xFF,0xFF,0xDF,0xFF,0x43,0xFF,0xFF, 0xFB,0xEF,0x5F,0xB7,0xFE,0x7F,0xE7,0xF9,
+0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xF9, 0xBF,0xFE,0xAF,0x77,0xFD,0xFF,0x2F,0xAF,
+0xA7,0xFE,0xFF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xF1,0x7F,0xEF,0xDF,
+0xFF,0x97,0xF5,0xEF,0xFF,0xDF,0xFF,0xFF, 0xBF,0xFF,0xBF,0xFF,0xFF,0xFE,0xFF,0xFF,
+0xFF,0xE0,0xFF,0xFF,0xF9,0xFE,0x2F,0x8B, 0xE3,0xF8,0xBE,0x77,0x9F,0xF9,0xDA,0x77,
+0x9D,0xE7,0x79,0xDE,0x77,0x9F,0xDD,0xFF, 0xFD,0xFD,0x7F,0x5F,0xD7,0xFD,0xFF,0x7F,
+0xE7,0xFE,0x7F,0x97,0xE7,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFF,0xAB,0xFF,0xEF,0xFA,0xFE,
+0xBF,0xAF,0xFF,0xFA,0xFF,0xFF,0xDF,0xFF, 0xFB,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,
+0x67,0xFF,0xF7,0xF5,0xFF,0xFF,0xFF,0xDF, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xEF,0xFF,0xBD, 0xEB,0xFF,0xFF,0xF7,0xAD,0xEB,0xFF,0xDF,
+0xFD,0xFF,0x3F,0xDF,0xF7,0xFD,0xFF,0x7F, 0xDF,0xFF,0x5F,0xFF,0xF7,0xFF,0xFF,0xFD,
+0xBF,0xFF,0xCB,0xF4,0xFF,0x7F,0xD3,0xF7, 0xFD,0x3F,0x7F,0xD3,0xF7,0xFF,0xFC,0x3F,
+0xFF,0xEA,0xFA,0xBE,0xAF,0xAB,0xEB,0xBA, 0xF4,0x95,0x6B,0x52,0xD4,0xAD,0x2F,0x4A,
+0xD2,0xF6,0xBF,0xD2,0x7F,0xF7,0x3F,0xFF, 0xFF,0xF3,0x7F,0xFF,0xFF,0xF7,0xFF,0xBA,
+0xDF,0xFB,0xFD,0xFF,0xBF,0xFF,0xFB,0xFF, 0xF8,0x7F,0xEA,0xFF,0xFE,0xFE,0xDF,0xFF,
+0xF7,0xFF,0x7F,0xBB,0xFF,0xFF,0xBF,0xDF, 0xFB,0xFF,0xFF,0xBF,0xFF,0xB1,0x7F,0xFF,
+0xFB,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF, 0xCF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF7,0xFF,
+0xFF,0xFF,0xF1,0xFF,0x69,0xBE,0xFA,0xBF, 0xAF,0xE2,0xFF,0xFE,0xFD,0xAF,0xF3,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xFC,0xFF,0xFF,0x07, 0xFD,0x95,0xDB,0xDF,0x7F,0xDF,0xAF,0xFF,
+0xF7,0xAF,0x36,0xFE,0xBF,0x65,0xEB,0xF6, 0xFE,0x9F,0x6F,0xFE,0x07,0xFF,0xCF,0xFF,
+0xF8,0xFE,0xFF,0xCF,0xFF,0xF6,0xFA,0xE7, 0xFB,0xFE,0xFF,0xBB,0xED,0xF9,0xFF,0xFF,
+0xFF,0x5F,0xFF,0xFF,0xFF,0x75,0xFF,0xEF, 0x7E,0xFD,0xE0,0xE8,0x5E,0xD3,0xE5,0xF9,
+0x3E,0x5F,0xD7,0xF7,0xFF,0xFA,0x2F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0x7F,
+0x7F,0xD7,0xF5,0x7D,0x5F,0x57,0xD5,0xF5, 0xEF,0xFF,0xF3,0x7F,0xFC,0x7F,0xFF,0xC7,
+0xF1,0xFF,0xFF,0x1F,0xCF,0xB0,0xFF,0x3F, 0xCF,0xF3,0xFC,0xFF,0x3F,0xCE,0xFF,0xE4,
+0xFF,0xDF,0x7F,0xFE,0xF7,0xBB,0xFF,0xFF, 0xDF,0xEF,0xEE,0xFF,0xBF,0xEF,0xFB,0xFE,
+0xBF,0xBF,0xEF,0xFF,0xD1,0xFF,0xFF,0xFF, 0xFD,0xFB,0xFF,0xFD,0xFF,0xFB,0x9F,0xE9,
+0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0xBF, 0xFF,0xB3,0xFF,0xFF,0xF7,0xFF,0xFF,0xAF,
+0xF7,0xFF,0xB6,0x3F,0xEB,0xFA,0xFE,0xBF, 0xAF,0xEB,0xFA,0xFE,0xBF,0xFE,0xA7,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF, 0xFE,0x9F,0xF7,0xF9,0xFF,0x7F,0x9F,0xE7,
+0xFF,0xFF,0xFE,0xAF,0x6F,0xFF,0xFF,0xFF, 0x9F,0xFF,0xDF,0xFF,0x7D,0x5F,0xDD,0xFF,
+0xFB,0xBF,0xE7,0xBB,0xFF,0xFB,0xDF,0x6D, 0x5F,0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xEB,0xF7,0xFF,0xE7,0xEF,0xF7,0xFF,0xFF, 0x7F,0xFF,0xF7,0xFF,0xFC,0x8F,0xFF,0xEF,
+0xFD,0xFE,0xFF,0xBE,0xF4,0xF2,0x7D,0xD7, 0xCF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xCF,0x6B,0xFF,0xBF,0x3F,0xFB,0xF2, 0xFC,0x7F,0xEB,0xFF,0x9F,0xFA,0xFF,0xFF,
+0x3F,0xFF,0xF3,0xFF,0xFF,0xFD,0x70,0xF7, 0xFF,0xFF,0xBF,0xFF,0xFB,0xD7,0xFE,0xF5,
+0x77,0xFF,0x15,0xDD,0x77,0xFD,0xFF,0x7F, 0xDF,0xF7,0xFB,0xCD,0xBF,0xFF,0xFD,0xFF,
+0xFF,0xDF,0x37,0xCD,0xF9,0xEC,0xFE,0xEF, 0xBB,0xF4,0xFB,0x3F,0x4F,0xB3,0xFF,0xFD,
+0xCB,0xFF,0xE9,0x7E,0x54,0x9F,0xE5,0x4B, 0xB7,0xFF,0xDD,0x7D,0xC7,0x71,0xDD,0x77,
+0x5D,0xD7,0x75,0xCD,0x7F,0xD6,0xFF,0xD3, 0xF6,0xF9,0x3F,0x6D,0x95,0xAF,0x7F,0xFE,
+0xFF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFE,0xF6,0xC7,0xFF,0xAD,0x7B,0xCA,0xFF,
+0xBF,0xBF,0xEF,0xFD,0xE3,0xDF,0xB7,0xED, 0xFB,0x7E,0xDF,0x37,0xED,0xE3,0xFB,0xDF,
+0xFF,0x52,0x5C,0x15,0xFD,0xCF,0x7F,0xDF, 0xFE,0xEF,0xEF,0xFB,0xFE,0xFF,0xBF,0xEC,
+0x7B,0xFE,0xFF,0xFE,0x3E,0x7F,0xDA,0xF7, 0xFD,0xFF,0x7F,0xFF,0xFF,0xFB,0xEF,0xBB,
+0x6F,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF, 0xF7,0x7D,0xFF,0xD8,0xFF,0xFD,0xBF,0x7F,
+0xFB,0xFF,0xFF,0x9F,0xFB,0xFE,0x7F,0x9F, 0xE7,0xF9,0xFE,0x7F,0x9F,0xEA,0x7F,0xF6,
+0xBF,0xBD,0x6A,0x5A,0xF6,0xE5,0xBF,0x77, 0x5F,0x6D,0xDD,0x77,0x5D,0xD7,0x75,0xDD,
+0x77,0xFF,0xA5,0xBF,0xCF,0xFB,0xFF,0xFF, 0xBF,0xCF,0xFB,0xFD,0xFF,0xBF,0xF3,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD,0xAB, 0xFF,0xBF,0xBF,0xFF,0xFB,0xFF,0x7F,0xEF,
+0xFF,0xBE,0xFB,0xEE,0xFB,0xBE,0xEF,0xBB, 0xEE,0xFB,0xBF,0xFF,0xB5,0xFF,0xD0,0xBC,
+0xFD,0x2F,0x4B,0xF7,0xFF,0xFF,0x9F,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,
+0xFA,0x8F,0xFD,0xAB,0xFA,0xDA,0xBF,0xAF, 0xB3,0xFD,0xFF,0xBF,0xFB,0xFE,0xFF,0xBF,
+0xEF,0xFB,0xFE,0xF7,0xBF,0xFF,0x9F,0xFF, 0x77,0xF7,0xBD,0xFD,0x77,0xDF,0xFF,0x7E,
+0xDF,0xED,0xBB,0xFE,0xFF,0xBE,0xEF,0xFB, 0xFE,0xFF,0xFA,0x3F,0xFF,0xBE,0x6F,0x8F,
+0xE6,0xF9,0xFE,0x7F,0x9F,0xC7,0xFE,0x7F, 0x9F,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7,0xFB,
+0x7F,0xFF,0x7F,0xCF,0xFF,0xFD,0xFF,0xFF, 0xDF,0xFB,0xAF,0xBF,0xEF,0xFF,0xFE,0xFF,
+0x9F,0xEF,0xFB,0xFF,0xFC,0xFF,0xFB,0xFE, 0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xF7,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF5,0xFF,0xFF,0xFF,0x3F,0xDF,0xF7,
+0xFF,0xFF,0x7F,0xEF,0xFE,0xFF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xEF,0xFF,0xB3,0x7F,
+0xFF,0x7B,0x5E,0xF7,0xFD,0xFF,0x7B,0x7F, 0xF7,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
+0xDF,0xF7,0xFF,0x17,0xFF,0xFF,0xFF,0x7F, 0xFF,0xFF,0xDD,0xF6,0xFC,0xBF,0xCB,0xF2,
+0xBC,0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xFE, 0x8F,0xFF,0xFA,0x7E,0xBF,0xA7,0xEB,0xDA,
+0xFC,0xBF,0xAF,0x7A,0xFE,0xBF,0xAF,0xEA, 0xFA,0xFE,0xBF,0xAF,0xF4,0xDF,0xFE,0xFF,
+0xF3,0x3C,0x7F,0x3E,0xFF,0xCF,0xF8,0xBF, 0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xE7,0xE8,
+0xFF,0xFC,0x9F,0xFF,0xFF,0xCF,0xEB,0xB3, 0xE7,0xFB,0x7B,0xF3,0xFE,0xFF,0xCF,0xDB,
+0xFB,0xFB,0xBF,0x6F,0x6F,0xDF,0xEC,0x7F, 0xFF,0xFF,0xF7,0xFD,0xFD,0xFF,0xFF,0xFF,
+0xFF,0xB2,0xBF,0xFF,0xDE,0xFD,0xBD,0xEF, 0xFB,0xF6,0xDF,0xEA,0xE7,0xDB,0xFE,0xBB,
+0xFF,0xEB,0xFB,0xBF,0x9F,0x8F,0xE8,0xFE, 0x3F,0x8F,0xA3,0xF8,0xFE,0x3F,0x8F,0xFF,
+0xF8,0x7E,0xFD,0xFD,0x7F,0xFF,0xFB,0xCD, 0xFF,0xFD,0xFF,0x5F,0xEF,0xFD,0xFF,0xFF,
+0xDF,0xF7,0xFD,0xFF,0xBE,0x90,0xFF,0xFF, 0xEE,0xFF,0x3F,0xBF,0xF3,0xBB,0xFE,0xB7,
+0xAB,0xFA,0xFE,0xAF,0xAD,0xEA,0xFA,0xDE, 0xAB,0xFF,0x63,0xFF,0xFE,0xF2,0xFF,0xB3,
+0xFF,0xDF,0xEE,0x7D,0xFF,0x03,0xF1,0xF4, 0x3F,0x1F,0xC3,0xF1,0xEC,0x7F,0xFE,0x6F,
+0xFF,0xFB,0xFB,0xFF,0x9F,0xFF,0xBF,0xFF, 0x7B,0x5F,0xFD,0xFF,0xDF,0xF7,0xFD,0xFD,
+0x7F,0x7F,0xDF,0xFE,0xCF,0xFB,0xFF,0xFF, 0xAF,0xFB,0xFF,0x1F,0xEF,0xA5,0xFD,0xBF,
+0xDF,0xFB,0x7D,0xFF,0xBF,0xDF,0xFB,0xFF, 0xFD,0x3B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
+0xAF,0xF3,0xFF,0xFB,0x7F,0xBF,0xD7,0xFB, 0xBF,0x7F,0xBB,0xF7,0xFF,0xF8,0x7F,0xFF,
+0xFA,0x5F,0xD7,0xFF,0xDF,0x7F,0xEF,0xFF, 0xFF,0x7F,0xDB,0xF7,0xFD,0xFF,0x7F,0xDF,
+0xB7,0xFB,0xEC,0xFF,0xFF,0xF7,0xBF,0xEF, 0xFD,0xFC,0xFB,0xFF,0xEF,0xF0,0xFE,0x3F,
+0x8F,0xE3,0xF8,0xFE,0x3F,0x8F,0xEF,0x8D, 0xFF,0xFF,0xEF,0x7F,0xBF,0xFF,0xFB,0xFF,
+0xDB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0xD8,0xFF,0x2E,0x7F,
+0xBE,0xEF,0xFE,0x6E,0xFF,0xBF,0xF9,0xFF, 0xFF,0xF3,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFC,0x66,0xBE,0x47,0xF3,0x7F,0xDF,0xFE, 0x87,0x9F,0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xD6,0x6F,0x7C, 0xFB,0x4F,0xD2,0xFF,0xFD,0x2B,0xFE,0xFF,
+0xFF,0xFD,0x5F,0xD7,0xD5,0xF5,0x7D,0xFF, 0xFF,0xFF,0xBF,0x9B,0xFF,0xFF,0xDF,0xB7,
+0xFF,0xFF,0xDF,0xFF,0x3F,0xCF,0xFE,0x7F, 0xBF,0xEF,0xFB,0xFC,0xFF,0x3F,0xFF,0xD9,
+0xBF,0xFE,0x97,0xEC,0x8F,0xB7,0xFE,0x9B, 0x7D,0xFD,0xB7,0xDD,0x77,0x1D,0xC7,0x71,
+0xDD,0x77,0x5D,0xD7,0xF3,0x6F,0xFD,0x3F, 0x73,0xDD,0xAF,0xFD,0x7A,0xFF,0xFF,0xAF,
+0xFE,0xFD,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF, 0xEF,0x66,0x7F,0xFF,0xFF,0xBF,0xBF,0xFF,
+0xFB,0xFF,0xF7,0xDF,0xFD,0xFB,0x7D,0xDF, 0xB7,0xCD,0xF3,0x7C,0x5F,0x3F,0x91,0x3F,
+0xFF,0x3D,0xEF,0x7B,0xFF,0xFC,0xFF,0xCA, 0xEF,0xFE,0xFF,0xBD,0xEF,0xFB,0x1E,0xE7,
+0xBB,0xEC,0x7F,0xB3,0xFF,0xFD,0x9F,0xFF, 0xFF,0xFE,0xFF,0xFF,0x7F,0xBF,0xFB,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xEE,0xFB,0xBF,0xDF, 0x67,0xFF,0xFF,0xBF,0xEF,0xDB,0xFF,0xBC,
+0xFE,0x7F,0xFB,0xFF,0x9F,0xEF,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x87,0xFF,0xEE,
+0xFB,0xBE,0xE5,0xBF,0xEF,0xF9,0xD7,0x65, 0xF7,0xDD,0xE7,0x7D,0xDF,0x77,0x5D,0xD7,
+0x7F,0xF8,0x9B,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xBF,0xEF,0xFB,0xFF,0x7F,0xCF,
+0xF3,0xFC,0xFF,0xBF,0xEF,0xFF,0xDB,0x3F, 0xEF,0xFB,0xFE,0xFF,0xDF,0xFF,0xFE,0xFB,
+0xBB,0xEF,0xBF,0xEF,0xBB,0xEE,0xFB,0xBE, 0xEF,0xBB,0xFF,0xFC,0x7F,0xFD,0x3B,0x5B,
+0xD6,0xE5,0xFD,0x4F,0xC3,0xFB,0xFF,0xBF, 0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFF,
+0xB4,0xFF,0xFA,0xBC,0x8F,0xB2,0xE9,0xD2, 0x2E,0xCF,0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,
+0xFF,0xBF,0xEF,0xFB,0xFF,0xEC,0xFF,0xFD, 0xFD,0x7F,0xDF,0xF7,0xE4,0xDF,0x5F,0xFF,
+0xFF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xC3,0xFF,0xEF,0xE6,0xF8,0xFE,
+0x3F,0x8B,0x83,0xF9,0xFE,0x7F,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x17,
+0xFD,0xFF,0xFF,0xFF,0x7F,0x5F,0xF7,0x2C, 0xFF,0xFF,0xFF,0xFE,0x7F,0xFF,0xE7,0xF9,
+0xFE,0x7F,0x9F,0xFE,0x2F,0xFF,0xFF,0xEF, 0xFF,0xFE,0xBF,0xEF,0xAD,0xFF,0xFF,0x7F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFE,0xDF,0xFF,0xDF,0xFF,0xFD,0xFD,0x7F,
+0xDF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0x3F,0xFE,
+0xF7,0xFD,0xEF,0x7A,0xFF,0xB1,0xBD,0xFF, 0x7F,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,
+0xFF,0x7F,0xF3,0x27,0xFF,0xDF,0xFF,0xDD, 0xFF,0xFC,0x9B,0xFF,0xCB,0xFC,0xBF,0x2F,
+0xCB,0xF2,0xFC,0xBF,0x2F,0xC9,0xFF,0xDE, 0xFF,0xDF,0xAF,0xEB,0xDA,0xFE,0xBB,0xAF,
+0xEB,0xF8,0xF7,0xAF,0xE8,0xFA,0xFE,0xBF, 0xAF,0xEB,0xF2,0xFF,0xFD,0xFF,0xFF,0xEF,
+0xBD,0xD7,0xBF,0xFF,0xFF,0xDE,0x8F,0xB8, 0xDE,0x37,0x8D,0xA3,0x78,0xDA,0x3F,0x8F,
+0xFF,0xA1,0xFF,0xFF,0xFB,0xFB,0xFF,0xFF, 0xFF,0xFF,0xA7,0xBD,0xFB,0x76,0xFD,0xBF,
+0xEF,0xDB,0xFE,0xBB,0xBF,0xFE,0x27,0x7F, 0xFF,0xFE,0xFE,0xFD,0xF5,0xFF,0xEF,0xF5,
+0xDF,0x1F,0xE7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0xFF,0xCD,0xFD,0xAE,0xFF,0xFA,
+0x3E,0x3F,0xAB,0xFD,0xF8,0x7E,0x8F,0xE3, 0xF8,0xFE,0x3E,0x8F,0xE3,0xF8,0xFF,0xFE,
+0x1F,0xEF,0xDF,0xBF,0xFE,0xDE,0xDF,0xD9, 0xFF,0xDF,0xBC,0xFF,0xFF,0x7F,0xFF,0xEF,
+0xFD,0x7F,0xDF,0xF7,0xF9,0x3F,0xFE,0xFF, 0xFF,0x6F,0xFE,0xDE,0xBF,0xF7,0xED,0xEA,
+0xFD,0x8F,0x83,0xF8,0xEA,0x3F,0x8F,0xEF, 0xFF,0xF4,0x7F,0xFF,0xEF,0xEF,0x7B,0xF3,
+0xF1,0x5F,0xFF,0xFF,0xF1,0x3B,0x7F,0xDF, 0xF7,0xFD,0xFF,0xFF,0xFF,0xFF,0xE0,0xFF,
+0xFF,0xFF,0xF7,0xFF,0x6F,0xFF,0x7F,0xFF, 0xFF,0xF7,0xDE,0xF7,0xBF,0xEF,0xFB,0xF7,
+0xFD,0xFF,0xFF,0xF5,0xFA,0xFF,0xFF,0xFB, 0xE7,0xFF,0xF3,0xF8,0x7F,0xF3,0xDF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0xEF, 0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,
+0xFF,0x7F,0xFF,0x9F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xCF,0xFF,0x37,0xFF,0xFF,
+0x7F,0xDF,0x77,0x5D,0xE7,0xFC,0xFF,0xBF, 0xF7,0xF5,0xFB,0xFF,0xFF,0xD7,0xF5,0xFB,
+0xFF,0xFF,0x45,0xFD,0x7F,0xEA,0xFD,0xBE, 0xBF,0xDF,0xF7,0xFF,0xFF,0xDB,0xFB,0xFE,
+0xFF,0xBF,0xEF,0xFF,0xFF,0xFF,0xFB,0x5F, 0x7F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFE,0xFF,0xEF,0xFD,0xFF,0x7F,0xDF, 0xFF,0xEF,0xFB,0xF8,0x0F,0xF3,0xFF,0xF9,
+0x2E,0xFB,0xFE,0xFC,0xF3,0xEF,0xFF,0xFF, 0xBF,0xFF,0xFB,0xE7,0xFF,0xFE,0x7E,0xFF,
+0xC0,0x6B,0xCF,0xFF,0x34,0xDF,0xF1,0xFD, 0xFF,0xEF,0xFF,0xFF,0xFF,0xDF,0xF7,0xFD,
+0xCF,0x7F,0x9C,0xFD,0xFD,0x6C,0xF7,0xFF, 0xF6,0xFD,0xEB,0x2B,0x9F,0xFF,0xFC,0xFE,
+0x7E,0xFF,0xFF,0xFF,0xFF,0xD7,0xF3,0xF7, 0xFF,0xFB,0xE1,0xBF,0xFF,0xEB,0x7A,0xDE,
+0xD7,0xFB,0xFF,0xF9,0xFE,0xFF,0xFF,0xF3, 0xDE,0x7F,0xFD,0xE7,0x7F,0xFF,0xFD,0xBB,
+0xFF,0xFF,0x7E,0xCC,0xF6,0xAF,0x5F,0x7F, 0xFE,0xF4,0x7D,0xF7,0xFD,0xBB,0x6E,0xDB,
+0xB7,0xFF,0xF7,0xDF,0x66,0xFF,0xFF,0xF7, 0x3D,0xCF,0xDE,0xBD,0xFF,0xFF,0xDE,0xDB,
+0x8D,0xF7,0x7E,0xDF,0xB7,0xEF,0x7F,0xFF, 0xF6,0x87,0xFF,0xFF,0xEF,0xFE,0xDE,0xBF,
+0xFF,0xFF,0xFF,0xBB,0xEF,0xFD,0xFF,0x7B, 0xDE,0xF7,0x3F,0xFF,0xBF,0xFB,0xDB,0xFF,
+0xF2,0xB6,0xFD,0xBD,0x7F,0xE7,0xFF,0xFF, 0xFF,0x6F,0xF7,0xFF,0xFF,0xFF,0xFE,0x77,
+0xFF,0xBF,0xF8,0xAF,0xFF,0xDF,0xBF,0xFF, 0xBF,0x7F,0xFB,0xFF,0xFF,0xFF,0xDB,0xFE,
+0xFF,0xBF,0xFF,0xFA,0xFF,0xFD,0xFF,0xF6, 0x7F,0xFF,0x9F,0xFF,0xFF,0x3F,0xEF,0xF8,
+0xEE,0x7E,0x9F,0xBA,0xFE,0xBF,0x8F,0xEF, 0xFE,0xFE,0xF9,0xFF,0xFA,0x7F,0xFE,0x7E,
+0xBF,0xAF,0xFB,0x96,0xFD,0x9F,0xEF,0x5E, 0x65,0xBE,0xEF,0x5B,0xB6,0xFF,0xBE,0xE3,
+0xFF,0xB5,0xBF,0xFF,0xFD,0xFF,0x7F,0xFF, 0xEF,0xDF,0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,
+0xBF,0xCF,0xFF,0xFF,0xFF,0xFD,0x9B,0xFF, 0xFE,0xFB,0xFE,0xDF,0xFF,0x7F,0xFF,0xF7,
+0xFE,0xFF,0xDF,0xFB,0xFB,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xB7,0xFE,0xFA,0xFF,0xAB,
+0xEF,0xFF,0xFD,0xB5,0x7B,0x7F,0xFB,0xF7, 0xFD,0xFF,0xFF,0xDD,0xFF,0xEF,0x8F,0xFF,
+0x2F,0xFF,0xFB,0x7C,0xFF,0x3F,0xDF,0x73, 0xEB,0xFE,0x3F,0xFF,0xEF,0xFB,0xFE,0xFF,
+0xEF,0xFD,0xFF,0xBF,0xFD,0x0F,0xFF,0xFF, 0xFF,0xF5,0xF9,0xFF,0x7F,0xD7,0xFD,0xFF,
+0xDF,0xFF,0xF7,0xFB,0xFF,0x7F,0xBF,0xFF, 0xFF,0xF0,0x9F,0xFF,0xFE,0x7F,0x8B,0xE3,
+0xF9,0xDE,0x27,0x9B,0xE6,0xBE,0x7F,0x9B, 0xC3,0xF8,0xDE,0x7F,0x9D,0xE7,0xFE,0x7F,
+0xFF,0xFF,0x5F,0xD7,0xFF,0xFF,0xFF,0x4F, 0xFB,0xFF,0xFF,0x7F,0xFF,0xAF,0xFF,0x9F,
+0x7F,0xFB,0xFF,0xE8,0xFF,0xFF,0xFE,0xBF, 0xAF,0xFF,0xFF,0xFE,0xBF,0xEF,0xF7,0xFF,
+0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFC,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,
+0xFD,0x3F,0xCF,0xFF,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFD,0x7F,0xFF,0xFF,0x93,0xFF,0xFF,
+0x7A,0xDF,0xF7,0xFF,0xFF,0x7B,0x7F,0xB7, 0xEF,0xFF,0xFF,0xFD,0xBF,0xFD,0xFB,0xFF,
+0xF7,0xFF,0xD7,0xFF,0xFF,0xFF,0xFC,0x9F, 0x6F,0xCB,0xFF,0xF4,0xBB,0xDF,0xD6,0xFD,
+0xBF,0x2F,0xD3,0xF7,0xFF,0xDF,0xFF,0xCF, 0xFF,0xFA,0xBE,0xBD,0xAF,0x6A,0xDA,0xBE,
+0xBB,0xAB,0x3A,0xBE,0x2D,0xAE,0xEB,0xDA, 0xF6,0x3F,0xAD,0xF5,0xDD,0xFF,0xCF,0xF1,
+0xFF,0xF9,0x7F,0xFF,0x73,0xFE,0xFF,0xCF, 0xC3,0xF4,0xF7,0x2F,0xF3,0xFF,0xFC,0xFF,
+0x7C,0x1F,0xFF,0x3F,0x4F,0xFF,0x7E,0xFF, 0xEF,0xBD,0xF6,0xFE,0xFF,0x2B,0xEF,0xDC,
+0xFB,0xFD,0xFF,0xFB,0xFF,0xEA,0x7B,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFB,0xF7,0xDF,0xFF,
+0xE3,0x7D,0xFF,0xB7,0xFF,0xBF,0xFF,0xFF, 0xDF,0xFF,0xF8,0xFF,0xBF,0xFF,0xBF,0xEB,
+0xE7,0xFA,0xFE,0x3D,0xBF,0xE9,0xFC,0xBF, 0xFF,0xFA,0xFB,0xFE,0xFF,0xFF,0xFF,0xD9,
+0xFF,0xFF,0xFF,0xF6,0x7F,0xFF,0xF6,0x7D, 0xFF,0xDF,0xCF,0xFD,0xBF,0xFB,0xEF,0x7E,
+0xFF,0x7F,0xFF,0xFF,0xD3,0xFF,0xFD,0xFB, 0xFF,0xFB,0xFF,0xFF,0xFF,0xEF,0xFF,0xBF,
+0xFE,0xFF,0xF7,0xEF,0xFF,0xFF,0xFF,0xFB, 0xFF,0x87,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,
+0x7B,0xFE,0xFF,0xFE,0x3B,0xF7,0xF7,0xFF, 0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,
+0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xFF,0xF7, 0xFF,0xFF,0xAD,0xFF,0xFE,0xF7,0xFF,0xFF,
+0x5F,0xFF,0xFF,0xDF,0xFF,0xFD,0xFF,0xF5, 0xFF,0xDF,0xFF,0xBD,0xFF,0xE9,0xFF,0xC7,
+0xF3,0xFF,0xFF,0xF7,0xFF,0xF3,0xFF,0xF8, 0x3B,0xFF,0xFF,0x7B,0xDF,0xBF,0xFB,0xEF,
+0xFB,0xFF,0xFB,0xF7,0xF7,0xBB,0xFF,0xFF, 0xFF,0xFF,0xFB,0xFF,0xFE,0x7F,0xF3,0x7F,
+0x5E,0xB7,0xBF,0xFD,0x7F,0xFF,0xF9,0x7F, 0xFB,0xFF,0xEB,0xFD,0x7F,0x7F,0xFF,0xEF,
+0xFB,0xE0,0x3F,0xFE,0xBF,0xBF,0xDF,0xFF, 0x7E,0xFF,0xF7,0xFF,0xFF,0xFE,0xBF,0xFF,
+0xDB,0x78,0xFF,0xFF,0xFF,0xEE,0xA1,0xBF, 0xF5,0xDE,0xFB,0xF7,0xFF,0xFB,0xFF,0xFF,
+0xFF,0xFF,0xFB,0xFF,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xEF,0xF0,0xFF,0xFF,0xFF,0xF3,
+0xF7,0xFF,0xEF,0xFF,0xE7,0xCF,0xFF,0xFB, 0xFF,0xEF,0xFF,0xFF,0x9F,0x9F,0xEF,0xFC,
+0x16,0xBF,0xFE,0xF3,0xE4,0xFF,0xFF,0xC6, 0xFF,0xE7,0xFF,0xFF,0xFD,0xFF,0xBF,0xFF,
+0xFF,0x3F,0xFF,0xBF,0xD6,0xAF,0x7F,0xFE, 0x6B,0x7E,0x7F,0xFF,0xAF,0xFF,0xFF,0xBF,
+0xFF,0x5F,0xFF,0xFE,0xFF,0xFF,0xFE,0xFF, 0xFF,0xBD,0xDB,0xFF,0xFE,0x5F,0xF2,0xFF,
+0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xEF,0x7F,0xFF,0xFF,0xFF,0xFF,0xDE,0xBF,
+0xFF,0xFF,0xEF,0xFB,0x77,0xFE,0xBD,0x7F, 0x5F,0xFF,0xFF,0xFF,0xDF,0x6F,0xED,0xFF,
+0xFD,0xFF,0x7F,0xFD,0x6F,0xFF,0xFF,0x77, 0xDA,0xCF,0xFD,0x5F,0xFF,0xBF,0xFF,0xFF,
+0xDF,0x7F,0xFF,0xFB,0xFF,0xFF,0xFF,0xFF, 0x66,0x7F,0xFF,0xFE,0xBF,0xE7,0xBF,0xFA,
+0xFF,0xFE,0xFF,0xFF,0xFF,0xDF,0xFF,0x59, 0xEF,0xFF,0xEF,0xFB,0x7F,0x89,0xFF,0xFF,
+0xE9,0xFF,0x6F,0xFF,0xF5,0xFF,0xFF,0xFF, 0xFF,0xFF,0x7F,0xF2,0xF7,0xFF,0xFF,0xEF,
+0xF8,0x7F,0xFB,0xFF,0xFD,0xFF,0xFF,0xD9, 0xFF,0xEF,0xBB,0xFF,0xFF,0xFF,0xBF,0xEF,
+0xDE,0xFF,0xFF,0x9F,0x7F,0xDF,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,0xAF,
+0xFF,0xFF,0xF7,0x3F,0xEB,0x9F,0xFE,0x7F, 0x9E,0x7F,0x9F,0xFE,0x87,0xFF,0xED,0xDB,
+0x56,0xFF,0xBF,0xAF,0x0B,0xD2,0xFF,0xEF, 0xDB,0x6E,0x7D,0xBD,0x6F,0xF8,0xFE,0x3F,
+0xFA,0x5B,0xFF,0xFD,0xBF,0xEF,0xFF,0xBF, 0x6F,0xDB,0xE6,0xFF,0xFF,0x3F,0xFF,0xDF,
+0xFE,0xFF,0xFF,0xFF,0xFF,0xDA,0x3F,0xFF, 0xFB,0xFE,0xFE,0xFF,0xFF,0xDF,0xF7,0xBD,
+0xFF,0xFD,0xFF,0xFE,0xFF,0xFB,0xFF,0xFF, 0xFF,0xFF,0xF1,0x5F,0xFD,0x9F,0xDF,0xFD,
+0xFF,0xFD,0x7F,0xFF,0xFF,0xFF,0xFF,0x76, 0xFA,0xFF,0xFF,0x7F,0xE3,0xF8,0xFF,0xAE,
+0xFF,0xFB,0x7E,0x9D,0x73,0xFF,0xFA,0x7F, 0xDF,0xFF,0xFF,0x7F,0xFF,0xFB,0xCD,0xFF,
+0x7F,0xEF,0xFB,0xFF,0xFD,0xFF,0xF7,0x7F, 0x7F,0xEF,0xFF,0xED,0xFF,0xFF,0xFF,0xB5,
+0xFF,0xBF,0xFF,0xBF,0xFD,0xEF,0xDB,0xF7, 0xFF,0x93,0xFF,0xEF,0xE2,0xF9,0xBE,0x7F,
+0x8B,0xE7,0xF9,0xFE,0x6B,0xE7,0xF9,0xFE, 0x7F,0x9F,0xE7,0xF9,0xFE,0x7F,0x47,0xFF,
+0xFF,0xFD,0xFF,0x9F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xF5,0xFF,0x9F,0xFF,0xF7,0xFE,
+0xFF,0xBF,0xFE,0x6F,0xFF,0xFF,0xFB,0xFF, 0xFF,0xFF,0xAF,0xFF,0xFF,0xFF,0x7F,0xFB,
+0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xDF,0xFF,0xFF,0xF7,0xFF,0xFF,0xFF,0xDF,
+0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,0xFF,0xFF, 0x5F,0xFB,0xFE,0xFF,0xF8,0x37,0xFF,0xFF,
+0xEF,0xFF,0x7F,0xFE,0xBF,0xFF,0xFF,0xFE, 0xBF,0xFF,0xFF,0x7F,0xFF,0xBF,0xFD,0xFF,
+0x7F,0xFA,0x7F,0xFF,0xFF,0x6F,0xFF,0xFF, 0x7D,0xFF,0xCF,0xFF,0xFF,0xFF,0x4F,0xFF,
+0xF2,0xFF,0xFF,0xFF,0xFF,0xFF,0xFA,0xBF, 0xFF,0xAE,0xEB,0xFA,0xFE,0xBB,0xAD,0xEB,
+0xFA,0xF7,0xAF,0x6B,0xFA,0xF6,0xBF,0x25, 0xE9,0xF2,0x7F,0x45,0xFF,0xFF,0xFD,0xF7,
+0xF7,0xBF,0xFF,0xDF,0xFF,0xFF,0xBF,0xFB, 0xFF,0xDF,0xF3,0xFF,0xF7,0x3F,0xCF,0xFF,
+0xA1,0xFF,0xFF,0xBF,0xE7,0xFF,0xFF,0x7F, 0xFF,0x3D,0xFF,0xFF,0xFF,0xF7,0xFF,0x2F,
+0xFF,0xFB,0xF5,0x7F,0xFE,0x57,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
+0x3F,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,0xFE, 0xF7,0xEE,0xAF,0xFE,0xEE,0xE7,0xFA,0xFF,
+0xFE,0x9D,0xF9,0x5E,0xFE,0xFF,0xEB,0xFF, 0xFF,0xDF,0xA7,0xFF,0xFF,0xFF,0xFC,0xDB,
+0xFF,0xFF,0xFF,0x7E,0xFB,0xFF,0xFF,0xEF, 0xFB,0xFD,0xFF,0xDB,0xFF,0xFF,0xFF,0xEF,
+0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,0xBF,0xFF, 0x6F,0x7F,0xFF,0xF7,0xFF,0xFF,0xF9,0xFF,
+0xF7,0xFF,0xBF,0xDE,0xF7,0xFF,0xFF,0xFF, 0xFA,0x7F,0xFD,0xBF,0x5F,0xFF,0xFF,0xBF,
+0xFF,0xED,0xFF,0xF7,0xBF,0xFF,0xFF,0xEF, 0xFF,0xDF,0xFF,0xFF,0xFF,0xE6,0xFF,0xFB,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,
+0xFD,0xFF,0xF5,0xFF,0xF6,0x7F,0xDF,0xBD, 0xCF,0xFF,0xFF,0xFF,0xFF,0xDF,0xFF,0xFF,
+0xFF,0xF9,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3, 0xFF,0xEE,0xBF,0xFF,0x7D,0xEF,0xFE,0xFF,
+0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xFF,0xFF,0xFF,0xFF,0xE7,0xFF,0xB5,0xAE,
+0xFF,0xFF,0xB6,0xFE,0xBF,0xFF,0xFF,0xBF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0x27,0xFF,0xEF,0xFE,0x7F,0xDF,0xFF, 0x7E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFD,0xFF,0xF7,0xF9,0x9F,0xFF, 0x5F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,
+0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0x0F,0xFF,0xE7,0xBF,0xFE,
+0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFC,0xBF, 0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xC4,
+0x6B,0xFF,0x29,0x1F,0xFB,0xAF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xEF,0x1B,0xFE,0xFF,0xFC,
+0x6F,0xFF,0xFF,0xFD,0x6A,0xF7,0xD7,0xF5, 0xBF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFE,0xBF,0xFF,0xFF,0xFA,0xFF,0xFF,0xF7, 0xFB,0xDD,0xBF,0xFF,0xE7,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0x7F,0xFF, 0xFF,0xF5,0xFF,0xFF,0xF7,0xFD,0xB3,0xEF,
+0xFD,0x7E,0x5D,0xFF,0xFD,0xFF,0xFF,0xFF, 0xFD,0x7F,0xD2,0xF5,0xFB,0x7E,0xCB,0xB7,
+0xFF,0xFF,0xFF,0xC6,0xFF,0xFD,0xEE,0x63, 0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xFD,0x65,
+0x5B,0xDF,0xFF,0xD5,0xFF,0xFF,0xFF,0xF6, 0xE7,0xBF,0xF7,0xA9,0xFF,0xFF,0xED,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFF,0xFF, 0xAF,0xFF,0xFF,0xFF,0xF8,0x1B,0xFF,0xE3,
+0xD0,0xBF,0xFF,0xE1,0xFF,0xFF,0xFF,0xFF, 0xFF,0xD7,0xFF,0xFF,0xFF,0x5F,0xFF,0xFF,
+0xFF,0xFF,0xAF,0xFF,0xDB,0x76,0xBF,0xFF, 0x7F,0xFF,0xBF,0xEF,0xFE,0xFF,0xBF,0xEF,
+0xFB,0xFE,0xFF,0xFF,0xFF,0xBF,0xF2,0x7F, 0xFF,0x9F,0xFE,0xBD,0xFE,0x7F,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xF7,0x3F,0xEC,0x7F,0xF6,0x95,0xBB,
+0xEF,0xF8,0xFE,0xFC,0xBF,0x2F,0xDA,0xFC, 0xBF,0x2F,0xCB,0xF2,0xFC,0xBF,0xEF,0xFF,
+0xA9,0xBF,0xCF,0xFB,0xFF,0xFF,0xFF,0xFE, 0xDD,0xB7,0x6D,0xF6,0xD9,0xB6,0x6D,0x9B,
+0x76,0xD9,0xBF,0xFB,0xFD,0xA3,0xFF,0xBF, 0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0x7F,0xDF,
+0xFD,0xEF,0x7B,0xDE,0xF7,0xFD,0xEF,0x7F, 0xFF,0xFF,0x05,0xFF,0xFA,0xFE,0x7F,0xEF,
+0xE3,0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xFF, 0xFF,0x5F,0xFF,0xFF,0xFD,0x7F,0xFB,0xAF,
+0xFF,0x63,0xC8,0xFF,0xBF,0xEF,0xFF,0xFF, 0xFA,0x7F,0xFF,0xFF,0xFF,0xFE,0x9F,0xF7,
+0xFF,0xFA,0xBF,0xFE,0x9F,0xFB,0x7F,0xFF, 0xFF,0xEF,0xD7,0xFF,0xFF,0xF5,0xFF,0xFF,
+0xFF,0xFF,0xFD,0x7F,0xFF,0xFF,0xBF,0xFF, 0xF9,0xBF,0xFF,0xBE,0x27,0x9F,0xE7,0xF9,
+0xFE,0x7F,0x8B,0xE7,0xFE,0x7F,0x9F,0xE2, 0xF9,0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,
+0xFF,0xFF,0xFB,0xFE,0xFF,0xFF,0xFF,0xD7, 0xFF,0xFF,0xFF,0xFF,0xF5,0xFF,0xFF,0xFF,
+0xD7,0xFF,0xFA,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFD,0xFF,0xFF,0xFF,0xAF,0xF7,0xFF,0xFF,
+0xFF,0xEB,0xFF,0xFF,0xFF,0xAF,0xFF,0xC4, 0xFF,0xF7,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF,
+0xFF,0x5F,0xFF,0xFF,0xFF,0xFF,0xD7,0xFF, 0xFF,0xFF,0xFF,0xFF,0xEB,0xFF,0xFB,0x7A,
+0xDF,0xF7,0xFD,0xFF,0xFF,0xFE,0xBF,0xFF, 0xFF,0x7F,0xFF,0xAF,0xFF,0xFF,0xFF,0xF7,
+0xEF,0xE3,0xFF,0xDD,0xD2,0xFF,0xDF,0xFF, 0xFF,0xF2,0xFC,0xBF,0xCB,0xF6,0xFD,0xBF,
+0x2F,0xCB,0xFF,0x7F,0xDF,0xDE,0xAF,0xFF, 0xDA,0xEE,0xBF,0xAF,0xE9,0xFA,0xF4,0xBD,
+0xAF,0x5A,0xAE,0xBB,0xAB,0x6B,0xDA,0xDE, 0xBF,0xAD,0xD7,0x5E,0xFF,0xFF,0xBF,0xFC,
+0xFF,0xDF,0xFD,0xFF,0xFF,0xFF,0xFF,0xDF, 0xF7,0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFA,
+0x1F,0xFF,0xFE,0xFB,0xEF,0xBF,0xFD,0xFF, 0xFD,0xBD,0x77,0xFF,0xFF,0xFF,0xFF,0x9D,
+0xEF,0xFF,0xFF,0xFF,0xEF,0x7D,0xFF,0xFB, 0xFE,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF7,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE, 0xBF,0xE4,0xFB,0xFF,0xFE,0x3F,0xFE,0xFF,
+0xFF,0xFF,0xFF,0xAF,0xEA,0xFE,0xBF,0xAF, 0xEB,0xFA,0xFE,0xFF,0xFF,0xFF,0x55,0xF6,
+0xFF,0xFE,0xF7,0xFF,0x7F,0xFF,0xEB,0xF7, 0x5F,0xC5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
+0x6F,0xFB,0xFF,0x8A,0xFF,0xFF,0xFF,0xFF, 0xEB,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0xBF,
+0xEF,0xFB,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF, 0x77,0xDF,0xFB,0xFF,0xFD,0x7F,0xEF,0xFF,
+0xFF,0xFF,0xBF,0x7F,0xFF,0xDF,0xBF,0xFF, 0xFB,0xFF,0xFF,0xFF,0xFE,0xEF,0xDF,0xFF,
+0xFE,0xFF,0x9F,0xEF,0x7D,0xFF,0xF7,0xFF, 0x7F,0xFF,0xFF,0xDF,0xF7,0xFD,0xFF,0xEF,
+0xDF,0xFF,0xDF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0xFB,
+0xFD,0xFF,0xBF,0xDF,0xD1,0xFF,0xF8,0x3B, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0x7E,0xDB,0xFD,0xFF,0x77,0xDB,0xB7,0x7D, 0xBF,0xFB,0xFF,0xF8,0x7F,0xED,0x7B,0x5E,
+0xFF,0xFE,0xFF,0xFF,0x4F,0xD7,0xFD,0x7F, 0xDF,0xD7,0xF5,0xFF,0x7F,0xFF,0xFF,0xFF,
+0xF2,0x3F,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF, 0xFF,0xBF,0xEF,0xFE,0xFF,0x3B,0xEE,0xFF,
+0xFC,0xEF,0xFF,0xFF,0xFF,0x85,0xFF,0xFD, 0xFE,0xFF,0xF5,0xFF,0xFF,0xFE,0xFF,0xDF,
+0xFB,0xFF,0x5F,0xBF,0xFF,0xFD,0xFF,0xFF, 0xFF,0xFF,0xA8,0xFF,0xFF,0x9F,0x9E,0xFF,
+0xFF,0xFF,0x7F,0xF3,0xFF,0xFF,0xCF,0xFF, 0xF7,0xFD,0xFF,0x7F,0xFF,0xFF,0xFC,0x16,
+0xBF,0xCF,0xA3,0xE5,0xEF,0x7F,0xFF,0xF3, 0xE4,0xFF,0xCF,0x93,0xFC,0xFF,0x3F,0xCF,
+0xFF,0xFF,0xFF,0xD6,0x0F,0x7D,0xBF,0x6E, 0xFB,0xF4,0xFC,0xAF,0x6D,0xDB,0x77,0xB7,
+0x6D,0xDB,0xF6,0xFD,0xBF,0xFF,0xFF,0xFF, 0xBF,0x9B,0xFA,0xDE,0xB7,0xB7,0xED,0xF9,
+0x7E,0xB7,0xAC,0xEB,0xD6,0xB3,0xAD,0xEB, 0x7A,0xDF,0xFF,0xFF,0xFF,0xD8,0xBF,0xFF,
+0xB7,0xED,0x9F,0x6F,0xDD,0xF7,0x68,0xDB, 0x37,0xB3,0x6C,0xDB,0x36,0xCD,0xB3,0x7F,
+0xFF,0x7F,0xF5,0x6F,0xFD,0xEF,0x79,0x3D, 0xF7,0x93,0xE4,0x7A,0x9E,0xAD,0xEA,0x7A,
+0x9E,0xF7,0xBD,0xEF,0xFF,0xFF,0xFF,0x76, 0x7F,0xFB,0xC6,0xFF,0xBB,0xEF,0xDA,0xFE,
+0xFD,0xBF,0xFB,0xFE,0xFF,0xBF,0xEF,0xFB, 0xFF,0xFF,0xFB,0xFF,0xA5,0xFF,0xFD,0xAB,
+0x6F,0x78,0xDE,0x17,0x8F,0x79,0xDF,0xFD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xFF,0xFB,
+0xFF,0xFB,0xFF,0xEF,0xFB,0xEF,0xFB,0xFE, 0xFF,0xBB,0xDA,0xF3,0xEF,0x3B,0xCE,0xF3,
+0xBC,0xEF,0x3F,0xCF,0xDF,0xFF,0xB7,0xFF, 0xFF,0xFF,0xCF,0x73,0xFF,0xBF,0xEF,0xFF,
+0xF3,0xFF,0x3F,0xCF,0xF3,0xFC,0xFF,0x3D, 0xCF,0x9F,0xFE,0x07,0xFF,0xAF,0xEB,0xFE,
+0xFD,0xBF,0xEF,0xEB,0xFA,0xFF,0xAF,0xEB, 0xFA,0xFE,0xBF,0xAF,0xFB,0xFE,0x3F,0xFB,
+0x9B,0xFF,0x7F,0xDF,0xFF,0xF3,0xFE,0xFF, 0xDE,0xF7,0xBF,0x7B,0xDE,0xF7,0xBD,0xEF,
+0x7B,0xFE,0xFF,0xFF,0xDF,0x3F,0xFE,0xFF, 0xB7,0xFF,0xEF,0xF7,0xFF,0xBF,0xED,0xFE,
+0xDF,0xB7,0xED,0xFB,0x7E,0xDF,0xFF,0xFF, 0xFF,0xFD,0x5F,0xEF,0xEB,0xFA,0xFE,0xF5,
+0xBF,0x6F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xF8,0xFF,0xA8,0xFF,
+0xFF,0xBF,0xEF,0xFB,0x6A,0xFB,0xB7,0xEF, 0xFB,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xBF,
+0xEF,0xFB,0xFF,0xE0,0xFF,0xFF,0xFD,0x7F, 0x5C,0xD7,0x7D,0xDF,0xF3,0x5C,0xF5,0xCD,
+0x73,0x5E,0xD7,0xB5,0xFD,0x7F,0xEF,0xFF, 0xDB,0xFF,0xFF,0xE2,0xF8,0xBE,0x2F,0x8F,
+0xE7,0xF8,0xBE,0x6B,0xE2,0xF8,0xBE,0x2F, 0x8B,0xE2,0xF9,0xFE,0x7F,0xE7,0xFF,0xD7,
+0xF5,0xFD,0x7F,0xFF,0xF7,0xF5,0xFD,0x7F, 0xD7,0xF5,0xFD,0x7F,0x5F,0xD7,0xF5,0xFF,
+0xFF,0xFF,0x8F,0xFF,0xAF,0xEB,0xFA,0xFF, 0xFF,0xBF,0xEB,0xFA,0xFF,0x2F,0xEB,0xFA,
+0xFE,0xBF,0xAF,0xEB,0xFF,0xFF,0xFE,0x5F, 0xFF,0x5F,0xFF,0xFF,0xFD,0xFF,0xFF,0xD7,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFE,0xB7,0xFD,
+0xFF,0x7E,0xDF,0xF7,0xAD,0xFF,0x7F,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0x7F,
+0xF6,0x7F,0xFF,0xFF,0xFF,0xDB,0xF6,0xFC, 0xAF,0xFF,0xFF,0xFF,0xFF,0xF7,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xEC,0xBF,0xFF, 0xAF,0xEB,0xFA,0xF6,0xAB,0x8F,0xEB,0xFA,
+0xF7,0xA5,0xEB,0xFA,0xBE,0xBF,0xAF,0xEB, 0xFA,0xFF,0x6D,0xFF,0xFF,0x7F,0xDF,0x33,
+0xDD,0xFF,0x7F,0xFE,0xF7,0xFC,0x7F,0xFB, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xA9,
+0xFF,0xFD,0xFF,0xFF,0xFE,0xFF,0xFF,0xDF, 0xFF,0xFF,0xEF,0xEF,0xFD,0xFF,0x7F,0xFF,
+0xFF,0xFF,0xFF,0xFE,0xA7,0xFF,0xFF,0xFF, 0x77,0xDF,0xF7,0xFD,0x9F,0x7F,0xFE,0x77,
+0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xAF,0xBF,0xAF,0xFF,0xF9,0xBE,0xBF,
+0x8F,0xFB,0xFE,0xFE,0xEF,0xFB,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFF,0xFF,0xFD,0xDF,0x6F,
+0xEF,0xFF,0x7F,0xFF,0xBF,0xBF,0xDF,0xFF, 0xFC,0xFF,0xDF,0xF7,0xFD,0xEF,0x7F,0xDF,
+0xFF,0xFF,0xFF,0x3F,0xF6,0xFF,0xCF,0xFF, 0xDB,0xFB,0xF7,0xFF,0xEB,0x7A,0xFF,0xFF,
+0xFF,0xBF,0xEF,0xFB,0xFF,0xFF,0xFF,0xFE, 0x6D,0xFD,0xFF,0x5F,0xFB,0xFF,0xFF,0xF7,
+0xFF,0x5F,0xF5,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xF8,0xFF,0xFB,0xFF,
+0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xE7,0xF6, 0xBF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,
+0xFF,0xC9,0xFF,0xFF,0xFF,0xBD,0xFF,0xBF, 0xAF,0xEF,0xEF,0x3F,0xD1,0xFC,0x7F,0xFB,
+0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xE3,0xFF, 0xFF,0xFF,0xFF,0xFD,0xFF,0xFF,0x77,0xFF,
+0xDF,0xB7,0xFD,0xF7,0xFD,0xF7,0xFF,0xFF, 0xFF,0xFF,0xFF,0x57,0xFF,0xF7,0xA5,0xFD,
+0x3F,0xDF,0xBF,0xBF,0xFE,0x7F,0xFF,0xFF, 0xFF,0xDF,0xFA,0xFD,0xFF,0xFF,0xFF,0xFE,
+0x87,0xFF,0xE9,0xFF,0xFE,0xEF,0xBF,0xEF, 0xFE,0xFE,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFA,0x9F,0xFF,0x3F, 0xFF,0xFD,0xFD,0x57,0xDF,0xFD,0xF3,0xFF,
+0xDF,0xFD,0xFF,0x5F,0xDF,0xF5,0xFD,0xFF, 0xFF,0xF9,0x8F,0xFF,0xFF,0xFF,0xEE,0x7F,
+0xFF,0xFF,0xBF,0x5E,0xFE,0xEC,0xFB,0x3F, 0x7F,0x9F,0xEF,0xF9,0xFF,0xFF,0xCD,0x6B,
+0xFF,0xFF,0xFF,0xC5,0xF3,0xFC,0xFA,0x38, 0xFF,0xAF,0x3F,0xEE,0x7F,0x9F,0xFF,0xD9,
+0xFF,0xFF,0xFD,0x7A,0xF7,0xFF,0xF3,0xFF, 0xAF,0x6F,0xDB,0xF2,0xB9,0xE9,0xFB,0xFF,
+0xFF,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xFB, 0xC5,0xBF,0xFF,0xEF,0xFF,0x5E,0xB7,0xAD,
+0xCD,0x79,0x7C,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0x93,0xFF,0xEF,
+0xEA,0xFE,0xBF,0xEF,0x5B,0xD2,0xCD,0xF5, 0x6D,0x77,0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,
+0xFF,0xFF,0x66,0xFF,0xD5,0x65,0x7D,0x5F, 0x75,0x9D,0x65,0x7F,0xD6,0xFB,0x4F,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF6,0xC7, 0xFF,0xBF,0xEF,0xFA,0xFE,0xFF,0xBF,0xEB,
+0xFF,0xDF,0xFF,0x7E,0xFF,0xFF,0xEF,0xFD, 0x7E,0xD7,0xFF,0x78,0xDF,0xFF,0x5F,0xDF,
+0xF5,0xBF,0x7F,0xDF,0xC5,0xFF,0x3F,0xF6, 0x7E,0xFF,0x0F,0xEF,0xF2,0x3E,0xBF,0xFF,
+0xFB,0x3F,0xFF,0xFB,0x7F,0xFF,0xB3,0xFE, 0xFB,0xF6,0xFD,0xFF,0xDA,0xF7,0xFD,0xFF,
+0x7F,0xDF,0xF7,0xBF,0xFF,0xFA,0x7F,0xFF, 0xFF,0xFF,0xFF,0x9F,0xFF,0xF3,0xDC,0xF9,
+0xBF,0xCE,0xE7,0xF9,0xFE,0x7F,0x9F,0xE7, 0xFF,0xFF,0xE2,0x7F,0xFE,0xFF,0xBF,0xEF,
+0xEB,0xFA,0xFF,0x9F,0x67,0x1E,0xFF,0x8F, 0xE7,0xF8,0xFE,0x7F,0x8F,0xEF,0xFF,0xBD,
+0xBF,0xFF,0xFB,0xFF,0xFF,0xDF,0xF7,0xFF, 0xFC,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFD,0xB3,0xFF,0xFF,0xEF, 0xFF,0xFF,0xBF,0xED,0xFF,0xFB,0xEE,0xFE,
+0xFF,0xFF,0xEF,0xFF,0xFE,0xFF,0xFF,0xFF, 0xFF,0xB5,0xFF,0xB7,0xFD,0xFD,0x6E,0xFF,
+0xFF,0xFE,0xFD,0x2F,0xD8,0xFE,0xBF,0x8F, 0xEB,0xF9,0xFE,0x3F,0xFF,0xFA,0xCF,0xFF,
+0xE7,0xD9,0xFA,0xBF,0xDF,0x77,0xFC,0xFB, 0x3F,0xAB,0xFE,0xFF,0xBF,0xEF,0xFB,0xFE,
+0xFF,0xFF,0xEE,0x1F,0xFF,0xDF,0xF7,0xFF, 0xFF,0xFF,0x5F,0x97,0x35,0xBF,0x5E,0xFE,
+0xBF,0xEF,0xFF,0xF7,0xFD,0xFF,0xFF,0xFA, 0xBF,0xFF,0xBE,0x6F,0x9F,0xE7,0xF8,0xBE,
+0x2F,0x8B,0x66,0x94,0x7D,0x9D,0xE7,0xF9, 0xFE,0x7F,0x9F,0xE7,0xF1,0x7F,0xFF,0xFF,
+0xFF,0xF7,0xF5,0xFD,0x7F,0x5F,0xFB,0xFD, 0x9E,0xFF,0xFB,0xFE,0xFF,0xFF,0xEF,0xFF,
+0xFF,0xA0,0xFF,0xFF,0xFF,0xBF,0xEF,0xEB, 0xFA,0xFE,0xBF,0xB7,0xF7,0xF7,0xFF,0xFF,
+0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xDD,0xFF, 0xFD,0xFF,0xFF,0xFF,0xD7,0xFF,0xFF,0xFF,
+0x7F,0xF5,0xFF,0xFF,0xEF,0xFF,0xFF,0xFF, 0xBF,0xFF,0xFF,0xAB,0xFE,0xFB,0xFE,0xFF,
+0xF7,0xAF,0xFF,0xFF,0xDE,0xF7,0xEB,0x5F, 0xDF,0xF7,0xFD,0xFF,0x7F,0xDF,0xFF,0xFF,
+0xB3,0xFF,0xC9,0xFE,0xFF,0xFF,0xFF,0xFF, 0xD6,0xFF,0xFF,0xCB,0xFF,0xFF,0xDF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFC,0x8F,0xFF,0xBA, 0xBE,0xBF,0xAF,0xEB,0x78,0xFE,0xB7,0xAD,
+0x3A,0xFE,0xB7,0xAF,0xEB,0x7A,0xFE,0xBF, 0xAF,0xFF,0x9F,0xFF,0xFF,0xDF,0xFC,0xFF,
+0xFF,0xFE,0xC3,0xFE,0xFF,0xFF,0x33,0xFC, 0xFF,0xBF,0xDF,0xF3,0xFF,0xFF,0xBB,0x9F,
+0xFF,0xFF,0xFF,0xEB,0xDF,0xFF,0xFF,0xAF, 0xF7,0x6F,0xF9,0xBF,0xEF,0xFD,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xE3,0x7F,0xFF,0xFF,0xFF, 0xFB,0xFF,0xFF,0xBF,0xFD,0xFB,0xF7,0xFF,
+0xDF,0xF7,0xFF,0xFE,0xEF,0x5F,0xBD,0xFF, 0xFA,0xFF,0xF8,0xFF,0xBF,0xAF,0xFB,0xFE,
+0xFE,0x3F,0xEF,0xE8,0xFF,0xDF,0xF3,0xFD, 0xFF,0xFF,0xFF,0xFF,0xFF,0xED,0xFF,0xFB,
+0xFD,0xFF,0xAF,0xFF,0xFF,0xFE,0xFE,0xBF, 0xDB,0xFF,0xFF,0xFF,0xBF,0xFF,0xDF,0xFF,
+0xFD,0xFF,0xCB,0xFF,0xFF,0xFF,0xFF,0xFF, 0xBF,0x6F,0xFF,0x7F,0xB7,0xB3,0xFF,0xFF,
+0xDF,0xFF,0xFB,0xEF,0xFF,0xFF,0xFF,0x07, 0xFF,0xFB,0xFF,0xFF,0xFF,0xED,0xFF,0xF5,
+0x7C,0xFF,0x7F,0xFE,0xFF,0xFF,0xEF,0xCF, 0xFF,0xFB,0xFF,0xFF,0x2F,0xFF,0xFF,0xFF,
+0xFF,0xF3,0xFF,0xFB,0xFF,0xFE,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
+0xFD,0x1B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFE,0x7C,0xFF,0xFF,0xFF,0xFF,
+0xEF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0x7F, 0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xDB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD, 0xFF,0xFF,0xF0,0x7F,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xDF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xBF,0xFE,
+0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xEF,0xFE,0xFF,0xBF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xEF,0xFA,0xB5,0xFF,0xFF,0xFF, 0xF7,0xF7,0xFF,0xFF,0xFF,0xFF,0xDF,0xFB,
+0xFC,0xFF,0xFF,0xFE,0xFF,0x7F,0xDF,0xBF, 0xFF,0xCB,0xBF,0xF9,0xFE,0x7F,0x9F,0xE7,
+0xF9,0xFE,0x7F,0x97,0xE1,0xFE,0x79,0x9F, 0xE7,0xFD,0xFE,0x7F,0xDF,0xFE,0x37,0xFF,
+0xFB,0xDE,0xDE,0xBD,0xEF,0xF3,0xFE,0xFB, 0xAF,0xEB,0xFE,0xFF,0xFF,0xCF,0xFF,0xFE,
+0xFF,0xBF,0xFF,0x8F,0xFF,0xEF,0xFB,0xFE, 0xFF,0xBF,0xE7,0xF9,0x5E,0x7F,0xEF,0xFB,
+0xDA,0xFF,0xBF,0xEF,0xFB,0xFE,0xFF,0xFD, 0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xDF,
+0xFF,0xFF,0x7F,0xFF,0xFF,0xF7,0xFB,0x7F, 0xFF,0xFF,0xFF,0xFF,0xFC,0x3F,0xFF,0xBF,
+0xEF,0xFB,0xFE,0xFF,0xBF,0xEF,0x7B,0x7F, 0xBF,0xEF,0xFB,0xFE,0xFF,0xB5,0xEF,0xFB,
+0xBF,0xFA,0x7F,0xFC,0xFF,0x3F,0xCF,0xF3, 0xFC,0xFF,0x3F,0xCF,0xBC,0xFF,0x3F,0xEF,
+0xF3,0xFC,0xFE,0x3F,0xCF,0xFF,0xEE,0xEF, 0xFB,0xFE,0xFF,0xBF,0xEF,0xFB,0x6A,0xD7,
+0xB7,0xFB,0xF8,0xFF,0xB7,0xEF,0xBA,0xFE, 0xFF,0xBF,0x7F,0xE9,0xFF,0xF9,0x7E,0x5F,
+0x97,0xE5,0xF9,0xFE,0x7F,0xBF,0xF9,0x7E, 0x5F,0x9F,0xE5,0xFB,0xFE,0x5F,0xB7,0xFF,
+0xA3,0xFF,0xF7,0xFD,0xFF,0x7F,0xDF,0xF7, 0xFD,0xFF,0x5E,0xF7,0x7D,0xFF,0x77,0xDF,
+0xF7,0xFD,0xFF,0x7F,0xFF,0xD7,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFD,0xDF,0xFB,0x7F,
+0xFF,0xFF,0xEF,0xFF,0xFE,0xFB,0xFF,0xFF, 0xBF,0xFE,0x8F,0xFF,0xDF,0xF7,0xFD,0xFD,
+0x7F,0xDF,0xF7,0xFD,0x3E,0xDF,0xF5,0xBD, 0xFF,0x7F,0xDF,0xF7,0xFD,0xF7,0xFF,0x9F,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xBE,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFD,0x3F,0xFF,0xDF,0xF7, 0xFD,0xFF,0x7F,0xDF,0xF7,0xFD,0xFF,0xCF,
+0x77,0xFC,0xFF,0x5F,0xDF,0xF7,0xFD,0xFF, 0xF4,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFD,0xFF,0xFF,0xFF,0xEE,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xED,0xFB,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xE9,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFB,0xFF,0xFF,0xFF,0xD3,0xFF,0xFF,
+0xBF,0x3F,0xFB,0xFF,0xFF,0xFF,0xFB,0xF3, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xF7, 0xFF,0xFF,0xFF,0xFF,0x17,0xFF,0xFF,0xFF,
+0xDF,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF, 0xDF,0xDF,0xFF,0xFD,0xFF,0xFF,0xDF,0xF7,
+0xFF,0x4F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFD,
+0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0x9F,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF, 0xFF,0xFF,0x7A,0x3F,0xFF,0xFF,0xFF,0xFF,
+0xFF,0xFF,0xFF,0x7F,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF2,
+0x7F,0xFF,0xFB,0xFE,0xFF,0xBF,0xEF,0xF8, 0xFE,0xFF,0xBF,0xFB,0xFE,0xFF,0x8F,0xEC,
+0xFB,0xFE,0xFF,0xBF,0xF8,0xF7,0xFE,0xFF, 0xBF,0xEF,0xFB,0xFE,0xFD,0xBF,0xCF,0xEC,
+0xFF,0x3F,0xEF,0xDB,0xF8,0xFF,0xBF,0xCF, 0xFF,0xF9,0xFF,0xFF,0xBF,0xFF,0xFB,0xFF,
+0xFF,0xFF,0xEF,0xFB,0xDF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xBB,0xFF,
+0xEF,0xFB,0xFE,0xEF,0xBF,0xEE,0xEB,0xFB, 0xFE,0xFF,0xEF,0xFE,0xEE,0xBF,0xFE,0xEB,
+0xFF,0xEF,0xFF,0x17,0xFF,0x7E,0xEB,0xBB, 0xFE,0xBF,0xBE,0xFB,0xEF,0x5B,0xF7,0xBD,
+0xFB,0xCF,0xBF,0xBF,0xBB,0xFB,0x7E,0xCC, 0xEF,0xFF
+
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/dabusb.c linux.18p8/drivers/usb/dabusb.c
--- linux.vanilla/drivers/usb/dabusb.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/dabusb.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,846 @@
+/*****************************************************************************/
+
+/*
+ *      dabusb.c  --  dab usb driver.
+ *
+ *      Copyright (C) 1999  Deti Fliegl (deti@fliegl.de)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ *  $Id: dabusb.c,v 1.45 2000/01/31 10:23:44 fliegl Exp $
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+
+#include "dabusb.h"
+#include "dabfirmware.h"
+
+/* --------------------------------------------------------------------- */
+
+#define NRDABUSB 4
+
+/*-------------------------------------------------------------------*/
+
+static dabusb_t dabusb[NRDABUSB];
+static int buffers = 256;
+
+/*-------------------------------------------------------------------*/
+
+static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src)
+{
+	unsigned long flags;
+	struct list_head *tmp;
+	int ret = 0;
+
+	spin_lock_irqsave (&s->lock, flags);
+
+	if (list_empty (src)) {
+		// no elements in source buffer
+		ret = -1;
+		goto err;
+	}
+	tmp = src->next;
+	list_del (tmp);
+	list_add_tail (tmp, dst);
+
+  err:	spin_unlock_irqrestore (&s->lock, flags);
+	return ret;
+}
+/*-------------------------------------------------------------------*/
+#ifdef DEBUG 
+static void dump_urb (purb_t purb)
+{
+	dbg("urb                   :%p", purb);
+	dbg("next                  :%p", purb->next);
+	dbg("dev                   :%p", purb->dev);
+	dbg("pipe                  :%08X", purb->pipe);
+	dbg("status                :%d", purb->status);
+	dbg("transfer_flags        :%08X", purb->transfer_flags);
+	dbg("transfer_buffer       :%p", purb->transfer_buffer);
+	dbg("transfer_buffer_length:%d", purb->transfer_buffer_length);
+	dbg("actual_length         :%d", purb->actual_length);
+	dbg("setup_packet          :%p", purb->setup_packet);
+	dbg("start_frame           :%d", purb->start_frame);
+	dbg("number_of_packets     :%d", purb->number_of_packets);
+	dbg("interval              :%d", purb->interval);
+	dbg("error_count           :%d", purb->error_count);
+	dbg("context               :%p", purb->context);
+	dbg("complete              :%p", purb->complete);
+}
+#endif
+/*-------------------------------------------------------------------*/
+static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q)
+{
+	unsigned long flags;
+	struct list_head *p;
+	pbuff_t b;
+
+	dbg("dabusb_cancel_queue");
+
+	spin_lock_irqsave (&s->lock, flags);
+
+	for (p = q->next; p != q; p = p->next) {
+		b = list_entry (p, buff_t, buff_list);
+
+#ifdef DEBUG
+		dump_urb(b->purb);
+#endif
+		usb_unlink_urb (b->purb);
+	}
+	spin_unlock_irqrestore (&s->lock, flags);
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_free_queue (struct list_head *q)
+{
+	struct list_head *tmp;
+	struct list_head *p;
+	pbuff_t b;
+
+	dbg("dabusb_free_queue");
+	for (p = q->next; p != q;) {
+		b = list_entry (p, buff_t, buff_list);
+
+#ifdef DEBUG 
+		dump_urb(b->purb);
+#endif
+		if (b->purb->transfer_buffer)
+			kfree (b->purb->transfer_buffer);
+		usb_free_urb(b->purb);
+		tmp = p->next;
+		list_del (p);
+		kfree (b);
+		p = tmp;
+	}
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_free_buffers (pdabusb_t s)
+{
+	unsigned long flags;
+	dbg("dabusb_free_buffers");
+
+	spin_lock_irqsave(&s->lock, flags);
+
+	dabusb_free_queue (&s->free_buff_list);
+	dabusb_free_queue (&s->rec_buff_list);
+
+	spin_unlock_irqrestore(&s->lock, flags);
+
+	s->got_mem = 0;
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+static void dabusb_iso_complete (purb_t purb)
+{
+	pbuff_t b = purb->context;
+	pdabusb_t s = b->s;
+	int i;
+	int len;
+	int dst = 0;
+	void *buf = purb->transfer_buffer;
+
+	dbg("dabusb_iso_complete");
+
+	// process if URB was not killed
+	if (purb->status != -ENOENT) {
+		unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE);
+		int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
+		for (i = 0; i < purb->number_of_packets; i++)
+			if (!purb->iso_frame_desc[i].status) {
+				len = purb->iso_frame_desc[i].actual_length;
+				if (len <= pipesize) {
+					memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len);
+					dst += len;
+				}
+				else
+					err("dabusb_iso_complete: invalid len %d", len);
+			}
+			else
+				warn("dabusb_iso_complete: corrupted packet status: %d", purb->iso_frame_desc[i].status);
+		if (dst != purb->actual_length)
+			err("dst!=purb->actual_length:%d!=%d", dst, purb->actual_length);
+	}
+
+	if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) {
+		s->overruns++;
+		err("overrun (%d)", s->overruns);
+	}
+	wake_up (&s->wait);
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_alloc_buffers (pdabusb_t s)
+{
+	int buffers = 0;
+	pbuff_t b;
+	unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);
+	int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));
+	int packets = _ISOPIPESIZE / pipesize;
+	int transfer_buffer_length = packets * pipesize;
+	int i;
+
+	dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",
+		 pipesize, packets, transfer_buffer_length);
+
+	while (buffers < (s->total_buffer_size << 10)) {
+		b = (pbuff_t) kmalloc (sizeof (buff_t), GFP_KERNEL);
+		if (!b) {
+			err("kmalloc(sizeof(buff_t))==NULL");
+			goto err;
+		}
+		memset (b, sizeof (buff_t), 0);
+		b->s = s;
+		b->purb = usb_alloc_urb(packets);
+		if (!b->purb) {
+			err("usb_alloc_urb == NULL");
+			kfree (b);
+			goto err;
+		}
+
+		b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL);
+		if (!b->purb->transfer_buffer) {
+			kfree (b->purb);
+			kfree (b);
+			err("kmalloc(%d)==NULL", transfer_buffer_length);
+			goto err;
+		}
+
+		b->purb->transfer_buffer_length = transfer_buffer_length;
+		b->purb->number_of_packets = packets;
+		b->purb->complete = dabusb_iso_complete;
+		b->purb->context = b;
+		b->purb->dev = s->usbdev;
+		b->purb->pipe = pipe;
+		b->purb->transfer_flags = USB_ISO_ASAP;
+
+		for (i = 0; i < packets; i++) {
+			b->purb->iso_frame_desc[i].offset = i * pipesize;
+			b->purb->iso_frame_desc[i].length = pipesize;
+		}
+
+		buffers += transfer_buffer_length;
+		list_add_tail (&b->buff_list, &s->free_buff_list);
+	}
+	s->got_mem = buffers;
+
+	return 0;
+
+	err:
+	dabusb_free_buffers (s);
+	return -ENOMEM;
+}
+/*-------------------------------------------------------------------*/
+static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
+{
+	int ret;
+	unsigned int pipe;
+	int actual_length;
+
+	dbg("dabusb_bulk");
+
+	if (!pb->pipe)
+		pipe = usb_rcvbulkpipe (s->usbdev, 2);
+	else
+		pipe = usb_sndbulkpipe (s->usbdev, 2);
+
+	ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 1000);
+	if(ret<0) {
+		err("dabusb: usb_bulk_msg failed(%d)",ret);
+	}
+	
+	if( ret == -EPIPE ) {
+		warn("CLEAR_FEATURE request to remove STALL condition.");
+		if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
+			err("request failed");
+		}
+
+	pb->size = actual_length;
+	return ret;
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_writemem (pdabusb_t s, int pos, unsigned char *data, int len)
+{
+	int ret;
+	unsigned char *transfer_buffer =  kmalloc (len, GFP_KERNEL);
+
+	if (!transfer_buffer) {
+		err("dabusb_writemem: kmalloc(%d) failed.", len);
+		return -ENOMEM;
+	}
+
+	memcpy (transfer_buffer, data, len);
+
+	ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300);
+
+	kfree (transfer_buffer);
+	return ret;
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit)
+{
+	dbg("dabusb_8051_reset: %d",reset_bit);
+	return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1);
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_loadmem (pdabusb_t s, const char *fname)
+{
+	int ret;
+	PINTEL_HEX_RECORD ptr = firmware;
+
+	dbg("Enter dabusb_loadmem (internal)");
+	
+	ret = dabusb_8051_reset (s, 1);
+	while (ptr->Type == 0) {
+
+		dbg("dabusb_writemem: %04X %p %d)", ptr->Address, ptr->Data, ptr->Length);
+
+		ret = dabusb_writemem (s, ptr->Address, ptr->Data, ptr->Length);
+		if (ret < 0) {
+			err("dabusb_writemem failed (%d %04X %p %d)", ret, ptr->Address, ptr->Data, ptr->Length);
+			break;
+		}
+		ptr++;
+	}
+	ret = dabusb_8051_reset (s, 0);
+
+	dbg("dabusb_loadmem: exit");
+
+	return ret;
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b)
+{
+	b->size = 4;
+	b->data[0] = 0x2a;
+	b->data[1] = 0;
+	b->data[2] = 0;
+	b->data[3] = 0;
+
+	dbg("dabusb_fpga_clear");
+
+	return dabusb_bulk (s, b);
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b)
+{
+	b->size = 4;
+	b->data[0] = 0x2c;
+	b->data[1] = 0;
+	b->data[2] = 0;
+	b->data[3] = 0;
+
+	dbg("dabusb_fpga_init");
+
+	return dabusb_bulk (s, b);
+}
+/* --------------------------------------------------------------------- */
+static int dabusb_fpga_download (pdabusb_t s, const char *fname)
+{
+	pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
+	unsigned int blen, n;
+	int ret;
+	unsigned char *buf = bitstream;
+
+	dbg("Enter dabusb_fpga_download (internal)");
+
+	if (!b) {
+		err("kmalloc(sizeof(bulk_transfer_t))==NULL");
+		return -ENOMEM;
+	}
+
+	b->pipe = 1;
+	ret = dabusb_fpga_clear (s, b);
+	mdelay (10);
+	blen = buf[73] + (buf[72] << 8);
+
+	dbg("Bitstream len: %i", blen);
+
+	b->data[0] = 0x2b;
+	b->data[1] = 0;
+	b->data[2] = 0;
+	b->data[3] = 60;
+
+	for (n = 0; n <= blen + 60; n += 60) {
+		// some cclks for startup
+		b->size = 64;
+		memcpy (b->data + 4, buf + 74 + n, 60);
+		ret = dabusb_bulk (s, b);
+		if (ret < 0) {
+			err("dabusb_bulk failed.");
+			break;
+		}
+		mdelay (1);
+	}
+
+	ret = dabusb_fpga_init (s, b);
+	kfree (b);
+
+	dbg("exit dabusb_fpga_download");
+
+	return ret;
+}
+
+static loff_t dabusb_llseek (struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int dabusb_stop (pdabusb_t s)
+{
+	dbg("dabusb_stop");
+
+	s->state = _stopped;
+	dabusb_cancel_queue (s, &s->rec_buff_list);
+
+	dbg("pending_io: %d", s->pending_io.counter);
+
+	s->pending_io.counter = 0;
+	return 0;
+}
+
+static int dabusb_startrek (pdabusb_t s)
+{
+	if (!s->got_mem && s->state != _started) {
+
+		dbg("dabusb_startrek");
+
+		if (dabusb_alloc_buffers (s) < 0)
+			return -ENOMEM;
+		dabusb_stop (s);
+		s->state = _started;
+		s->readptr = 0;
+	}
+
+	if (!list_empty (&s->free_buff_list)) {
+		pbuff_t end;
+		int ret;
+		
+	while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) {
+
+			dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list);
+
+			end = list_entry (s->rec_buff_list.prev, buff_t, buff_list);
+
+			ret = usb_submit_urb (end->purb);
+			if (ret) {
+				err("usb_submit_urb returned:%d", ret);
+				if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
+					err("startrek: dabusb_add_buf_tail failed");
+				break;
+			}
+			else
+				atomic_inc (&s->pending_io);
+		}
+		dbg("pending_io: %d",s->pending_io.counter);
+	}
+
+	return 0;
+}
+
+static ssize_t dabusb_read (struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	pdabusb_t s = (pdabusb_t) file->private_data;
+	unsigned long flags;
+	unsigned ret = 0;
+	int rem;
+	int cnt;
+	pbuff_t b;
+	purb_t purb = NULL;
+
+	dbg("dabusb_read");
+
+	if (*ppos)
+		return -ESPIPE;
+
+	if (s->remove_pending)
+		return -EIO;
+
+
+	if (!s->usbdev)
+		return -EIO;
+
+	while (count > 0) {
+		dabusb_startrek (s);
+
+		spin_lock_irqsave (&s->lock, flags);
+
+		if (list_empty (&s->rec_buff_list)) {
+
+			spin_unlock_irqrestore(&s->lock, flags);
+
+			err("error: rec_buf_list is empty");
+			goto err;
+		}
+		
+		b = list_entry (s->rec_buff_list.next, buff_t, buff_list);
+		purb = b->purb;
+
+		spin_unlock_irqrestore(&s->lock, flags);
+
+		if (purb->status == -EINPROGRESS) {
+			if (file->f_flags & O_NONBLOCK)		// return nonblocking
+			 {
+				if (!ret)
+					ret = -EAGAIN;
+				goto err;
+			}
+
+			interruptible_sleep_on (&s->wait);
+
+			if (signal_pending (current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				goto err;
+			}
+
+			spin_lock_irqsave (&s->lock, flags);
+
+			if (list_empty (&s->rec_buff_list)) {
+				spin_unlock_irqrestore(&s->lock, flags);
+				err("error: still no buffer available.");
+				goto err;
+			}
+			spin_unlock_irqrestore(&s->lock, flags);
+			s->readptr = 0;
+		}
+		if (s->remove_pending) {
+			ret = -EIO;
+			goto err;
+		}
+
+		rem = purb->actual_length - s->readptr;		// set remaining bytes to copy
+
+		if (count >= rem)
+			cnt = rem;
+		else
+			cnt = count;
+
+		dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt);
+
+		if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) {
+			err("read: copy_to_user failed");
+			if (!ret)
+				ret = -EFAULT;
+			goto err;
+		}
+
+		s->readptr += cnt;
+		count -= cnt;
+		buf += cnt;
+		ret += cnt;
+
+		if (s->readptr == purb->actual_length) {
+			// finished, take next buffer
+			if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
+				err("read: dabusb_add_buf_tail failed");
+			s->readptr = 0;
+		}
+	}
+      err:			//up(&s->mutex);
+	return ret;
+}
+
+static int dabusb_open (struct inode *inode, struct file *file)
+{
+	int devnum = MINOR (inode->i_rdev);
+	pdabusb_t s;
+
+	if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
+		return -EIO;
+
+	s = &dabusb[devnum - DABUSB_MINOR];
+
+	dbg("dabusb_open");
+	down (&s->mutex);
+
+	while (!s->usbdev || s->opened) {
+		up (&s->mutex);
+
+		if (file->f_flags & O_NONBLOCK) {
+			return -EBUSY;
+		}
+		schedule_timeout (HZ / 2);
+
+		if (signal_pending (current)) {
+			return -EAGAIN;
+		}
+		down (&s->mutex);
+	}
+	if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
+		err("set_interface failed");
+		return -EINVAL;
+	}
+	s->opened = 1;
+	up (&s->mutex);
+
+	file->f_pos = 0;
+	file->private_data = s;
+
+	return 0;
+}
+
+static int dabusb_release (struct inode *inode, struct file *file)
+{
+	pdabusb_t s = (pdabusb_t) file->private_data;
+
+	dbg("dabusb_release");
+
+	down (&s->mutex);
+	dabusb_stop (s);
+	dabusb_free_buffers (s);
+	up (&s->mutex);
+
+	if (!s->remove_pending) {
+		if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
+			err("set_interface failed");
+	}
+	else
+		wake_up (&s->remove_ok);
+
+	s->opened = 0;
+	return 0;
+}
+
+static int dabusb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	pdabusb_t s = (pdabusb_t) file->private_data;
+	pbulk_transfer_t pbulk;
+	int ret = 0;
+	int version = DABUSB_VERSION;
+
+	dbg("dabusb_ioctl");
+
+	if (s->remove_pending)
+		return -EIO;
+
+	down (&s->mutex);
+
+	if (!s->usbdev) {
+		up (&s->mutex);
+		return -EIO;
+	}
+
+	switch (cmd) {
+
+	case IOCTL_DAB_BULK:
+		pbulk = (pbulk_transfer_t) kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
+
+		if (!pbulk) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		if (copy_from_user (pbulk, (void *) arg, sizeof (bulk_transfer_t))) {
+			ret = -EFAULT;
+			kfree (pbulk);
+			break;
+		}
+
+		dabusb_bulk (s, pbulk);
+		ret = copy_to_user ((void *) arg, pbulk, sizeof (bulk_transfer_t));
+		kfree (pbulk);
+		break;
+
+	case IOCTL_DAB_OVERRUNS:
+		ret = put_user (s->overruns, (unsigned int *) arg);
+		break;
+
+	case IOCTL_DAB_VERSION:
+		ret = put_user (version, (unsigned int *) arg);
+		break;
+
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+	up (&s->mutex);
+	return ret;
+}
+
+static struct file_operations dabusb_fops =
+{
+	llseek:		dabusb_llseek,
+	read:		dabusb_read,
+	ioctl:		dabusb_ioctl,
+	open:		dabusb_open,
+	release:	dabusb_release,
+};
+
+static int dabusb_find_struct (void)
+{
+	int u;
+
+	for (u = 0; u < NRDABUSB; u++) {
+		pdabusb_t s = &dabusb[u];
+		if (!s->usbdev)
+			return u;
+	}
+	return -1;
+}
+
+/* --------------------------------------------------------------------- */
+static void *dabusb_probe (struct usb_device *usbdev, unsigned int ifnum)
+{
+	int devnum;
+	pdabusb_t s;
+
+	dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
+	  usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);
+
+	/* the 1234:5678 is just a self assigned test ID */
+	if ((usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x2131) &&
+	    (usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x9999))
+		return NULL;
+
+	/* We don't handle multiple configurations */
+	if (usbdev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	if (ifnum != _DABUSB_IF && usbdev->descriptor.idProduct == 0x9999)
+		return NULL;
+
+	devnum = dabusb_find_struct ();
+	if (devnum == -1)
+		return NULL;
+
+	s = &dabusb[devnum];
+
+	down (&s->mutex);
+	s->remove_pending = 0;
+	s->usbdev = usbdev;
+
+	if (usb_set_configuration (usbdev, usbdev->config[0].bConfigurationValue) < 0) {
+		err("set_configuration failed");
+		goto reject;
+	}
+	if (usbdev->descriptor.idProduct == 0x2131) {
+		dabusb_loadmem (s, NULL);
+		goto reject;
+	}
+	else {
+		dabusb_fpga_download (s, NULL);
+
+		if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) {
+			err("set_interface failed");
+			goto reject;
+		}
+	}
+	dbg("bound to interface: %d", ifnum);
+	up (&s->mutex);
+	MOD_INC_USE_COUNT;
+	return s;
+
+      reject:
+	up (&s->mutex);
+	s->usbdev = NULL;
+	return NULL;
+}
+
+static void dabusb_disconnect (struct usb_device *usbdev, void *ptr)
+{
+	pdabusb_t s = (pdabusb_t) ptr;
+
+	dbg("dabusb_disconnect");
+
+	s->remove_pending = 1;
+	wake_up (&s->wait);
+	if (s->state == _started)
+		sleep_on (&s->remove_ok);
+	s->usbdev = NULL;
+	s->overruns = 0;
+	MOD_DEC_USE_COUNT;
+}
+
+static struct usb_driver dabusb_driver =
+{
+	"dabusb",
+	dabusb_probe,
+	dabusb_disconnect,
+	{NULL, NULL},
+	&dabusb_fops,
+	DABUSB_MINOR
+};
+
+/* --------------------------------------------------------------------- */
+
+int __init dabusb_init (void)
+{
+	unsigned u;
+
+	/* register misc device */
+	if (usb_register(&dabusb_driver))
+		return -1;
+
+	/* initialize struct */
+	for (u = 0; u < NRDABUSB; u++) {
+		pdabusb_t s = &dabusb[u];
+		memset (s, 0, sizeof (dabusb_t));
+		init_MUTEX (&s->mutex);
+		s->usbdev = NULL;
+		s->total_buffer_size = buffers;
+		init_waitqueue_head (&s->wait);
+		init_waitqueue_head (&s->remove_ok);
+		spin_lock_init (&s->lock);
+		INIT_LIST_HEAD (&s->free_buff_list);
+		INIT_LIST_HEAD (&s->rec_buff_list);
+	}
+
+	dbg("dabusb_init: driver registered");
+	return 0;
+}
+
+void __exit dabusb_cleanup (void)
+{
+	dbg("dabusb_cleanup");
+
+	usb_deregister (&dabusb_driver);
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de");
+MODULE_DESCRIPTION ("DAB-USB Interface Driver for Linux (c)1999");
+MODULE_PARM (buffers, "i");
+
+int __init init_module (void)
+{
+	return dabusb_init ();
+}
+
+void __exit cleanup_module (void)
+{
+	dabusb_cleanup ();
+}
+
+#endif
+
+/* --------------------------------------------------------------------- */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/dabusb.h linux.18p8/drivers/usb/dabusb.h
--- linux.vanilla/drivers/usb/dabusb.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/dabusb.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,84 @@
+#define _BULK_DATA_LEN 64
+typedef struct
+{
+	unsigned char data[_BULK_DATA_LEN];
+	unsigned int size;
+	unsigned int pipe;
+}bulk_transfer_t,*pbulk_transfer_t;
+
+#define DABUSB_MINOR 240		/* some unassigned USB minor */
+#define DABUSB_VERSION 0x1000
+#define IOCTL_DAB_BULK              _IOWR('d', 0x30, bulk_transfer_t)
+#define IOCTL_DAB_OVERRUNS	    _IOR('d',  0x15, int)
+#define IOCTL_DAB_VERSION           _IOR('d', 0x3f, int) 
+
+#ifdef __KERNEL__
+
+typedef enum { _stopped=0, _started } driver_state_t;
+
+typedef struct
+{
+	struct semaphore mutex;
+	struct usb_device *usbdev;
+	wait_queue_head_t wait;
+	wait_queue_head_t remove_ok;
+	spinlock_t lock;
+	volatile atomic_t pending_io;
+	driver_state_t state;
+	int remove_pending;
+	int got_mem;
+	int total_buffer_size;
+	unsigned int overruns;
+	int readptr;
+	int opened;
+	struct list_head free_buff_list;
+	struct list_head rec_buff_list;
+} dabusb_t,*pdabusb_t;
+
+typedef struct 
+{
+	pdabusb_t s;
+	purb_t purb;
+	struct list_head buff_list;
+} buff_t,*pbuff_t;
+
+typedef struct
+{
+	wait_queue_head_t wait;
+} bulk_completion_context_t, *pbulk_completion_context_t;
+
+
+#define _DABUSB_IF 2
+#define _DABUSB_ISOPIPE 0x09
+#define _ISOPIPESIZE	16384
+
+#define _BULK_DATA_LEN 64
+// Vendor specific request code for Anchor Upload/Download
+// This one is implemented in the core
+#define ANCHOR_LOAD_INTERNAL  0xA0
+
+// EZ-USB Control and Status Register.  Bit 0 controls 8051 reset
+#define CPUCS_REG    0x7F92
+#define _TOTAL_BUFFERS 384
+
+#define MAX_INTEL_HEX_RECORD_LENGTH 16
+
+#ifndef _BYTE_DEFINED
+#define _BYTE_DEFINED
+typedef unsigned char BYTE;
+#endif // !_BYTE_DEFINED
+
+#ifndef _WORD_DEFINED
+#define _WORD_DEFINED
+typedef unsigned short WORD;
+#endif // !_WORD_DEFINED
+
+typedef struct _INTEL_HEX_RECORD
+{
+   BYTE  Length;
+   WORD  Address;
+   BYTE  Type;
+   BYTE  Data[MAX_INTEL_HEX_RECORD_LENGTH];
+} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD;
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/dc2xx.c linux.18p8/drivers/usb/dc2xx.c
--- linux.vanilla/drivers/usb/dc2xx.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/dc2xx.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 1999-2000 by David Brownell <david-b@pacbell.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+ 
+ 
+/*
+ * USB driver for Kodak DC-2XX series digital still cameras
+ *
+ * The protocol here is the same as the one going over a serial line, but
+ * it uses USB for speed.  Set up /dev/kodak, get gphoto (www.gphoto.org),
+ * and have fun!
+ *
+ * This should also work for a number of other digital (non-Kodak) cameras,
+ * by adding the vendor and product IDs to the table below.  They'll need
+ * to be the sort using USB just as a fast bulk data channel.
+ */
+
+/*
+ * HISTORY
+ *
+ * 26 August, 1999 -- first release (0.1), works with my DC-240.
+ * 	The DC-280 (2Mpixel) should also work, but isn't tested.
+ *	If you use gphoto, make sure you have the USB updates.
+ *	Lives in a 2.3.14 or so Linux kernel, in drivers/usb.
+ * 31 August, 1999 -- minor update to recognize DC-260 and handle
+ *	its endpoints being in a different order.  Note that as
+ *	of gPhoto 0.36pre, the USB updates are integrated.
+ * 12 Oct, 1999 -- handle DC-280 interface class (0xff not 0x0);
+ *	added timeouts to bulk_msg calls.  Minor updates, docs.
+ * 03 Nov, 1999 -- update for 2.3.25 kernel API changes.
+ * 08 Jan, 2000 .. multiple camera support
+ *
+ * Thanks to:  the folk who've provided USB product IDs, sent in
+ * patches, and shared their sucesses!
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#undef DEBUG
+#include <linux/usb.h>
+
+
+
+/* current USB framework handles max of 16 USB devices per driver */
+#define	MAX_CAMERAS		8
+
+/* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */
+#define	USB_CAMERA_MINOR_BASE	80
+
+
+// XXX remove packet size limit, now that bulk transfers seem fixed
+
+/* Application protocol limit is 0x8002; USB has disliked that limit! */
+#define	MAX_PACKET_SIZE		0x2000		/* e.g. image downloading */
+
+#define	MAX_READ_RETRY		5		/* times to retry reads */
+#define	MAX_WRITE_RETRY		5		/* times to retry writes */
+#define	RETRY_TIMEOUT		(HZ)		/* sleep between retries */
+
+
+/* table of cameras that work through this driver */
+static const struct camera {
+	unsigned short	idVendor;
+	unsigned short	idProduct;
+	/* plus hooks for camera-specific info if needed */
+} cameras [] = {
+	/* These have the same application level protocol */  
+    { 0x040a, 0x0120 },		// Kodak DC-240
+    { 0x040a, 0x0130 },		// Kodak DC-280
+
+	/* These have a different application level protocol which
+	 * is part of the Flashpoint "DigitaOS".  That supports some
+	 * non-camera devices, and some non-Kodak cameras.
+	 */  
+    { 0x040a, 0x0100 },		// Kodak DC-220
+    { 0x040a, 0x0110 },		// Kodak DC-260
+    { 0x040a, 0x0111 },		// Kodak DC-265
+    { 0x040a, 0x0112 },		// Kodak DC-290
+    { 0xf003, 0x6002 },		// HP PhotoSmart C500
+
+	/* Other USB devices may well work here too, so long as they
+	 * just stick to half duplex bulk packet exchanges.  That
+	 * means, among other things, no iso or interrupt endpoints.
+	 */
+};
+
+
+struct camera_state {
+	struct usb_device	*dev;		/* USB device handle */
+	int			inEP;		/* read endpoint */
+	int			outEP;		/* write endpoint */
+	const struct camera	*info;		/* DC-240, etc */
+	int			subminor;	/* which minor dev #? */
+	int			isActive;	/* I/O taking place? */
+
+	/* this is non-null iff the device is open */
+	char			*buf;		/* buffer for I/O */
+
+	/* always valid */
+	wait_queue_head_t	wait;		/* for timed waits */
+};
+
+
+/* Support multiple cameras, possibly of different types.  */
+static struct camera_state *minor_data [MAX_CAMERAS];
+
+
+static ssize_t camera_read (struct file *file,
+	char *buf, size_t len, loff_t *ppos)
+{
+	struct camera_state	*camera;
+	int			retries;
+
+	if (len > MAX_PACKET_SIZE)
+		return -EINVAL;
+
+	camera = (struct camera_state *) file->private_data;
+	if (!camera->dev)
+		return -ENODEV;
+	if (camera->isActive++)
+		return -EBUSY;
+
+	/* Big reads are common, for image downloading.  Smaller ones
+	 * are also common (even "directory listing" commands don't
+	 * send very much data).  We preserve packet boundaries here,
+	 * they matter in the application protocol.
+	 */
+	for (retries = 0; retries < MAX_READ_RETRY; retries++) {
+		int			count;
+		int			result;
+
+		if (signal_pending (current)) {
+			camera->isActive = 0;
+			return -EINTR;
+		}
+		if (!camera->dev) {
+			camera->isActive = 0;
+			return -ENODEV;
+		}
+
+		result = usb_bulk_msg (camera->dev,
+			  usb_rcvbulkpipe (camera->dev, camera->inEP),
+			  camera->buf, len, &count, HZ*10);
+
+		dbg ("read (%d) - 0x%x %d", len, result, count);
+
+		if (!result) {
+			if (copy_to_user (buf, camera->buf, count))
+				return -EFAULT;
+			camera->isActive = 0;
+			return count;
+		}
+		if (result != USB_ST_TIMEOUT)
+			break;
+		interruptible_sleep_on_timeout (&camera->wait, RETRY_TIMEOUT);
+
+		dbg ("read (%d) - retry", len);
+	}
+	camera->isActive = 0;
+	return -EIO;
+}
+
+static ssize_t camera_write (struct file *file,
+	const char *buf, size_t len, loff_t *ppos)
+{
+	struct camera_state	*camera;
+	ssize_t			bytes_written = 0;
+
+	if (len > MAX_PACKET_SIZE)
+		return -EINVAL;
+
+	camera = (struct camera_state *) file->private_data;
+	if (!camera->dev)
+		return -ENODEV;
+	if (camera->isActive++)
+		return -EBUSY;
+	
+	/* most writes will be small: simple commands, sometimes with
+	 * parameters.  putting images (like borders) into the camera
+	 * would be the main use of big writes.
+	 */
+	while (len > 0) {
+		char		*obuf = camera->buf;
+		int		maxretry = MAX_WRITE_RETRY;
+		unsigned long	copy_size, thistime;
+
+		/* it's not clear that retrying can do any good ... or that
+		 * fragmenting application packets into N writes is correct.
+		 */
+		thistime = copy_size = len;
+		if (copy_from_user (obuf, buf, copy_size)) {
+			bytes_written = -EFAULT;
+			break;
+		}
+		while (thistime) {
+			int		result;
+			int		count;
+
+			if (signal_pending (current)) {
+				if (!bytes_written)
+					bytes_written = -EINTR;
+				goto done;
+			}
+			if (!camera->dev) {
+				if (!bytes_written)
+					bytes_written = -ENODEV;
+				goto done;
+			}
+
+			result = usb_bulk_msg (camera->dev,
+				 usb_sndbulkpipe (camera->dev, camera->outEP),
+				 obuf, thistime, &count, HZ*10);
+
+			if (result)
+				dbg ("write USB err - %x", result);
+
+			if (count) {
+				obuf += count;
+				thistime -= count;
+				maxretry = MAX_WRITE_RETRY;
+				continue;
+			} else if (!result)
+				break;
+				
+			if (result == USB_ST_TIMEOUT) {	/* NAK - delay a bit */
+				if (!maxretry--) {
+					if (!bytes_written)
+						bytes_written = -ETIME;
+					goto done;
+				}
+                                interruptible_sleep_on_timeout (&camera->wait,
+					RETRY_TIMEOUT);
+				continue;
+			} 
+			if (!bytes_written)
+				bytes_written = -EIO;
+			goto done;
+		}
+		bytes_written += copy_size;
+		len -= copy_size;
+		buf += copy_size;
+	}
+done:
+	camera->isActive = 0;
+	dbg ("wrote %d", bytes_written); 
+	return bytes_written;
+}
+
+static int camera_open (struct inode *inode, struct file *file)
+{
+	struct camera_state	*camera;
+	int			subminor;
+
+	subminor = MINOR (inode->i_rdev) - USB_CAMERA_MINOR_BASE;
+	if (subminor < 0 || subminor >= MAX_CAMERAS
+			|| !(camera = minor_data [subminor])) {
+		return -ENODEV;
+	}
+
+	if (!(camera->buf = (char *) kmalloc (MAX_PACKET_SIZE, GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+
+	dbg ("open"); 
+
+	camera->isActive = 0;
+	file->private_data = camera;
+	return 0;
+}
+
+static int camera_release (struct inode *inode, struct file *file)
+{
+	struct camera_state *camera;
+
+	camera = (struct camera_state *) file->private_data;
+	kfree (camera->buf);
+
+	/* If camera was unplugged with open file ... */
+	if (!camera->dev) {
+		minor_data [camera->subminor] = NULL;
+		kfree (camera);
+	}
+
+	dbg ("close"); 
+
+	return 0;
+}
+
+	/* XXX should define some ioctls to expose camera type
+	 * to applications ... what USB exposes should suffice.
+	 * apps should be able to see the camera type.
+	 */
+static /* const */ struct file_operations usb_camera_fops = {
+	    /* Uses GCC initializer extension; simpler to maintain */
+	read:		camera_read,
+	write:		camera_write,
+	open:		camera_open,
+	release:	camera_release,
+};
+
+
+
+static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	int				i;
+	const struct camera		*camera_info = NULL;
+	struct usb_interface_descriptor	*interface;
+	struct usb_endpoint_descriptor	*endpoint;
+	int				direction, ep;
+	struct camera_state		*camera;
+
+	/* Is it a supported camera? */
+	for (i = 0; i < sizeof (cameras) / sizeof (struct camera); i++) {
+		if (cameras [i].idVendor != dev->descriptor.idVendor)
+			continue;
+		if (cameras [i].idProduct != dev->descriptor.idProduct)
+			continue;
+		camera_info = &cameras [i];
+		break;
+	}
+	if (camera_info == NULL)
+		return NULL;
+
+	/* these have one config, one interface */
+	if (dev->descriptor.bNumConfigurations != 1
+			|| dev->config[0].bNumInterfaces != 1) {
+		dbg ("Bogus camera config info");
+		return NULL;
+	}
+
+	/* models differ in how they report themselves */
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	if ((interface->bInterfaceClass != USB_CLASS_PER_INTERFACE
+		&& interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+			|| interface->bInterfaceSubClass != 0
+			|| interface->bInterfaceProtocol != 0
+			|| interface->bNumEndpoints != 2
+			) {
+		dbg ("Bogus camera interface info");
+		return NULL;
+	}
+
+
+	/* select "subminor" number (part of a minor number) */
+	for (i = 0; i < MAX_CAMERAS; i++) {
+		if (!minor_data [i])
+			break;
+	}
+	if (i >= MAX_CAMERAS) {
+		info ("Ignoring additional USB Camera");
+		return NULL;
+	}
+
+	/* allocate & init camera state */
+	camera = minor_data [i] = kmalloc (sizeof *camera, GFP_KERNEL);
+	if (!camera) {
+		err ("no memory!");
+		return NULL;
+	}
+	camera->info = camera_info;
+	camera->subminor = i;
+	camera->isActive = 0;
+	camera->buf = NULL;
+	init_waitqueue_head (&camera->wait);
+	info ("USB Camera #%d connected", camera->subminor);
+
+
+	/* get input and output endpoints (either order) */
+	endpoint = interface->endpoint;
+	camera->outEP = camera->inEP =  -1;
+
+	ep = endpoint [0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	direction = endpoint [0].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+	if (direction == USB_DIR_IN)
+		camera->inEP = ep;
+	else
+		camera->outEP = ep;
+
+	ep = endpoint [1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	direction = endpoint [1].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+	if (direction == USB_DIR_IN)
+		camera->inEP = ep;
+	else
+		camera->outEP = ep;
+
+	if (camera->outEP == -1 || camera->inEP == -1
+			|| endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK
+			|| endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK
+			) {
+		dbg ("Bogus endpoints");
+		goto error;
+	}
+
+
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue)) {
+		err ("Failed usb_set_configuration");
+		goto error;
+	}
+
+	camera->dev = dev;
+	return camera;
+
+error:
+	minor_data [camera->subminor] = NULL;
+	kfree (camera);
+	return NULL;
+}
+
+static void camera_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct camera_state	*camera = (struct camera_state *) ptr;
+	int			subminor = camera->subminor;
+
+	/* If camera's not opened, we can clean up right away.
+	 * Else apps see a disconnect on next I/O; the release cleans.
+	 */
+	if (!camera->buf) {
+		minor_data [subminor] = NULL;
+		kfree (camera);
+	} else
+		camera->dev = NULL;
+
+	info ("USB Camera #%d disconnected", subminor);
+}
+
+static /* const */ struct usb_driver camera_driver = {
+	"dc2xx",
+	camera_probe,
+	camera_disconnect,
+	{ NULL, NULL },
+	&usb_camera_fops,
+	USB_CAMERA_MINOR_BASE
+};
+
+
+int __init usb_dc2xx_init(void)
+{
+ 	if (usb_register (&camera_driver) < 0)
+ 		return -1;
+	return 0;
+}
+
+void __exit usb_dc2xx_cleanup(void)
+{
+	usb_deregister (&camera_driver);
+}
+
+
+MODULE_AUTHOR("David Brownell, david-b@pacbell.net");
+MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras");
+
+module_init (usb_dc2xx_init);
+module_exit (usb_dc2xx_cleanup);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/devices.c linux.18p8/drivers/usb/devices.c
--- linux.vanilla/drivers/usb/devices.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/devices.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,526 @@
+/*
+ * devices.c
+ * (C) Copyright 1999 Randy Dunlap.
+ * (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
+ * (C) Copyright 1999 Deti Fliegl (new USB architecture)
+ *
+ * $id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *************************************************************
+ *
+ * <mountpoint>/devices contains USB topology, device, config, class,
+ * interface, & endpoint data.
+ *
+ * I considered using /proc/bus/usb/devices/device# for each device
+ * as it is attached or detached, but I didn't like this for some
+ * reason -- maybe it's just too deep of a directory structure.
+ * I also don't like looking in multiple places to gather and view
+ * the data.  Having only one file for ./devices also prevents race
+ * conditions that could arise if a program was reading device info
+ * for devices that are being removed (unplugged).  (That is, the
+ * program may find a directory for devnum_12 then try to open it,
+ * but it was just unplugged, so the directory is now deleted.
+ * But programs would just have to be prepared for situations like
+ * this in any plug-and-play environment.)
+ *
+ * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *   Converted the whole proc stuff to real
+ *   read methods. Now not the whole device list needs to fit
+ *   into one page, only the device list for one bus.
+ *   Added a poll method to /proc/bus/usb/devices, to wake
+ *   up an eventual usbd
+ * 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *   Turned into its own filesystem
+ *
+ * $Id: devices.c,v 1.5 2000/01/11 13:58:21 tom Exp $
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+#include <linux/usbdevice_fs.h>
+#include <asm/uaccess.h>
+
+#define MAX_TOPO_LEVEL		6
+
+/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
+#define ALLOW_SERIAL_NUMBER
+
+static char *format_topo =
+/* T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
+  "T:  Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
+
+static char *format_string_manufacturer =
+/* S:  Manufacturer=xxxx */
+  "S:  Manufacturer=%.100s\n";
+
+static char *format_string_product =
+/* S:  Product=xxxx */
+  "S:  Product=%.100s\n";
+
+#ifdef ALLOW_SERIAL_NUMBER
+static char *format_string_serialnumber =
+/* S:  SerialNumber=xxxx */
+  "S:  SerialNumber=%.100s\n";
+#endif
+
+static char *format_bandwidth =
+/* B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
+  "B:  Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
+  
+static char *format_device1 =
+/* D:  Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
+  "D:  Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
+
+static char *format_device2 =
+/* P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx */
+  "P:  Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
+
+static char *format_config =
+/* C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
+  "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
+  
+static char *format_iface =
+/* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
+  "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+
+static char *format_endpt =
+/* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
+  "E:  Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n";
+
+
+/*
+ * Need access to the driver and USB bus lists.
+ * extern struct list_head usb_driver_list;
+ * extern struct list_head usb_bus_list;
+ * However, these will come from functions that return ptrs to each of them.
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
+static unsigned int conndiscevcnt = 0;
+
+/* this struct stores the poll state for <mountpoint>/devices pollers */
+struct usb_device_status {
+	unsigned int lastev;
+};
+
+struct class_info {
+	int class;
+	char *class_name;
+};
+
+static const struct class_info clas_info[] =
+{					/* max. 5 chars. per name string */
+	{USB_CLASS_PER_INTERFACE,	">ifc"},
+	{USB_CLASS_AUDIO,		"audio"},
+	{USB_CLASS_COMM,		"comm."},
+	{USB_CLASS_HID,			"HID"},
+	{USB_CLASS_HUB,			"hub"},
+	{USB_CLASS_PRINTER,		"print"},
+	{USB_CLASS_MASS_STORAGE,	"stor."},
+	{USB_CLASS_DATA,		"data"},
+	{USB_CLASS_VENDOR_SPEC,		"vend."},
+	{-1,				"unk."}		/* leave as last */
+};
+
+/*****************************************************************/
+
+void usbdevfs_conn_disc_event(void)
+{
+	wake_up(&deviceconndiscwq);
+	conndiscevcnt++;
+}
+
+static const char *class_decode(const int class)
+{
+	int ix;
+
+	for (ix = 0; clas_info[ix].class != -1; ix++)
+		if (clas_info[ix].class == class)
+			break;
+	return (clas_info[ix].class_name);
+}
+
+static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct usb_endpoint_descriptor *desc)
+{
+	char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
+
+	if (start > end)
+		return start;
+	start += sprintf(start, format_endpt, desc->bEndpointAddress,
+			 (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL
+			 	? 'B' :			/* bidirectional */
+			 (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
+			 desc->bmAttributes, EndpointType[desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK],
+			 desc->wMaxPacketSize, desc->bInterval);
+	return start;
+}
+
+static char *usb_dump_endpoint(char *start, char *end, const struct usb_endpoint_descriptor *endpoint)
+{
+	return usb_dump_endpoint_descriptor(start, end, endpoint);
+}
+
+static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
+{
+	struct usb_interface_descriptor *desc = &iface->altsetting[setno];
+
+	if (start > end)
+		return start;
+	start += sprintf(start, format_iface,
+			 desc->bInterfaceNumber,
+			 desc->bAlternateSetting,
+			 desc->bNumEndpoints,
+			 desc->bInterfaceClass,
+			 class_decode(desc->bInterfaceClass),
+			 desc->bInterfaceSubClass,
+			 desc->bInterfaceProtocol,
+			 iface->driver ? iface->driver->name : "(none)");
+	return start;
+}
+
+static char *usb_dump_interface(char *start, char *end, const struct usb_interface *iface, int setno)
+{
+	struct usb_interface_descriptor *desc = &iface->altsetting[setno];
+	int i;
+
+	start = usb_dump_interface_descriptor(start, end, iface, setno);
+	for (i = 0; i < desc->bNumEndpoints; i++) {
+		if (start > end)
+			return start;
+		start = usb_dump_endpoint(start, end, desc->endpoint + i);
+	}
+	return start;
+}
+
+/* TBD:
+ * 0. TBDs
+ * 1. marking active config and ifaces (code lists all, but should mark
+ *    which ones are active, if any)
+ * 2. add <halted> status to each endpoint line
+ */
+
+static char *usb_dump_config_descriptor(char *start, char *end, const struct usb_config_descriptor *desc, int active)
+{
+	if (start > end)
+		return start;
+	start += sprintf(start, format_config,
+			 active ? '*' : ' ',	/* mark active/actual/current cfg. */
+			 desc->bNumInterfaces,
+			 desc->bConfigurationValue,
+			 desc->bmAttributes,
+			 desc->MaxPower * 2);
+	return start;
+}
+
+static char *usb_dump_config(char *start, char *end, const struct usb_config_descriptor *config, int active)
+{
+	int i, j;
+	struct usb_interface *interface;
+
+	if (start > end)
+		return start;
+	if (!config)		/* getting these some in 2.3.7; none in 2.3.6 */
+		return start + sprintf(start, "(null Cfg. desc.)\n");
+	start = usb_dump_config_descriptor(start, end, config, active);
+	for (i = 0; i < config->bNumInterfaces; i++) {
+		interface = config->interface + i;
+		if (!interface)
+			break;
+		for (j = 0; j < interface->num_altsetting; j++) {
+			if (start > end)
+				return start;
+			start = usb_dump_interface(start, end, interface, j);
+		}
+	}
+	return start;
+}
+
+/*
+ * Dump the different USB descriptors.
+ */
+static char *usb_dump_device_descriptor(char *start, char *end, const struct usb_device_descriptor *desc)
+{
+	if (start > end)
+		return start;
+	start += sprintf (start, format_device1,
+			  desc->bcdUSB >> 8, desc->bcdUSB & 0xff,
+			  desc->bDeviceClass,
+			  class_decode (desc->bDeviceClass),
+			  desc->bDeviceSubClass,
+			  desc->bDeviceProtocol,
+			  desc->bMaxPacketSize0,
+			  desc->bNumConfigurations);
+	if (start > end)
+		return start;
+	start += sprintf(start, format_device2,
+			 desc->idVendor, desc->idProduct,
+			 desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
+	return start;
+}
+
+/*
+ * Dump the different strings that this device holds.
+ */
+static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+{
+	char *buf;
+
+	if (start > end)
+		return start;
+	buf = kmalloc(128, GFP_KERNEL);
+	if (!buf)
+		return start;
+	if (dev->descriptor.iManufacturer) {
+		if (usb_string(dev, dev->descriptor.iManufacturer, buf, 128) > 0)
+			start += sprintf(start, format_string_manufacturer, buf);
+	}				
+	if (start > end)
+		goto out;
+	if (dev->descriptor.iProduct) {
+		if (usb_string(dev, dev->descriptor.iProduct, buf, 128) > 0)
+			start += sprintf(start, format_string_product, buf);
+	}
+	if (start > end)
+		goto out;
+#ifdef ALLOW_SERIAL_NUMBER
+	if (dev->descriptor.iSerialNumber) {
+		if (usb_string(dev, dev->descriptor.iSerialNumber, buf, 128) > 0)
+			start += sprintf(start, format_string_serialnumber, buf);
+	}
+#endif
+ out:
+	kfree(buf);
+	return start;
+}
+
+static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
+{
+	int i;
+
+	if (start > end)
+		return start;
+		
+	start = usb_dump_device_descriptor(start, end, &dev->descriptor);
+
+	if (start > end)
+		return start;
+	
+	start = usb_dump_device_strings (start, end, dev);
+	
+	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+		if (start > end)
+			return start;
+		start = usb_dump_config(start, end, dev->config + i,
+					(dev->config + i) == dev->actconfig); /* active ? */
+	}
+	return start;
+}
+
+
+#ifdef PROC_EXTRA /* TBD: may want to add this code later */
+
+static char *usb_dump_hub_descriptor(char *start, char *end, const struct usb_hub_descriptor * desc)
+{
+	int leng = USB_DT_HUB_NONVAR_SIZE;
+	unsigned char *ptr = (unsigned char *)desc;
+
+	if (start > end)
+		return start;
+	start += sprintf(start, "Interface:");
+	while (leng && start <= end) {
+		start += sprintf(start, " %02x", *ptr);
+		ptr++; leng--;
+	}
+	*start++ = '\n';
+	return start;
+}
+
+static char *usb_dump_string(char *start, char *end, const struct usb_device *dev, char *id, int index)
+{
+	if (start > end)
+		return start;
+	start += sprintf(start, "Interface:");
+	if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
+		start += sprintf(start, "%s: %.100s ", id, dev->stringindex[index]);
+	return start;
+}
+
+#endif /* PROC_EXTRA */
+
+/*****************************************************************/
+
+static char *usb_device_dump(char *start, char *end, struct usb_device *usbdev,
+			     struct usb_bus *bus, int level, int index, int count)
+{
+	int chix;
+	int cnt = 0;
+	int parent_devnum = 0;
+
+	if (level > MAX_TOPO_LEVEL)
+		return start;
+	if (usbdev->parent && usbdev->parent->devnum != -1)
+		parent_devnum = usbdev->parent->devnum;
+	/*
+	 * So the root hub's parent is 0 and any device that is
+	 * plugged into the root hub has a parent of 0.
+	 */
+	start += sprintf(start, format_topo, bus->busnum, level, parent_devnum, index, count,
+			 usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild);
+	/*
+	 * level = topology-tier level;
+	 * parent_devnum = parent device number;
+	 * index = parent's connector number;
+	 * count = device count at this level
+	 */
+	/* If this is the root hub, display the bandwidth information */
+	if (level == 0)
+		start += sprintf(start, format_bandwidth, bus->bandwidth_allocated, 
+				FRAME_TIME_MAX_USECS_ALLOC,
+				(100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC,
+			         bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs);
+	start = usb_dump_desc(start, end, usbdev);
+	if (start > end)
+		return start + sprintf(start, "(truncated)\n");
+	/* Now look at all of this device's children. */
+	for (chix = 0; chix < usbdev->maxchild; chix++) {
+		if (start > end)
+			return start;
+		if (usbdev->children[chix])
+			start = usb_device_dump(start, end, usbdev->children[chix], bus, level + 1, chix, ++cnt);
+	}
+	return start;
+}
+
+static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+	struct list_head *buslist;
+	struct usb_bus *bus;
+	char *page, *end;
+	ssize_t ret = 0;
+	unsigned int pos, len;
+
+	if (*ppos < 0)
+		return -EINVAL;
+	if (nbytes <= 0)
+		return 0;
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EFAULT;
+        if (!(page = (char*) __get_free_pages(GFP_KERNEL,1)))
+                return -ENOMEM;
+	pos = *ppos;
+	/* enumerate busses */
+	for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
+		/* print devices for this bus */
+		bus = list_entry(buslist, struct usb_bus, bus_list);
+		end = usb_device_dump(page, page + (2*PAGE_SIZE - 256), bus->root_hub, bus, 0, 0, 0);
+		len = end - page;
+		if (len > pos) {
+			len -= pos;
+			if (len > nbytes)
+				len = nbytes;
+			if (copy_to_user(buf, page + pos, len)) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+			nbytes -= len;
+			buf += len;
+			ret += len;
+			pos = 0;
+			*ppos += len;
+		} else
+			pos -= len;
+	}
+	free_pages((unsigned long)page, 1);
+	return ret;
+}
+
+/* Kernel lock for "lastev" protection */
+static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct usb_device_status *st = (struct usb_device_status *)file->private_data;
+	unsigned int mask = 0;
+
+	lock_kernel();
+	if (!st) {
+		st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
+		if (!st)
+			return POLLIN;
+		/*
+		 * need to prevent the module from being unloaded, since
+		 * proc_unregister does not call the release method and
+		 * we would have a memory leak
+		 */
+		st->lastev = conndiscevcnt;
+		file->private_data = st;
+		mask = POLLIN;
+	}
+	if (file->f_mode & FMODE_READ)
+                poll_wait(file, &deviceconndiscwq, wait);
+	if (st->lastev != conndiscevcnt)
+		mask |= POLLIN;
+	st->lastev = conndiscevcnt;
+	unlock_kernel();
+	return mask;
+}
+
+static int usb_device_open(struct inode *inode, struct file *file)
+{
+        file->private_data = NULL;
+        return 0;
+}
+
+static int usb_device_release(struct inode *inode, struct file *file)
+{
+	if (file->private_data) {
+		kfree(file->private_data);
+		file->private_data = NULL;
+	}
+
+        return 0;
+}
+
+static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
+{
+	switch (orig) {
+	case 0:
+		file->f_pos = offset;
+		return file->f_pos;
+
+	case 1:
+		file->f_pos += offset;
+		return file->f_pos;
+
+	case 2:
+		return -EINVAL;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+struct file_operations usbdevfs_devices_fops = {
+	llseek:		usb_device_lseek,
+	read:		usb_device_read,
+	poll:		usb_device_poll,
+	open:		usb_device_open,
+	release:	usb_device_release,
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/devio.c linux.18p8/drivers/usb/devio.c
--- linux.vanilla/drivers/usb/devio.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/devio.c	Fri Sep 15 12:49:48 2000
@@ -0,0 +1,1254 @@
+/*****************************************************************************/
+
+/*
+ *      devio.c  --  User space communication with USB devices.
+ *
+ *      Copyright (C) 1999-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  $Id: devio.c,v 1.7 2000/02/01 17:28:48 fliegl Exp $
+ *
+ *  This file implements the usbdevfs/x/y files, where
+ *  x is the bus number and y the device number.
+ *
+ *  It allows user space programs/"drivers" to communicate directly
+ *  with USB devices without intervening kernel driver.
+ *
+ *  Revision history
+ *    22.12.1999   0.1   Initial release (split from proc_usb.c)
+ *    04.01.2000   0.2   Turned into its own filesystem
+ */
+
+/*****************************************************************************/
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/signal.h>
+#include <linux/poll.h>
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <asm/uaccess.h>
+
+
+struct async {
+        struct list_head asynclist;
+        struct dev_state *ps;
+	struct task_struct *task;
+	unsigned int signr;
+	void *userbuffer;
+        void *userurb;
+        urb_t urb;
+};
+
+/*
+ * my own sync control and bulk methods. Here to experiment
+ * and because the kernel ones set the process to TASK_UNINTERRUPTIBLE.
+ */
+
+struct sync {
+	wait_queue_head_t wait;
+};
+
+static void sync_completed(purb_t urb)
+{
+        struct sync *s = (struct sync *)urb->context;
+ 
+        wake_up(&s->wait);	
+}
+
+static int do_sync(purb_t urb, int timeout)
+{
+        DECLARE_WAITQUEUE(wait, current);
+	unsigned long tm;
+	signed long tmdiff;
+	struct sync s;
+	int ret;
+
+	tm = jiffies+timeout;
+	init_waitqueue_head(&s.wait);
+	add_wait_queue(&s.wait, &wait);
+	urb->context = &s;
+	urb->complete = sync_completed;
+	set_current_state(TASK_INTERRUPTIBLE);
+	if ((ret = usb_submit_urb(urb)))
+		goto out;
+	while (urb->status == -EINPROGRESS) {
+		tmdiff = tm - jiffies;
+		if (tmdiff <= 0) {
+			ret = -ETIMEDOUT;
+			goto out;
+		}
+		if (signal_pending(current)) {
+			ret = -EINTR;
+			goto out;
+		}
+		schedule_timeout(tmdiff);
+	}
+	ret = urb->status;
+ out:
+	set_current_state(TASK_RUNNING);
+	usb_unlink_urb(urb);
+	remove_wait_queue(&s.wait, &wait);
+	return ret;
+}
+
+static int my_usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
+			      __u16 value, __u16 index, void *data, __u16 size, int timeout)
+{
+	urb_t *urb;
+	int ret;
+
+	if (!(urb = usb_alloc_urb(0)))
+		return -ENOMEM;
+	if (!(urb->setup_packet = kmalloc(8, GFP_KERNEL))) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+	urb->setup_packet[0] = requesttype;
+	urb->setup_packet[1] = request;
+	urb->setup_packet[2] = value;
+	urb->setup_packet[3] = value >> 8;
+	urb->setup_packet[4] = index;
+	urb->setup_packet[5] = index >> 8;
+	urb->setup_packet[6] = size;
+	urb->setup_packet[7] = size >> 8;
+	urb->dev = dev;
+        urb->pipe = pipe;
+        urb->transfer_buffer = data;
+        urb->transfer_buffer_length = size;
+	ret = do_sync(urb, timeout);
+	//if (ret >= 0)
+	//	ret = urb->status;
+	if (ret >= 0)
+		ret = urb->actual_length;
+	kfree(urb->setup_packet);
+	usb_free_urb(urb);
+	return ret;
+}
+
+static int my_usb_bulk_msg(struct usb_device *dev, unsigned int pipe, 
+			   void *data, int len, int *actual_length, int timeout)
+{
+	urb_t *urb;
+	int ret;
+
+	if (!(urb = usb_alloc_urb(0)))
+		return -ENOMEM;
+        urb->dev = dev;
+        urb->pipe = pipe;
+        urb->transfer_buffer = data;
+        urb->transfer_buffer_length = len;
+	ret = do_sync(urb, timeout);
+	//if (ret >= 0)
+	//	ret = urb->status;
+	if (ret >= 0 && actual_length != NULL)
+		*actual_length = urb->actual_length;
+	usb_free_urb(urb);
+	return ret;
+}
+
+static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
+{
+	switch (orig) {
+	case 0:
+		file->f_pos = offset;
+		return file->f_pos;
+
+	case 1:
+		file->f_pos += offset;
+		return file->f_pos;
+
+	case 2:
+		return -EINVAL;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static ssize_t usbdev_read(struct file *file, char * buf, size_t nbytes, loff_t *ppos)
+{
+	struct dev_state *ps = (struct dev_state *)file->private_data;
+	ssize_t ret = 0;
+	unsigned len;
+	loff_t pos;
+	int i;
+
+	pos = *ppos;
+	down_read(&ps->devsem);
+	if (!ps->dev) {
+		ret = -ENODEV;
+		goto err;
+	} else if (pos < 0) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (pos < sizeof(struct usb_device_descriptor)) {
+		len = sizeof(struct usb_device_descriptor) - pos;
+		if (len > nbytes)
+			len = nbytes;
+		if (copy_to_user(buf, ((char *)&ps->dev->descriptor) + pos, len)) {
+			ret = -EFAULT;
+			goto err;
+		}
+
+		*ppos += len;
+		buf += len;
+		nbytes -= len;
+		ret += len;
+	}
+
+	pos = sizeof(struct usb_device_descriptor);
+	for (i = 0; nbytes && i < ps->dev->descriptor.bNumConfigurations; i++) {
+		struct usb_config_descriptor *config =
+			(struct usb_config_descriptor *)ps->dev->rawdescriptors[i];
+		unsigned int length = le16_to_cpu(config->wTotalLength);
+
+		if (*ppos < pos + length) {
+			len = length - (*ppos - pos);
+			if (len > nbytes)
+				len = nbytes;
+
+			if (copy_to_user(buf,
+			    ps->dev->rawdescriptors[i] + (*ppos - pos), len)) {
+				ret = -EFAULT;
+				goto err;
+			}
+
+			*ppos += len;
+			buf += len;
+			nbytes -= len;
+			ret += len;
+		}
+
+		pos += length;
+	}
+
+err:
+	up_read(&ps->devsem);
+	return ret;
+}
+
+extern inline unsigned int ld2(unsigned int x)
+{
+        unsigned int r = 0;
+        
+        if (x >= 0x10000) {
+                x >>= 16;
+                r += 16;
+        }
+        if (x >= 0x100) {
+                x >>= 8;
+                r += 8;
+        }
+        if (x >= 0x10) {
+                x >>= 4;
+                r += 4;
+        }
+        if (x >= 4) {
+                x >>= 2;
+                r += 2;
+        }
+        if (x >= 2)
+                r++;
+        return r;
+}
+
+/*
+ * async list handling
+ */
+
+static struct async *alloc_async(unsigned int numisoframes)
+{
+        unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t);
+        struct async *as = kmalloc(assize, GFP_KERNEL);
+        if (!as)
+                return NULL;
+        memset(as, 0, assize);
+        as->urb.number_of_packets = numisoframes;
+        return as;
+}
+
+static void free_async(struct async *as)
+{
+        if (as->urb.transfer_buffer)
+                kfree(as->urb.transfer_buffer);
+        kfree(as);
+}
+
+extern __inline__ void async_newpending(struct async *as)
+{
+        struct dev_state *ps = as->ps;
+        unsigned long flags;
+        
+        spin_lock_irqsave(&ps->lock, flags);
+        list_add_tail(&as->asynclist, &ps->async_pending);
+        spin_unlock_irqrestore(&ps->lock, flags);
+}
+
+extern __inline__ void async_removepending(struct async *as)
+{
+        struct dev_state *ps = as->ps;
+        unsigned long flags;
+        
+        spin_lock_irqsave(&ps->lock, flags);
+        list_del(&as->asynclist);
+        INIT_LIST_HEAD(&as->asynclist);
+        spin_unlock_irqrestore(&ps->lock, flags);
+}
+
+extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
+{
+        unsigned long flags;
+        struct async *as = NULL;
+
+        spin_lock_irqsave(&ps->lock, flags);
+        if (!list_empty(&ps->async_completed)) {
+                as = list_entry(ps->async_completed.next, struct async, asynclist);
+                list_del(&as->asynclist);
+                INIT_LIST_HEAD(&as->asynclist);
+        }
+        spin_unlock_irqrestore(&ps->lock, flags);
+        return as;
+}
+
+extern __inline__ struct async *async_getpending(struct dev_state *ps, void *userurb)
+{
+        unsigned long flags;
+        struct async *as;
+        struct list_head *p;
+
+        spin_lock_irqsave(&ps->lock, flags);
+        for (p = ps->async_pending.next; p != &ps->async_pending; ) {
+                as = list_entry(p, struct async, asynclist);
+                p = p->next;
+                if (as->userurb != userurb)
+                        continue;
+                list_del(&as->asynclist);
+                INIT_LIST_HEAD(&as->asynclist);
+                spin_unlock_irqrestore(&ps->lock, flags);
+                return as;
+        }
+        spin_unlock_irqrestore(&ps->lock, flags);
+        return NULL;
+}
+
+static void async_completed(purb_t urb)
+{
+        struct async *as = (struct async *)urb->context;
+        struct dev_state *ps = as->ps;
+	struct siginfo sinfo;
+
+#if 1
+	printk(KERN_DEBUG "usbdevfs: async_completed: status %d errcount %d actlen %d pipe 0x%x\n", 
+	       urb->status, urb->error_count, urb->actual_length, urb->pipe);
+#endif
+        spin_lock(&ps->lock);
+        list_del(&as->asynclist);
+        list_add_tail(&as->asynclist, &ps->async_completed);
+        spin_unlock(&ps->lock);
+        wake_up(&ps->wait);
+	if (as->signr) {
+		sinfo.si_signo = as->signr;
+		sinfo.si_errno = as->urb.status;
+		sinfo.si_code = SI_ASYNCIO;
+		sinfo.si_addr = as->userurb;
+		send_sig_info(as->signr, &sinfo, as->task);
+	}
+}
+
+static void destroy_all_async(struct dev_state *ps)
+{
+        struct async *as;
+        unsigned long flags;
+
+        spin_lock_irqsave(&ps->lock, flags);
+        while (!list_empty(&ps->async_pending)) {
+                as = list_entry(ps->async_pending.next, struct async, asynclist);
+                list_del(&as->asynclist);
+                INIT_LIST_HEAD(&as->asynclist);
+                spin_unlock_irqrestore(&ps->lock, flags);
+                /* usb_unlink_urb calls the completion handler with status == USB_ST_URB_KILLED */
+                usb_unlink_urb(&as->urb);
+                spin_lock_irqsave(&ps->lock, flags);
+        }
+        spin_unlock_irqrestore(&ps->lock, flags);
+        while ((as = async_getcompleted(ps)))
+                free_async(as);
+}
+
+/*
+ * interface claiming
+ */
+
+static void *driver_probe(struct usb_device *dev, unsigned int intf)
+{
+	return NULL;
+}
+
+static void driver_disconnect(struct usb_device *dev, void *context)
+{
+	struct dev_state *ps = (struct dev_state *)context;
+
+	ps->ifclaimed = 0;
+}
+
+struct usb_driver usbdevfs_driver = {
+	name:		"usbdevfs",
+	probe:		driver_probe,
+	disconnect:	driver_disconnect,
+};
+
+static int claimintf(struct dev_state *ps, unsigned int intf)
+{
+	struct usb_device *dev = ps->dev;
+	struct usb_interface *iface;
+	int err;
+
+	if (intf >= 8*sizeof(ps->ifclaimed) || !dev || intf >= dev->actconfig->bNumInterfaces)
+		return -EINVAL;
+	/* already claimed */
+	if (test_bit(intf, &ps->ifclaimed))
+		return 0;
+	iface = &dev->actconfig->interface[intf];
+	err = -EBUSY;
+	lock_kernel();
+	if (!usb_interface_claimed(iface)) {
+		usb_driver_claim_interface(&usbdevfs_driver, iface, ps);
+		set_bit(intf, &ps->ifclaimed);
+		err = 0;
+	}
+	unlock_kernel();
+	return err;
+}
+
+static int releaseintf(struct dev_state *ps, unsigned int intf)
+{
+	struct usb_device *dev;
+	struct usb_interface *iface;
+	int err;
+
+	if (intf >= 8*sizeof(ps->ifclaimed))
+		return -EINVAL;
+	err = -EINVAL;
+	lock_kernel();
+	dev = ps->dev;
+	if (dev && test_and_clear_bit(intf, &ps->ifclaimed)) {
+		iface = &dev->actconfig->interface[intf];
+		usb_driver_release_interface(&usbdevfs_driver, iface);
+		err = 0;
+	}
+	unlock_kernel();
+	return err;
+}
+
+static int checkintf(struct dev_state *ps, unsigned int intf)
+{
+	if (intf >= 8*sizeof(ps->ifclaimed))
+		return -EINVAL;
+	if (test_bit(intf, &ps->ifclaimed))
+		return 0;
+	/* if not yet claimed, claim it for the driver */
+	printk(KERN_WARNING "usbdevfs: process %d (%s) did not claim interface %u before use\n",
+	       current->pid, current->comm, intf);
+	return claimintf(ps, intf);
+}
+
+static int findintfep(struct usb_device *dev, unsigned int ep)
+{
+	unsigned int i, j, e;
+        struct usb_interface *iface;
+	struct usb_interface_descriptor *alts;
+	struct usb_endpoint_descriptor *endpt;
+
+	if (ep & ~(USB_DIR_IN|0xf))
+		return -EINVAL;
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+		iface = &dev->actconfig->interface[i];
+		for (j = 0; j < iface->num_altsetting; j++) {
+                        alts = &iface->altsetting[j];
+			for (e = 0; e < alts->bNumEndpoints; e++) {
+				endpt = &alts->endpoint[e];
+				if (endpt->bEndpointAddress == ep)
+					return i;
+			}
+		}
+	}
+	return -ENOENT; 
+}
+
+static int findintfif(struct usb_device *dev, unsigned int ifn)
+{
+	unsigned int i, j;
+        struct usb_interface *iface;
+	struct usb_interface_descriptor *alts;
+
+	if (ifn & ~0xff)
+		return -EINVAL;
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+		iface = &dev->actconfig->interface[i];
+		for (j = 0; j < iface->num_altsetting; j++) {
+                        alts = &iface->altsetting[j];
+			if (alts->bInterfaceNumber == ifn)
+				return i;
+		}
+	}
+	return -ENOENT; 
+}
+
+extern struct list_head usb_driver_list;
+
+#if 0
+static int finddriver(struct usb_driver **driver, char *name)
+{
+	struct list_head *tmp;
+
+	tmp = usb_driver_list.next;
+	while (tmp != &usb_driver_list) {
+		struct usb_driver *d = list_entry(tmp, struct usb_driver,
+							driver_list);
+
+		if (!strcmp(d->name, name)) {
+			*driver = d;
+			return 0;
+		}
+
+		tmp = tmp->next;
+	}
+
+	return -EINVAL;
+}
+#endif
+
+/*
+ * file operations
+ */
+static int usbdev_open(struct inode *inode, struct file *file)
+{
+	struct usb_device *dev;
+	struct dev_state *ps;
+	int ret;
+
+	/* 
+	 * no locking necessary here, as both sys_open (actually filp_open)
+	 * and the hub thread have the kernel lock
+	 * (still acquire the kernel lock for safety)
+	 */
+	lock_kernel();
+	ret = -ENOENT;
+	if (ITYPE(inode->i_ino) != IDEVICE)
+		goto out;
+	dev = inode->u.usbdev_i.p.dev;
+	if (!dev)
+		goto out;
+	ret = -ENOMEM;
+	if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
+		goto out;
+	ret = 0;
+	ps->dev = dev;
+	ps->file = file;
+	spin_lock_init(&ps->lock);
+	INIT_LIST_HEAD(&ps->async_pending);
+	INIT_LIST_HEAD(&ps->async_completed);
+	init_waitqueue_head(&ps->wait);
+	init_rwsem(&ps->devsem);
+	ps->discsignr = 0;
+	ps->disctask = current;
+	ps->disccontext = NULL;
+	ps->ifclaimed = 0;
+	wmb();
+	list_add_tail(&ps->list, &dev->filelist);
+	file->private_data = ps;
+ out:
+	unlock_kernel();
+        return ret;
+}
+
+static int usbdev_release(struct inode *inode, struct file *file)
+{
+	struct dev_state *ps = (struct dev_state *)file->private_data;
+	unsigned int i;
+
+	lock_kernel();
+	list_del(&ps->list);
+	INIT_LIST_HEAD(&ps->list);
+	if (ps->dev) {
+		for (i = 0; ps->ifclaimed && i < 8*sizeof(ps->ifclaimed); i++)
+			if (test_bit(i, &ps->ifclaimed))
+				releaseintf(ps, i);
+	}
+	unlock_kernel();
+	destroy_all_async(ps);
+	kfree(ps);
+        return 0;
+}
+
+static int proc_control(struct dev_state *ps, void *arg)
+{
+	struct usb_device *dev = ps->dev;
+	struct usbdevfs_ctrltransfer ctrl;
+	unsigned int tmo;
+	unsigned char *tbuf;
+	int i, ret;
+
+	if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl)))
+		return -EFAULT;
+	switch (ctrl.requesttype & 0x1f) {
+	case USB_RECIP_ENDPOINT:
+		if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0)
+			return ret;
+		if ((ret = checkintf(ps, ret)))
+			return ret;
+		break;
+
+	case USB_RECIP_INTERFACE:
+		if ((ret = findintfif(ps->dev, ctrl.index & 0xff)) < 0)
+			return ret;
+		if ((ret = checkintf(ps, ret)))
+			return ret;
+		break;
+	}
+	if (ctrl.length > PAGE_SIZE)
+		return -EINVAL;
+	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	tmo = (ctrl.timeout * HZ + 999) / 1000;
+	if (ctrl.requesttype & 0x80) {
+		if (ctrl.length && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.length)) {
+			free_page((unsigned long)tbuf);
+			return -EINVAL;
+		}
+		i = my_usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+				       ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
+		if ((i > 0) && ctrl.length) {
+			if (copy_to_user(ctrl.data, tbuf, ctrl.length))
+				return -EFAULT;
+		}
+	} else {
+		if (ctrl.length) {
+			if (copy_from_user(tbuf, ctrl.data, ctrl.length))
+				return -EFAULT;
+		}
+		i = my_usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+				       ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
+	}
+	free_page((unsigned long)tbuf);
+	if (i<0) {
+		printk(KERN_DEBUG "usbdevfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n", 
+		       dev->devnum, ctrl.requesttype, ctrl.request, ctrl.length, i);
+	}
+	return i;
+}
+
+static int proc_bulk(struct dev_state *ps, void *arg)
+{
+	struct usb_device *dev = ps->dev;
+	struct usbdevfs_bulktransfer bulk;
+	unsigned int tmo, len1, pipe;
+	int len2;
+	unsigned char *tbuf;
+	int i, ret;
+
+	if (copy_from_user(&bulk, (void *)arg, sizeof(bulk)))
+		return -EFAULT;
+	if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
+		return ret;
+	if ((ret = checkintf(ps, ret)))
+		return ret;
+	if (bulk.ep & USB_DIR_IN)
+		pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f);
+	else
+		pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f);
+	if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
+		return -EINVAL;
+	len1 = bulk.len;
+	if (len1 > PAGE_SIZE)
+		len1 = PAGE_SIZE;
+	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	tmo = (bulk.timeout * HZ + 999) / 1000;
+	if (bulk.ep & 0x80) {
+		if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
+			free_page((unsigned long)tbuf);
+			return -EINVAL;
+		}
+		i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+		if (!i && len2) {
+			if (copy_to_user(bulk.data, tbuf, len2))
+				return -EFAULT;
+		}
+	} else {
+		if (len1) {
+			if (copy_from_user(tbuf, bulk.data, len1))
+				return -EFAULT;
+		}
+		i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+	}
+	free_page((unsigned long)tbuf);
+	if (i < 0) {
+		printk(KERN_WARNING "usbdevfs: USBDEVFS_BULK failed dev %d ep 0x%x len %u ret %d\n", 
+		       dev->devnum, bulk.ep, bulk.len, i);
+		return i;
+	}
+	return len2;
+}
+
+static int proc_resetep(struct dev_state *ps, void *arg)
+{
+	unsigned int ep;
+	int ret;
+
+	if (get_user(ep, (unsigned int *)arg))
+		return -EFAULT;
+	if ((ret = findintfep(ps->dev, ep)) < 0)
+		return ret;
+	if ((ret = checkintf(ps, ret)))
+		return ret;
+	usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0);
+	return 0;
+}
+
+static int proc_clearhalt(struct dev_state *ps, void *arg)
+{
+	unsigned int ep;
+	int pipe;
+	int ret;
+
+	if (get_user(ep, (unsigned int *)arg))
+		return -EFAULT;
+	if ((ret = findintfep(ps->dev, ep)) < 0)
+		return ret;
+	if ((ret = checkintf(ps, ret)))
+		return ret;
+	if (ep & USB_DIR_IN)
+		pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
+	else
+		pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
+
+	return usb_clear_halt(ps->dev, pipe);
+}
+
+static int proc_getdriver(struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_getdriver gd;
+	struct usb_interface *interface;
+	int ret;
+
+	if (copy_from_user(&gd, arg, sizeof(gd)))
+		return -EFAULT;
+	if ((ret = findintfif(ps->dev, gd.interface)) < 0)
+		return ret;
+	interface = usb_ifnum_to_if(ps->dev, gd.interface);
+	if (!interface)
+		return -EINVAL;
+	if (!interface->driver)
+		return -ENODATA;
+	strcpy(gd.driver, interface->driver->name);
+	if (copy_to_user(arg, &gd, sizeof(gd)))
+		return -EFAULT;
+	return 0;
+}
+
+static int proc_connectinfo(struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_connectinfo ci;
+
+	ci.devnum = ps->dev->devnum;
+	ci.slow = ps->dev->slow;
+	if (copy_to_user(arg, &ci, sizeof(ci)))
+		return -EFAULT;
+	return 0;
+}
+
+static int proc_resetdevice(struct dev_state *ps)
+{
+	int i, ret;
+
+	ret = usb_reset_device(ps->dev);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < ps->dev->actconfig->bNumInterfaces; i++) {
+		struct usb_interface *intf = &ps->dev->actconfig->interface[i];
+
+		/* Don't simulate interfaces we've claimed */
+		if (test_bit(i, &ps->ifclaimed))
+			continue;
+
+		if (intf->driver) {
+			down(&intf->driver->serialize);
+			intf->driver->disconnect(ps->dev, intf->private_data);
+			intf->driver->probe(ps->dev, i);
+			up(&intf->driver->serialize);
+		}
+	}
+
+	return 0;
+}
+
+static int proc_setintf(struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_setinterface setintf;
+	struct usb_interface *interface;
+	int ret;
+
+	if (copy_from_user(&setintf, arg, sizeof(setintf)))
+		return -EFAULT;
+	if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
+		return ret;
+	interface = usb_ifnum_to_if(ps->dev, setintf.interface);
+	if (!interface)
+		return -EINVAL;
+	if (interface->driver) {
+		if ((ret = checkintf(ps, ret)))
+			return ret;
+	}
+	if (usb_set_interface(ps->dev, setintf.interface, setintf.altsetting))
+		return -EINVAL;
+	return 0;
+}
+
+static int proc_setconfig(struct dev_state *ps, void *arg)
+{
+	unsigned int u;
+
+	if (get_user(u, (unsigned int *)arg))
+		return -EFAULT;
+	if (usb_set_configuration(ps->dev, u) < 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int proc_submiturb(struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_urb uurb;
+	struct usbdevfs_iso_packet_desc *isopkt = NULL;
+	struct async *as;
+	unsigned int u, totlen, isofrmlen;
+	int ret;
+
+	if (copy_from_user(&uurb, arg, sizeof(uurb)))
+		return -EFAULT;
+	if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD))
+		return -EINVAL;
+	if (!uurb.buffer)
+		return -EINVAL;
+	if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
+		return -EINVAL;
+	if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
+		return ret;
+	if ((ret = checkintf(ps, ret)))
+		return ret;
+	switch(uurb.type) {
+	case USBDEVFS_URB_TYPE_BULK:
+		uurb.number_of_packets = 0;
+		if (uurb.buffer_length > 16384)
+			return -EINVAL;
+		if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
+			return -EFAULT;
+		break;
+
+	case USBDEVFS_URB_TYPE_ISO:
+		/* arbitrary limit */
+		if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128)
+			return -EINVAL;
+		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets;
+		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
+			return -ENOMEM;
+		if (copy_from_user(isopkt, &((struct usbdevfs_urb *)arg)->iso_frame_desc, isofrmlen)) {
+			kfree(isopkt);
+			return -EFAULT;
+		}
+		for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+			if (isopkt[u].length > 1023) {
+				kfree(isopkt);
+				return -EINVAL;
+			}
+			totlen += isopkt[u].length;
+		}
+		if (totlen > 32768) {
+			kfree(isopkt);
+			return -ENOMEM;
+		}
+		uurb.buffer_length = totlen;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	if (!(as = alloc_async(uurb.number_of_packets))) {
+		if (isopkt)
+			kfree(isopkt);
+		return -ENOMEM;
+	}
+	if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
+		if (isopkt)
+			kfree(isopkt);
+		free_async(as);
+		return -ENOMEM;
+	}
+        as->urb.next = NULL;
+        as->urb.dev = ps->dev;
+        as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
+        as->urb.transfer_flags = uurb.flags;
+	as->urb.transfer_buffer_length = uurb.buffer_length;
+	as->urb.start_frame = uurb.start_frame;
+	as->urb.number_of_packets = uurb.number_of_packets;
+        as->urb.context = as;
+        as->urb.complete = async_completed;
+	for (totlen = u = 0; u < uurb.number_of_packets; u++) {
+		as->urb.iso_frame_desc[u].offset = totlen;
+		as->urb.iso_frame_desc[u].length = isopkt[u].length;
+		totlen += isopkt[u].length;
+	}
+	if (isopkt)
+		kfree(isopkt);
+	as->ps = ps;
+        as->userurb = arg;
+	if (uurb.endpoint & USB_DIR_IN)
+		as->userbuffer = uurb.buffer;
+	else
+		as->userbuffer = NULL;
+	as->signr = uurb.signr;
+	as->task = current;
+	if (!(uurb.endpoint & USB_DIR_IN)) {
+		if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
+			free_async(as);
+			return -EFAULT;
+		}
+	}
+        async_newpending(as);
+        if ((ret = usb_submit_urb(&as->urb))) {
+		printk(KERN_DEBUG "usbdevfs: usb_submit_urb returned %d\n", ret);
+                async_removepending(as);
+                free_async(as);
+                return ret;
+        }
+        return 0;
+}
+
+static int proc_unlinkurb(struct dev_state *ps, void *arg)
+{
+	struct async *as;
+
+	as = async_getpending(ps, arg);
+	if (!as)
+		return -EINVAL;
+	usb_unlink_urb(&as->urb);
+	return 0;
+}
+
+static int processcompl(struct async *as)
+{
+	unsigned int i;
+
+	if (as->userbuffer)
+		if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length))
+			return -EFAULT;
+	if (put_user(as->urb.status,
+		     &((struct usbdevfs_urb *)as->userurb)->status))
+		return -EFAULT;
+	if (put_user(as->urb.actual_length,
+		     &((struct usbdevfs_urb *)as->userurb)->actual_length))
+		return -EFAULT;
+	if (put_user(as->urb.error_count,
+		     &((struct usbdevfs_urb *)as->userurb)->error_count))
+		return -EFAULT;
+	if (!(usb_pipeisoc(as->urb.pipe)))
+		return 0;
+	for (i = 0; i < as->urb.number_of_packets; i++) {
+		if (put_user(as->urb.iso_frame_desc[i].actual_length, 
+			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length))
+			return -EFAULT;
+		if (put_user(as->urb.iso_frame_desc[i].status, 
+			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static int proc_reapurb(struct dev_state *ps, void *arg)
+{
+        DECLARE_WAITQUEUE(wait, current);
+	struct async *as = NULL;
+	void *addr;
+	int ret;
+
+	add_wait_queue(&ps->wait, &wait);
+	while (ps->dev) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		if ((as = async_getcompleted(ps)))
+			break;
+		if (signal_pending(current))
+			break;
+		up_read(&ps->devsem);
+		schedule();
+		down_read(&ps->devsem);
+	}
+	remove_wait_queue(&ps->wait, &wait);
+	set_current_state(TASK_RUNNING);
+	if (as) {
+		ret = processcompl(as);
+		addr = as->userurb;
+		free_async(as);
+		if (ret)
+			return ret;
+		if (put_user(addr, (void **)arg))
+			return -EFAULT;
+		return 0;
+	}
+	if (signal_pending(current))
+		return -EINTR;
+	return -EIO;
+}
+
+static int proc_reapurbnonblock(struct dev_state *ps, void *arg)
+{
+	struct async *as;
+	void *addr;
+	int ret;
+
+	if (!(as = async_getcompleted(ps)))
+		return -EAGAIN;
+	ret = processcompl(as);
+	addr = as->userurb;
+	free_async(as);
+	if (ret)
+		return ret;
+	if (put_user(addr, (void **)arg))
+		return -EFAULT;
+	return 0;
+}
+
+static int proc_disconnectsignal(struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_disconnectsignal ds;
+
+	if (copy_from_user(&ds, arg, sizeof(ds)))
+		return -EFAULT;
+	if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX))
+		return -EINVAL;
+	ps->discsignr = ds.signr;
+	ps->disccontext = ds.context;
+	return 0;
+}
+
+static int proc_claiminterface(struct dev_state *ps, void *arg)
+{
+	unsigned int intf;
+	int ret;
+
+	if (get_user(intf, (unsigned int *)arg))
+		return -EFAULT;
+	if ((ret = findintfif(ps->dev, intf)) < 0)
+		return ret;
+	return claimintf(ps, ret);
+}
+
+static int proc_releaseinterface(struct dev_state *ps, void *arg)
+{
+	unsigned int intf;
+	int ret;
+
+	if (get_user(intf, (unsigned int *)arg))
+		return -EFAULT;
+	if ((ret = findintfif(ps->dev, intf)) < 0)
+		return ret;
+	return releaseintf(ps, intf);
+}
+
+static int proc_ioctl (struct dev_state *ps, void *arg)
+{
+	struct usbdevfs_ioctl	ctrl;
+	int			size;
+	void			*buf = 0;
+	int			retval = 0;
+
+	/* get input parameters and alloc buffer */
+	if (copy_from_user (&ctrl, (void *) arg, sizeof (ctrl)))
+		return -EFAULT;
+	if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
+		if ((buf = kmalloc (size, GFP_KERNEL)) == 0)
+			return -ENOMEM;
+		if ((_IOC_DIR (ctrl.ioctl_code) & _IOC_WRITE) != 0
+				&& copy_from_user (buf, ctrl.data, size) != 0) {
+			kfree (buf);
+			return -EFAULT;
+		} else
+			memset (arg, 0, size);
+	}
+
+	/* ioctl to device */
+	if (ctrl.ifno < 0) {
+		switch (ctrl.ioctl_code) {
+		/* access/release token for issuing control messages
+		 * ask a particular driver to bind/unbind, ... etc
+		 */
+		}
+		retval = -ENOSYS;
+
+	/* ioctl to the driver which has claimed a given interface */
+	} else {
+		struct usb_interface	*ifp = 0;
+		if (!ps->dev)
+			retval = -ENODEV;
+		else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces)
+			retval = -EINVAL;
+		else {
+			if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+				retval = -EINVAL;
+			else if (ifp->driver == 0 || ifp->driver->ioctl == 0)
+				retval = -ENOSYS;
+		}
+		if (retval == 0)
+			/* ifno might usefully be passed ... */
+			retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
+			/* size = min (size, retval)? */
+	}
+
+	/* cleanup and return */
+	if (retval >= 0
+			&& (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0
+			&& size > 0
+			&& copy_to_user (ctrl.data, buf, size) != 0)
+		retval = -EFAULT;
+	if (buf != 0)
+		kfree (buf);
+	return retval;
+}
+
+static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct dev_state *ps = (struct dev_state *)file->private_data;
+	int ret = -ENOIOCTLCMD;
+
+	if (!(file->f_mode & FMODE_WRITE))
+		return -EPERM;
+	down_read(&ps->devsem);
+	if (!ps->dev) {
+		up_read(&ps->devsem);
+		return -ENODEV;
+	}
+	switch (cmd) {
+	case USBDEVFS_CONTROL:
+		ret = proc_control(ps, (void *)arg);
+		if (ret >= 0)
+			inode->i_mtime = CURRENT_TIME;
+		break;
+
+	case USBDEVFS_BULK:
+		ret = proc_bulk(ps, (void *)arg);
+		if (ret >= 0)
+			inode->i_mtime = CURRENT_TIME;
+		break;
+
+	case USBDEVFS_RESETEP:
+		ret = proc_resetep(ps, (void *)arg);
+		if (ret >= 0)
+			inode->i_mtime = CURRENT_TIME;
+		break;
+
+	case USBDEVFS_RESET:
+		ret = proc_resetdevice(ps);
+		break;
+
+	case USBDEVFS_CLEAR_HALT:
+		ret = proc_clearhalt(ps, (void *)arg);
+		if (ret >= 0)
+			inode->i_mtime = CURRENT_TIME;
+		break;
+
+	case USBDEVFS_GETDRIVER:
+		ret = proc_getdriver(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_CONNECTINFO:
+		ret = proc_connectinfo(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_SETINTERFACE:
+		ret = proc_setintf(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_SETCONFIGURATION:
+		ret = proc_setconfig(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_SUBMITURB:
+		ret = proc_submiturb(ps, (void *)arg);
+		if (ret >= 0)
+			inode->i_mtime = CURRENT_TIME;
+		break;
+
+	case USBDEVFS_DISCARDURB:
+		ret = proc_unlinkurb(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_REAPURB:
+		ret = proc_reapurb(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_REAPURBNDELAY:
+		ret = proc_reapurbnonblock(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_DISCSIGNAL:
+		ret = proc_disconnectsignal(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_CLAIMINTERFACE:
+		ret = proc_claiminterface(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_RELEASEINTERFACE:
+		ret = proc_releaseinterface(ps, (void *)arg);
+		break;
+
+	case USBDEVFS_IOCTL:
+		ret = proc_ioctl(ps, (void *) arg);
+		break;
+	}
+	up_read(&ps->devsem);
+	if (ret >= 0)
+		inode->i_atime = CURRENT_TIME;
+	return ret;
+}
+
+/* No kernel lock - fine */
+static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct dev_state *ps = (struct dev_state *)file->private_data;
+        unsigned int mask = 0;
+
+	poll_wait(file, &ps->wait, wait);
+	if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
+		mask |= POLLOUT | POLLWRNORM;
+	if (!ps->dev)
+		mask |= POLLERR | POLLHUP;
+	return mask;
+}
+
+struct file_operations usbdevfs_device_file_operations = {
+	llseek:		usbdev_lseek,
+	read:		usbdev_read,
+	poll:		usbdev_poll,
+	ioctl:		usbdev_ioctl,
+	open:		usbdev_open,
+	release:	usbdev_release,
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/drivers.c linux.18p8/drivers/usb/drivers.c
--- linux.vanilla/drivers/usb/drivers.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/drivers.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,119 @@
+/*
+ * drivers.c
+ * (C) Copyright 1999 Randy Dunlap.
+ * (C) Copyright 1999, 2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
+ * (C) Copyright 1999 Deti Fliegl (new USB architecture)
+ *
+ * $id$
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *************************************************************
+ *
+ * 1999-12-16: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *   Converted the whole proc stuff to real
+ *   read methods. Now not the whole device list needs to fit
+ *   into one page, only the device list for one bus.
+ *   Added a poll method to /proc/bus/usb/devices, to wake
+ *   up an eventual usbd
+ * 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *   Turned into its own filesystem
+ *
+ * $Id: drivers.c,v 1.3 2000/01/11 13:58:24 tom Exp $
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <asm/uaccess.h>
+
+/*****************************************************************/
+
+/*
+ * Dump usb_driver_list.
+ *
+ * We now walk the list of registered USB drivers.
+ */
+static ssize_t usb_driver_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+	struct list_head *tmp = usb_driver_list.next;
+	char *page, *start, *end;
+	ssize_t ret = 0;
+	unsigned int pos, len;
+
+	if (*ppos < 0)
+		return -EINVAL;
+	if (nbytes <= 0)
+		return 0;
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EFAULT;
+        if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+                return -ENOMEM;
+	start = page;
+	end = page + (PAGE_SIZE - 100);
+	pos = *ppos;
+	for (; tmp != &usb_driver_list; tmp = tmp->next) {
+		struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
+		int minor = driver->fops ? driver->minor : -1;
+		if (minor == -1)
+			start += sprintf (start, "         %s\n", driver->name);
+		else
+			start += sprintf (start, "%3d-%3d: %s\n", minor, minor + 15, driver->name);
+		if (start > end) {
+			start += sprintf(start, "(truncated)\n");
+			break;
+		}
+	}
+	if (start == page)
+		start += sprintf(start, "(none)\n");
+	len = start - page;
+	if (len > pos) {
+		len -= pos;
+		if (len > nbytes)
+			len = nbytes;
+		ret = len;
+		if (copy_to_user(buf, page + pos, len))
+			ret = -EFAULT;
+		else
+			*ppos += len;
+	}
+	free_page((unsigned long)page);
+	return ret;
+}
+
+static loff_t usb_driver_lseek(struct file * file, loff_t offset, int orig)
+{
+	switch (orig) {
+	case 0:
+		file->f_pos = offset;
+		return file->f_pos;
+
+	case 1:
+		file->f_pos += offset;
+		return file->f_pos;
+
+	case 2:
+		return -EINVAL;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+struct file_operations usbdevfs_drivers_fops = {
+	llseek:		usb_driver_lseek,
+	read:		usb_driver_read,
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/dsbr100.c linux.18p8/drivers/usb/dsbr100.c
--- linux.vanilla/drivers/usb/dsbr100.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/dsbr100.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,354 @@
+/* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
+ into both the USB and an analog audio input, so this thing
+ only deals with initialisation and frequency setting, the
+ audio data has to be handled by a sound driver.
+
+ Major issue: I can't find out where the device reports the signal
+ strength, and indeed the windows software appearantly just looks
+ at the stereo indicator as well.  So, scanning will only find
+ stereo stations.  Sad, but I can't help it.
+
+ Also, the windows program sends oodles of messages over to the
+ device, and I couldn't figure out their meaning.  My suspicion
+ is that they don't have any:-)
+
+ You might find some interesting stuff about this module at
+ http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
+
+ Copyright (c) 2000 Markus Demleitner <msdemlei@tucana.harvard.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 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
+
+ History:
+
+ Version 0.23:
+ 	Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
+
+ Version 0.22:
+ 	Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, 
+	thanks to Mike Cox for pointing the problem out.
+
+ Version 0.21:
+ 	Markus: Minor cleanup, warnings if something goes wrong, lame attempt
+	to adhere to Documentation/CodingStyle
+
+ Version 0.2: 
+ 	Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
+	Markus: Copyright clarification
+
+ Version 0.01: Markus: initial release
+
+*/
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/videodev.h>
+#include <linux/usb.h>
+
+#define DSB100_VENDOR 0x04b4
+#define DSB100_PRODUCT 0x1002
+
+#define TB_LEN 16
+
+static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum);
+static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr);
+static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd, 
+	void *arg);
+static int usb_dsbr100_open(struct video_device *dev, int flags);
+static void usb_dsbr100_close(struct video_device *dev);
+
+
+typedef struct
+{	struct urb readurb,writeurb;
+	struct usb_device *dev;
+	unsigned char transfer_buffer[TB_LEN];
+	int curfreq;
+	int stereo;
+	int ifnum;
+} usb_dsbr100;
+
+
+static struct video_device usb_dsbr100_radio=
+{
+	"D-Link DSB R-100 USB radio",
+	VID_TYPE_TUNER,
+	VID_HARDWARE_AZTECH,
+	usb_dsbr100_open,
+	usb_dsbr100_close,
+	NULL,	/* Can't read  (no capture ability) */
+	NULL,	/* Can't write */
+	NULL,	/* No poll */
+	usb_dsbr100_ioctl,
+	NULL,
+	NULL
+};
+
+static int users = 0;
+
+static struct usb_driver usb_dsbr100_driver = {
+	name:		"dsbr100",
+	probe:		usb_dsbr100_probe,
+	disconnect:	usb_dsbr100_disconnect,
+	driver_list: {NULL,NULL},
+	fops: NULL,
+	minor: 0
+};
+
+
+static int dsbr100_start(usb_dsbr100 *radio)
+{
+	if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
+		0x00, 0xC0, 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
+	    usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
+		0x02, 0xC0, 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
+		return -1;
+	return (radio->transfer_buffer)[0];
+}
+
+
+static int dsbr100_stop(usb_dsbr100 *radio)
+{
+	if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
+		0x00, 0xC0, 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
+	    usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
+		0x02, 0xC0, 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
+		return -1;
+	return (radio->transfer_buffer)[0];
+}
+
+
+static int dsbr100_setfreq(usb_dsbr100 *radio, int freq)
+{
+	freq = (freq*80)/16+856;
+	if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
+		0x01, 0xC0, (freq&0xff00)>>8, freq&0xff, 
+		radio->transfer_buffer, 8, 300)<0
+	 || usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
+		0x00, 0xC0, 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
+	    usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
+		0x00, 0xC0, 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
+		radio->stereo = -1;
+		return -1;
+	}
+	radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
+	return (radio->transfer_buffer)[0];
+}
+
+static void dsbr100_getstat(usb_dsbr100 *radio)
+{
+	if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
+		0x00, 0xC0, 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
+		radio->stereo = -1;
+	else
+		radio->stereo = ! (radio->transfer_buffer[0]&0x01);
+}
+
+
+static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	usb_dsbr100 *radio;
+
+	if (dev->descriptor.idVendor!=DSB100_VENDOR ||
+			dev->descriptor.idProduct!=DSB100_PRODUCT)
+		return NULL;
+	if (!(radio = kmalloc(sizeof(usb_dsbr100),GFP_KERNEL)))
+		return NULL;
+	usb_dsbr100_radio.priv = radio;
+	radio->dev = dev;
+	radio->ifnum = ifnum;
+	radio->curfreq = 1454;
+	return (void*)radio;
+}
+
+static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr)
+{
+	usb_dsbr100 *radio=ptr;
+
+	if (users)
+		return;
+	kfree(radio);
+	usb_dsbr100_radio.priv = NULL;
+}
+
+static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd, 
+	void *arg)
+{
+	usb_dsbr100 *radio=dev->priv;
+
+	if (!radio)
+		return -EINVAL;
+
+	switch(cmd)
+	{
+		case VIDIOCGCAP: {
+			struct video_capability v;
+			v.type=VID_TYPE_TUNER;
+			v.channels=1;
+			v.audios=1;
+			/* No we don't do pictures */
+			v.maxwidth=0;
+			v.maxheight=0;
+			v.minwidth=0;
+			v.minheight=0;
+			strcpy(v.name, "D-Link R-100 USB Radio");
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCGTUNER: {
+			struct video_tuner v;
+			dsbr100_getstat(radio);
+			if(copy_from_user(&v, arg,sizeof(v))!=0) 
+				return -EFAULT;
+			if(v.tuner)	/* Only 1 tuner */ 
+				return -EINVAL;
+			v.rangelow = 87*16;
+			v.rangehigh = 108*16;
+			v.flags = VIDEO_TUNER_LOW;
+			v.mode = VIDEO_MODE_AUTO;
+			v.signal = radio->stereo*0x7000;
+				/* Don't know how to get signal strength */
+			v.flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
+			strcpy(v.name, "DSB R-100");
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSTUNER: {
+			struct video_tuner v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.tuner!=0)
+				return -EINVAL;
+			/* Only 1 tuner so no setting needed ! */
+			return 0;
+		}
+		case VIDIOCGFREQ: 
+			if (radio->curfreq==-1)
+				return -EINVAL;
+			if(copy_to_user(arg, &(radio->curfreq), 
+				sizeof(radio->curfreq)))
+				return -EFAULT;
+			return 0;
+
+		case VIDIOCSFREQ:
+			if(copy_from_user(&(radio->curfreq), arg,
+				sizeof(radio->curfreq)))
+				return -EFAULT;
+			if (dsbr100_setfreq(radio, radio->curfreq)==-1)
+				warn("set frequency failed");
+			return 0;
+
+		case VIDIOCGAUDIO: {
+			struct video_audio v;
+			memset(&v,0, sizeof(v));
+			v.flags|=VIDEO_AUDIO_MUTABLE;
+			v.mode=VIDEO_SOUND_STEREO;
+			v.volume=1;
+			v.step=1;
+			strcpy(v.name, "Radio");
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;			
+		}
+		case VIDIOCSAUDIO: {
+			struct video_audio v;
+			if(copy_from_user(&v, arg, sizeof(v))) 
+				return -EFAULT;	
+			if(v.audio) 
+				return -EINVAL;
+
+			if(v.flags&VIDEO_AUDIO_MUTE) {
+				if (dsbr100_stop(radio)==-1)
+					warn("radio did not respond properly");
+			}
+			else
+				if (dsbr100_start(radio)==-1)
+					warn("radio did not respond properly");
+			return 0;
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+
+static int usb_dsbr100_open(struct video_device *dev, int flags)
+{
+	usb_dsbr100 *radio=dev->priv;
+
+	if (! radio) {
+		warn("radio not initialised");
+		return -EAGAIN;
+	}
+	if(users)
+	{
+		warn("radio in use");
+		return -EBUSY;
+	}
+	users++;
+	MOD_INC_USE_COUNT;
+	if (dsbr100_start(radio)<0)
+		warn("radio did not start up properly");
+	dsbr100_setfreq(radio,radio->curfreq);
+	return 0;
+}
+
+static void usb_dsbr100_close(struct video_device *dev)
+{
+	usb_dsbr100 *radio=dev->priv;
+
+	if (!radio)
+		return;
+	users--;
+	dsbr100_stop(radio);
+	MOD_DEC_USE_COUNT;
+}
+
+int __init dsbr100_init(void)
+{
+	usb_dsbr100_radio.priv = NULL;
+	usb_register(&usb_dsbr100_driver);
+	if (video_register_device(&usb_dsbr100_radio,VFL_TYPE_RADIO)==-1) {	
+		warn("couldn't register video device");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int __init init_module(void)
+{
+	return dsbr100_init();
+}
+
+void cleanup_module(void)
+{
+	usb_dsbr100 *radio=usb_dsbr100_radio.priv;
+
+	if (radio)
+		dsbr100_stop(radio);
+	video_unregister_device(&usb_dsbr100_radio);
+	usb_deregister(&usb_dsbr100_driver);
+}
+
+/*
+vi: ts=8
+Sigh.  Of course, I am one of the ts=2 heretics, but Linus' wish is
+my command.
+*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/evdev.c linux.18p8/drivers/usb/evdev.c
--- linux.vanilla/drivers/usb/evdev.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/evdev.c	Fri Sep  1 14:40:40 2000
@@ -0,0 +1,349 @@
+/*
+ * $Id: evdev.c,v 1.8 2000/05/29 09:01:52 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Event char devices, giving access to raw input device events.
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#define EVDEV_MINOR_BASE	64
+#define EVDEV_MINORS		32
+#define EVDEV_BUFFER_SIZE	64
+
+#include <linux/poll.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/kcomp.h>
+
+struct evdev {
+	int used;
+	int open;
+	int minor;
+	struct input_handle handle;
+	wait_queue_head_t wait;
+	devfs_handle_t devfs;
+	struct evdev_list *list;
+};
+
+struct evdev_list {
+	struct input_event buffer[EVDEV_BUFFER_SIZE];
+	int head;
+	int tail;
+	struct fasync_struct *fasync;
+	struct evdev *evdev;
+	struct evdev_list *next;
+};
+
+static struct evdev *evdev_table[EVDEV_MINORS] = { NULL, /* ... */ };
+
+static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+{
+	struct evdev *evdev = handle->private;
+	struct evdev_list *list = evdev->list;
+
+	while (list) {
+
+		get_fast_time(&list->buffer[list->head].time);
+		list->buffer[list->head].type = type;
+		list->buffer[list->head].code = code;
+		list->buffer[list->head].value = value;
+		list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+		
+		kill_fasync(list->fasync, SIGIO);
+
+		list = list->next;
+	}
+
+	wake_up_interruptible(&evdev->wait);
+}
+
+static int evdev_fasync(int fd, struct file *file, int on)
+{
+	int retval;
+	struct evdev_list *list = file->private_data;
+	retval = fasync_helper(fd, file, on, &list->fasync);
+	return retval < 0 ? retval : 0;
+}
+
+static int evdev_release(struct inode * inode, struct file * file)
+{
+	struct evdev_list *list = file->private_data;
+	struct evdev_list **listptr = &list->evdev->list;
+
+	evdev_fasync(-1, file, 0);
+
+	while (*listptr && (*listptr != list))
+		listptr = &((*listptr)->next);
+	*listptr = (*listptr)->next;
+
+	if (!--list->evdev->open)
+		input_close_device(&list->evdev->handle);	
+	
+	if (!--list->evdev->used) {
+		input_unregister_minor(list->evdev->devfs);
+		evdev_table[list->evdev->minor] = NULL;
+		kfree(list->evdev);
+	}
+
+	kfree(list);
+
+	return 0;
+}
+
+static int evdev_open(struct inode * inode, struct file * file)
+{
+	struct evdev_list *list;
+	int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE;
+
+	if (i > EVDEV_MINORS || !evdev_table[i])
+		return -ENODEV;
+
+	if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+	memset(list, 0, sizeof(struct evdev_list));
+
+	list->evdev = evdev_table[i];
+	list->next = evdev_table[i]->list;
+	evdev_table[i]->list = list;
+
+	file->private_data = list;
+
+	list->evdev->used++;
+
+	if (!list->evdev->open++)
+		input_open_device(&list->evdev->handle);	
+
+	return 0;
+}
+
+static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct evdev_list *list = file->private_data;
+	int retval = 0;
+
+	if (list->head == list->tail) {
+
+		add_wait_queue(&list->evdev->wait, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+
+		while (list->head == list->tail) {
+
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+
+			schedule();
+		}
+
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&list->evdev->wait, &wait);
+	}
+
+	if (retval)
+		return retval;
+
+	while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
+		if (copy_to_user(buffer + retval, list->buffer + list->tail,
+			 sizeof(struct input_event))) return -EFAULT;
+		list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
+		retval += sizeof(struct input_event);
+	}
+
+	return retval;	
+}
+
+/* No kernel lock - fine */
+static unsigned int evdev_poll(struct file *file, poll_table *wait)
+{
+	struct evdev_list *list = file->private_data;
+	poll_wait(file, &list->evdev->wait, wait);
+	if (list->head != list->tail)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct evdev_list *list = file->private_data;
+	struct evdev *evdev = list->evdev;
+	struct input_dev *dev = evdev->handle.dev;
+	int retval;
+
+	switch (cmd) {
+
+		case EVIOCGVERSION:
+			return put_user(EV_VERSION, (int *) arg);
+
+		case EVIOCGID:
+			if ((retval = put_user(dev->idbus,     ((short *) arg) + 0))) return retval;
+			if ((retval = put_user(dev->idvendor,  ((short *) arg) + 1))) return retval;
+			if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval;
+			if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval;
+			return 0;
+
+		default:
+
+			if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
+				return -EINVAL;
+
+			if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+
+				long *bits;
+				int len;
+
+				switch (_IOC_NR(cmd) & EV_MAX) {
+					case      0: bits = dev->evbit;  len = EV_MAX;  break;
+					case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+					case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+					case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+					case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+					case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+					default: return -EINVAL;
+				}
+				len = NBITS(len) * sizeof(long);
+				if (len > _IOC_SIZE(cmd)) {
+					printk(KERN_WARNING "evdev.c: Truncating bitfield length from %d to %d\n",
+						len, _IOC_SIZE(cmd));
+					len = _IOC_SIZE(cmd);
+				}
+				return copy_to_user((char *) arg, bits, len) ? -EFAULT : len;
+			}
+
+			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+				int len;
+				if (!dev->name) return 0;
+				len = strlen(dev->name) + 1;
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+				return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len;
+			}
+
+			if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+				int t = _IOC_NR(cmd) & ABS_MAX;
+
+				if ((retval = put_user(dev->abs[t],     ((int *) arg) + 0))) return retval;
+				if ((retval = put_user(dev->absmin[t],  ((int *) arg) + 1))) return retval;
+				if ((retval = put_user(dev->absmax[t],  ((int *) arg) + 2))) return retval;
+				if ((retval = put_user(dev->absfuzz[t], ((int *) arg) + 3))) return retval;
+				if ((retval = put_user(dev->absflat[t], ((int *) arg) + 4))) return retval;
+
+				return 0;
+			}
+	}
+	return -EINVAL;
+}
+
+static struct file_operations evdev_fops = {
+	read:		evdev_read,
+	write:		evdev_write,
+	poll:		evdev_poll,
+	open:		evdev_open,
+	release:	evdev_release,
+	ioctl:		evdev_ioctl,
+	fasync:		evdev_fasync,
+};
+
+static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev)
+{
+	struct evdev *evdev;
+	int minor;
+
+	for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
+	if (evdev_table[minor]) {
+		printk(KERN_ERR "evdev: no more free evdev devices\n");
+		return NULL;
+	}
+
+	if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
+		return NULL;
+	memset(evdev, 0, sizeof(struct evdev));
+
+	init_waitqueue_head(&evdev->wait);
+
+	evdev->minor = minor;
+	evdev_table[minor] = evdev;
+
+	evdev->handle.dev = dev;
+	evdev->handle.handler = handler;
+	evdev->handle.private = evdev;
+
+	evdev->used = 1;
+
+	evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE);
+
+	printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number);
+
+	return &evdev->handle;
+}
+
+static void evdev_disconnect(struct input_handle *handle)
+{
+	struct evdev *evdev = handle->private;
+
+	if (evdev->open)
+		input_close_device(handle);
+
+	if (!--evdev->used) {
+		input_unregister_minor(evdev->devfs);
+		evdev_table[evdev->minor] = NULL;
+		kfree(evdev);
+	}
+}
+	
+static struct input_handler evdev_handler = {
+	event:		evdev_event,
+	connect:	evdev_connect,
+	disconnect:	evdev_disconnect,
+	fops:		&evdev_fops,
+	minor:		EVDEV_MINOR_BASE,
+};
+
+static int __init evdev_init(void)
+{
+	input_register_handler(&evdev_handler);
+	return 0;
+}
+
+static void __exit evdev_exit(void)
+{
+	input_unregister_handler(&evdev_handler);
+}
+
+module_init(evdev_init);
+module_exit(evdev_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hid-debug.h linux.18p8/drivers/usb/hid-debug.h
--- linux.vanilla/drivers/usb/hid-debug.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/hid-debug.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,235 @@
+/*
+ * $Id: hid-debug.h,v 1.2 2000/05/29 10:54:53 vojtech Exp $
+ *
+ *  (c) 1999 Andreas Gal	<gal@cs.uni-magdeburg.de>
+ *  (c) 2000 Vojtech Pavlik	<vojtech@suse.cz>
+ *
+ *  Some debug stuff for the HID parser.
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+struct hid_usage_entry {
+	unsigned  page;
+	unsigned  usage;
+	char     *description;
+};
+
+static struct hid_usage_entry hid_usage_table[] = {
+  {  1,      0, "GenericDesktop" },
+    {0, 0x01, "Pointer"},
+    {0, 0x02, "Mouse"},
+    {0, 0x04, "Joystick"},
+    {0, 0x05, "GamePad"},
+    {0, 0x06, "Keyboard"},
+    {0, 0x07, "Keypad"},
+    {0, 0x08, "MultiAxis"},
+      {0, 0x30, "X"},
+      {0, 0x31, "Y"},
+      {0, 0x32, "Z"},
+      {0, 0x33, "Rx"},
+      {0, 0x34, "Ry"},
+      {0, 0x35, "Rz"},
+      {0, 0x36, "Slider"},
+      {0, 0x37, "Dial"},
+      {0, 0x38, "Wheel"},
+      {0, 0x39, "HatSwitch"},
+    {0, 0x3a, "CountedBuffer"},
+      {0, 0x3b, "ByteCount"},
+      {0, 0x3c, "MotionWakeup"},
+      {0, 0x3d, "Start"},
+      {0, 0x3e, "Select"},
+      {0, 0x40, "Vx"},
+      {0, 0x41, "Vy"},
+      {0, 0x42, "Vz"},
+      {0, 0x43, "Vbrx"},
+      {0, 0x44, "Vbry"},
+      {0, 0x45, "Vbrz"},
+      {0, 0x46, "Vno"},
+    {0, 0x80, "SystemControl"}, 
+      {0, 0x81, "SystemPowerDown"},
+      {0, 0x82, "SystemSleep"},
+      {0, 0x83, "SystemWakeUp"},
+      {0, 0x84, "SystemContextMenu"},
+      {0, 0x85, "SystemMainMenu"},
+      {0, 0x86, "SystemAppMenu"},
+      {0, 0x87, "SystemMenuHelp"},
+      {0, 0x88, "SystemMenuExit"},
+      {0, 0x89, "SystemMenuSelect"},
+      {0, 0x8a, "SystemMenuRight"},
+      {0, 0x8b, "SystemMenuLeft"},
+      {0, 0x8c, "SystemMenuUp"},
+      {0, 0x8d, "SystemMenuDown"},
+    {0, 0x90, "D-padUp"},
+    {0, 0x91, "D-padDown"},
+    {0, 0x92, "D-padRight"},
+    {0, 0x93, "D-padLeft"},
+  {  7, 0, "Keyboard" },
+  {  8, 0, "LED" },
+  {  9, 0, "Button" },
+  { 12, 0, "Hotkey" },
+  { 13, 0, "Digitizers" },
+    {0, 0x01, "Digitizer"},
+    {0, 0x02, "Pen"},
+    {0, 0x03, "LightPen"},
+    {0, 0x04, "TouchScreen"},
+    {0, 0x05, "TouchPad"},
+    {0, 0x20, "Stylus"},
+    {0, 0x21, "Puck"},
+    {0, 0x22, "Finger"},
+    {0, 0x30, "TipPressure"},
+    {0, 0x31, "BarrelPressure"},
+    {0, 0x32, "InRange"},
+    {0, 0x33, "Touch"},
+    {0, 0x34, "UnTouch"},
+    {0, 0x35, "Tap"},
+    {0, 0x39, "TabletFunctionKey"},
+    {0, 0x3a, "ProgramChangeKey"},
+    {0, 0x3c, "Invert"},
+    {0, 0x42, "TipSwitch"},
+    {0, 0x43, "SecondaryTipSwitch"},
+    {0, 0x44, "BarrelSwitch"},
+    {0, 0x45, "Eraser"},
+    {0, 0x46, "TabletPick"},
+  { 15, 0, "PhysicalInterfaceDevice" },
+  { 0, 0, NULL }
+};
+
+static void resolv_usage_page(unsigned page) {
+	struct hid_usage_entry *p;
+
+	for (p = hid_usage_table; p->description; p++)
+		if (p->page == page) {
+			printk("%s", p->description);
+			return;
+		}
+	printk("%04x", page);
+}
+
+static void resolv_usage(unsigned usage) {
+	struct hid_usage_entry *p;
+
+	resolv_usage_page(usage >> 16);
+	printk(".");
+	for (p = hid_usage_table; p->description; p++)
+		if (p->page == (usage >> 16)) {
+			for(++p; p->description && p->page == 0; p++)
+				if (p->usage == (usage & 0xffff)) {
+					printk("%s", p->description);
+					return;
+				}
+			break;
+		}
+	printk("%04x", usage & 0xffff);
+}
+
+__inline__ static void tab(int n) {
+	while (n--) printk(" ");
+}
+
+static void hid_dump_field(struct hid_field *field, int n) {
+	int j;
+	
+	if (field->physical) {
+		tab(n);
+		printk("Physical(");
+		resolv_usage(field->physical); printk(")\n");
+	}
+	if (field->logical) {
+		tab(n);
+		printk("Logical(");
+		resolv_usage(field->logical); printk(")\n");
+	}
+	tab(n); printk("Usage(%d)\n", field->maxusage);
+	for (j = 0; j < field->maxusage; j++) {
+		tab(n+2);resolv_usage(field->usage[j].hid); printk("\n");
+	}
+	if (field->logical_minimum != field->logical_maximum) {
+		tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
+		tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
+	}
+	if (field->physical_minimum != field->physical_maximum) {
+		tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
+		tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
+	}
+	if (field->unit_exponent) {
+		tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
+	}
+	if (field->unit) {
+		tab(n); printk("Unit(%u)\n", field->unit);
+	}
+	tab(n); printk("Report Size(%u)\n", field->report_size);
+	tab(n); printk("Report Count(%u)\n", field->report_count);
+	tab(n); printk("Report Offset(%u)\n", field->report_offset);
+
+	tab(n); printk("Flags( ");
+	j = field->flags;
+	printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
+	printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
+	printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
+	printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
+	printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
+	printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+	printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
+	printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
+	printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
+	printk(")\n");
+}
+
+void hid_dump_device(struct hid_device *device) {
+	struct hid_report_enum *report_enum;
+	struct hid_report *report;
+	struct list_head *list;
+	unsigned i,k;
+	static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+	
+	printk("Application(");
+	resolv_usage(device->application);
+	printk(")\n");
+
+	for (i = 0; i < HID_REPORT_TYPES; i++) {
+		report_enum = device->report_enum + i;
+		list = report_enum->report_list.next;
+		while (list != &report_enum->report_list) {
+			report = (struct hid_report *) list;
+			tab(2);
+			printk("%s", table[i]);
+			if (report->id)
+				printk("(%d)", report->id);
+			printk("[%s]", table[report->type]);
+			printk("\n");
+			for (k = 0; k < report->maxfield; k++) {
+				tab(4);
+				printk("Field(%d)\n", k);
+				hid_dump_field(report->field[k], 6);
+			}
+			list = list->next;
+		}
+	}
+}
+
+void hid_dump_input(struct hid_usage *usage, __s32 value) {
+	printk("hidd: input ");
+	resolv_usage(usage->hid);
+	printk(" = %d\n", value);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hid.c linux.18p8/drivers/usb/hid.c
--- linux.vanilla/drivers/usb/hid.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/hid.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,1526 @@
+/*
+ * $Id: hid.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000 Vojtech Pavlik
+ *
+ *  USB HID support for the Linux input drivers
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#undef DEBUG
+#undef DEBUG_DATA
+#include <linux/usb.h>
+
+#include <asm/unaligned.h>
+
+#include "hid.h"
+
+#ifdef DEBUG
+#include "hid-debug.h"
+#else
+#define hid_dump_input(a,b)	do { } while (0)
+#define hid_dump_device(c)	do { } while (0)
+#endif
+
+#define unk	KEY_UNKNOWN
+
+static unsigned char hid_keyboard[256] = {
+	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+	 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+	 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95,
+	120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,
+	115,114,unk,unk,unk,unk,unk,124,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+	150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
+};
+
+static struct {
+	__s32 x;
+	__s32 y;
+}  hid_hat_to_axis[] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}, { 0, 0}};
+
+static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
+				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
+
+/*
+ * Register a new report for a device.
+ */
+
+static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
+{
+	struct hid_report_enum *report_enum = device->report_enum + type;
+	struct hid_report *report;
+	 
+	if (report_enum->report_id_hash[id])
+		return report_enum->report_id_hash[id];
+
+	if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))
+		return NULL;
+	memset(report, 0, sizeof(struct hid_report));
+
+	if (id != 0) report_enum->numbered = 1;
+
+	report->id = id;
+	report->type = type;
+	report->size = 0;
+	report->device = device;
+	report_enum->report_id_hash[id] = report;
+
+	list_add_tail(&report->list, &report_enum->report_list);
+
+	return report;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
+{
+	if (report->maxfield < HID_MAX_FIELDS) {
+		struct hid_field *field;
+
+		if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+				+ values * sizeof(unsigned), GFP_KERNEL)))
+			return NULL;
+		memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+				+ values * sizeof(unsigned));
+
+		report->field[report->maxfield++] = field;
+		field->usage = (struct hid_usage *)(field + 1);
+		field->value = (unsigned *)(field->usage + usages);
+		field->report = report;
+
+		return field;
+	}
+
+	dbg("too many fields in report");
+	return NULL;
+}
+
+/*
+ * Open a collection. The type/usage is pushed on the stack.
+ */
+
+static int open_collection(struct hid_parser *parser, unsigned type)
+{
+	unsigned usage;
+
+	usage = parser->local.usage[0];
+
+	if (type == HID_COLLECTION_APPLICATION)
+		parser->device->application = usage;
+
+	if (parser->collection_stack_ptr < HID_COLLECTION_STACK_SIZE) { /* PUSH on stack */
+		struct hid_collection *collection = parser->collection_stack + parser->collection_stack_ptr++;
+		collection->type = type;
+		collection->usage = usage;
+		return 0;
+	}
+
+	dbg("collection stack overflow");
+	return -1;
+}
+
+/*
+ * Close a collection.
+ */
+
+static int close_collection(struct hid_parser *parser)
+{
+	if (parser->collection_stack_ptr > 0) {	/* POP from stack */
+		parser->collection_stack_ptr--;
+		return 0;
+	}
+	dbg("collection stack underflow");
+	return -1;
+}
+
+/*
+ * Climb up the stack, search for the specified collection type
+ * and return the usage.
+ */
+
+static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
+{
+	int n;
+	for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
+		if (parser->collection_stack[n].type == type)
+			return parser->collection_stack[n].usage;
+	return 0; /* we know nothing about this usage type */
+}
+
+/*
+ * Add a usage to the temporary parser table.
+ */
+
+static int hid_add_usage(struct hid_parser *parser, unsigned usage)
+{
+	if (parser->local.usage_index >= MAX_USAGES) {
+		dbg("usage index exceeded");
+		return -1;
+	}
+	parser->local.usage[parser->local.usage_index++] = usage;
+	return 0;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags)
+{
+	struct hid_report *report;
+	struct hid_field *field;
+	int usages;
+	unsigned offset;
+	int i;
+
+	if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
+    		dbg("hid_register_report failed");
+		return -1;
+	}
+
+	if (HID_MAIN_ITEM_VARIABLE & ~flags) { /* ARRAY */
+		if (parser->global.logical_maximum <= parser->global.logical_minimum) {
+			dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
+			return -1;
+		}
+		usages = parser->local.usage_index;
+		/* Hint: we can assume usages < MAX_USAGE here */
+	} else { /* VARIABLE */
+		usages = parser->global.report_count;
+	}
+	offset = report->size;
+	report->size += parser->global.report_size *
+			parser->global.report_count;
+	if (usages == 0)
+		return 0; /* ignore padding fields */
+	if ((field = hid_register_field(report, usages,
+			     parser->global.report_count)) == NULL)
+		return 0;
+	field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
+	field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
+	for (i = 0; i < usages; i++) field->usage[i].hid = parser->local.usage[i];
+	field->maxusage = usages;
+	field->flags = flags;
+	field->report_offset = offset;
+	field->report_type = report_type;
+	field->report_size = parser->global.report_size;
+	field->report_count = parser->global.report_count;
+	field->logical_minimum = parser->global.logical_minimum;
+	field->logical_maximum = parser->global.logical_maximum;
+	field->physical_minimum = parser->global.physical_minimum;
+	field->physical_maximum = parser->global.physical_maximum;
+	field->unit_exponent = parser->global.unit_exponent;
+	field->unit = parser->global.unit;
+	return 0;
+}
+
+/*
+ * Read data value from item.
+ */
+
+static __inline__ __u32 item_udata(struct hid_item *item)
+{
+	switch (item->size) {
+		case 1: return item->data.u8;
+		case 2: return item->data.u16;
+		case 4: return item->data.u32;
+	}
+	return 0;
+}
+
+static __inline__ __s32 item_sdata(struct hid_item *item)
+{
+	switch (item->size) {
+		case 1: return item->data.s8;
+		case 2: return item->data.s16;
+		case 4: return item->data.s32;
+	}
+	return 0;
+}
+
+/*
+ * Process a global item.
+ */
+
+static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
+{
+	switch (item->tag) {
+
+		case HID_GLOBAL_ITEM_TAG_PUSH:
+
+			if (parser->global_stack_ptr < HID_GLOBAL_STACK_SIZE) {
+				memcpy(parser->global_stack + parser->global_stack_ptr++,
+					&parser->global, sizeof(struct hid_global));
+				return 0;
+			}
+			dbg("global enviroment stack overflow");
+			return -1;
+
+		case HID_GLOBAL_ITEM_TAG_POP:
+
+			if (parser->global_stack_ptr > 0) {
+				memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
+					sizeof(struct hid_global));
+				return 0;
+			}
+			dbg("global enviroment stack underflow");
+			return -1;
+
+		case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+			parser->global.usage_page = item_udata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+			parser->global.logical_minimum = item_sdata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+			parser->global.logical_maximum = item_sdata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+			parser->global.physical_minimum = item_sdata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+			parser->global.physical_maximum = item_sdata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+			parser->global.unit_exponent = item_udata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_UNIT:
+			parser->global.unit = item_udata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+			if ((parser->global.report_size = item_udata(item)) > 32) {
+				dbg("invalid report_size %d", parser->global.report_size);
+				return -1;
+			}
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+			if ((parser->global.report_count = item_udata(item)) > MAX_USAGES) {
+				dbg("invalid report_count %d", parser->global.report_count);
+				return -1;
+			}
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+			if ((parser->global.report_id = item_udata(item)) == 0) {
+				dbg("report_id 0 is invalid");
+				return -1;
+			}
+			return 0;
+
+		default:
+			dbg("unknown global tag 0x%x", item->tag);
+			return -1;
+	}
+}
+
+/*
+ * Process a local item.
+ */
+
+static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
+{
+	__u32 data;
+
+	if (item->size == 0) {
+		dbg("item data expected for local item");
+		return -1;
+	}
+
+	data = item_udata(item);
+
+	switch (item->tag) {
+
+		case HID_LOCAL_ITEM_TAG_DELIMITER:
+
+			if (data) {
+				/*
+				 * We treat items before the first delimiter
+				 * as global to all usage sets (branch 0).
+				 * In the moment we process only these global
+				 * items and the first delimiter set.
+				 */
+				if (parser->local.delimiter_depth != 0) {
+					dbg("nested delimiters");
+					return -1;
+				}
+				parser->local.delimiter_depth++;
+				parser->local.delimiter_branch++;
+			} else {
+				if (parser->local.delimiter_depth < 1) {
+					dbg("bogus close delimiter");
+					return -1;
+				}
+				parser->local.delimiter_depth--;
+			}
+			return 1;
+
+		case HID_LOCAL_ITEM_TAG_USAGE:
+
+			if (parser->local.delimiter_branch < 2) {
+				if (item->size <= 2)
+					data = (parser->global.usage_page << 16) + data;
+				return hid_add_usage(parser, data);
+			}
+			dbg("alternative usage ignored");
+			return 0;
+
+		case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+
+			if (parser->local.delimiter_branch < 2) {
+				if (item->size <= 2)
+					data = (parser->global.usage_page << 16) + data;
+				parser->local.usage_minimum = data;
+				return 0;
+			}
+			dbg("alternative usage ignored");
+			return 0;
+
+		case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+
+			if (parser->local.delimiter_branch < 2) {
+				unsigned n;
+				if (item->size <= 2)
+					data = (parser->global.usage_page << 16) + data;
+				for (n = parser->local.usage_minimum; n <= data; n++)
+					if (hid_add_usage(parser, n)) {
+						dbg("hid_add_usage failed\n");
+						return -1;
+					}
+				return 0;
+			}
+			dbg("alternative usage ignored");
+			return 0;
+
+		default:
+
+			dbg("unknown local item tag 0x%x", item->tag);
+			return 0;
+	}
+}
+
+/*
+ * Process a main item.
+ */
+
+static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
+{
+	__u32 data;
+	int ret;
+
+	data = item_udata(item);
+	
+	switch (item->tag) {
+		case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+			ret = open_collection(parser, data & 3);
+			break;
+		case HID_MAIN_ITEM_TAG_END_COLLECTION:
+			ret = close_collection(parser);
+			break;
+		case HID_MAIN_ITEM_TAG_INPUT:
+			ret = hid_add_field(parser, HID_INPUT_REPORT, data);
+			break;
+		case HID_MAIN_ITEM_TAG_OUTPUT:
+			ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
+			break;
+		case HID_MAIN_ITEM_TAG_FEATURE:
+			ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
+			break;
+		default:
+			dbg("unknown main item tag 0x%x", item->tag);
+			ret = 0;
+	}
+
+	memset(&parser->local, 0, sizeof(parser->local));	/* Reset the local parser environment */
+
+	return ret;
+}
+
+/*
+ * Process a reserved item.
+ */
+
+static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
+{
+	dbg("reserved item type, tag 0x%x", item->tag);
+	return 0;
+}
+
+/*
+ * Free a report and all registered fields. The field->usage and
+ * field->value table's are allocated behind the field, so we need
+ * only to free(field) itself.
+ */
+
+static void hid_free_report(struct hid_report *report)
+{
+	unsigned n;
+
+	for (n = 0; n < report->maxfield; n++)
+		kfree(report->field[n]);
+	kfree(report);
+}
+
+/*
+ * Free a device structure, all reports, and all fields.
+ */
+
+static void hid_free_device(struct hid_device *device)
+{
+	unsigned i,j;
+
+	for (i = 0; i < HID_REPORT_TYPES; i++) {
+		struct hid_report_enum *report_enum = device->report_enum + i;
+
+		for (j = 0; j < 256; j++) {
+			struct hid_report *report = report_enum->report_id_hash[j];
+			if (report) hid_free_report(report);
+		}
+	}
+
+	if (device->rdesc) kfree(device->rdesc);
+}
+
+/*
+ * Fetch a report description item from the data stream. We support long
+ * items, though they are not used yet.
+ */
+
+static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
+{
+	if ((end - start) > 0) {
+
+		__u8 b = *start++;
+		item->type = (b >> 2) & 3;
+		item->tag  = (b >> 4) & 15;
+
+		if (item->tag == HID_ITEM_TAG_LONG) {
+
+			item->format = HID_ITEM_FORMAT_LONG;
+
+			if ((end - start) >= 2) {
+
+				item->size = *start++;
+				item->tag  = *start++;
+
+				if ((end - start) >= item->size) {
+					item->data.longdata = start;
+					start += item->size;
+					return start;
+				}
+			}
+		} else {
+
+			item->format = HID_ITEM_FORMAT_SHORT;
+			item->size = b & 3;
+			switch (item->size) {
+
+				case 0:
+					return start;
+
+				case 1: 
+					if ((end - start) >= 1) {
+						item->data.u8 = *start++;
+						return start;
+					}
+					break;
+
+				case 2: 
+					if ((end - start) >= 2) {
+						item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++));
+						return start;
+					}
+
+				case 3: 
+					item->size++;
+					if ((end - start) >= 4) {
+						item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++));
+						return start;
+					}
+			}
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Parse a report description into a hid_device structure. Reports are
+ * enumerated, fields are attached to these reports.
+ */
+
+static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
+{
+	struct hid_device *device;
+	struct hid_parser *parser;
+	struct hid_item    item;
+	__u8 *end;
+	unsigned i;
+	static int (*dispatch_type[])(struct hid_parser *parser,
+				      struct hid_item *item) = {
+		hid_parser_main,
+		hid_parser_global,
+		hid_parser_local,
+		hid_parser_reserved
+	};
+
+	if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
+		return NULL;
+	memset(device, 0, sizeof(struct hid_device));
+
+	for (i = 0; i < HID_REPORT_TYPES; i++)
+		INIT_LIST_HEAD(&device->report_enum[i].report_list);
+
+	if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) {
+		kfree(device);
+		return NULL;
+	}
+	memcpy(device->rdesc, start, size);
+
+	if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+		kfree(device->rdesc);
+		kfree(device);
+		return NULL;
+	}
+	memset(parser, 0, sizeof(struct hid_parser));
+	parser->device = device;
+	
+	end = start + size;
+	while ((start = fetch_item(start, end, &item)) != 0) {
+		if (item.format != HID_ITEM_FORMAT_SHORT) {
+			dbg("unexpected long global item");
+			hid_free_device(device);
+			kfree(parser);
+			return NULL;
+		}
+		if (dispatch_type[item.type](parser, &item)) {
+			dbg("item %u %u %u %u parsing failed\n",
+				item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
+			hid_free_device(device);
+			kfree(parser);
+			return NULL;
+		}
+
+		if (start == end) {
+			if (parser->collection_stack_ptr) {
+				dbg("unbalanced collection at end of report description");
+				hid_free_device(device);
+				kfree(parser);
+				return NULL;
+			}
+			if (parser->local.delimiter_depth) {
+				dbg("unbalanced delimiter at end of report description");
+				hid_free_device(device);
+				kfree(parser);
+				return NULL;
+			}
+			kfree(parser);
+			return device;
+		}
+	}
+
+	dbg("item fetching failed at offset %d\n", (int)(end - start));
+	hid_free_device(device);
+	kfree(parser);
+	return NULL;
+}
+
+/*
+ * Convert a signed n-bit integer to signed 32-bit integer. Common
+ * cases are done through the compiler, the screwed things has to be
+ * done by hand.
+ */
+
+static __inline__ __s32 snto32(__u32 value, unsigned n)
+{
+	switch (n) {
+		case 8:  return ((__s8)value);
+		case 16: return ((__s16)value);
+		case 32: return ((__s32)value);
+	}
+	return value & (1 << (n - 1)) ? value | (-1 << n) : value;
+}
+
+/*
+ * Convert a signed 32-bit integer to a signed n-bit integer. 
+ */
+
+static __inline__ __u32 s32ton(__s32 value, unsigned n)
+{
+	__s32 a = value >> (n - 1);
+	if (a && a != -1) return value > 0 ? 1 << (n - 1) : (1 << n) - 1;
+	return value & ((1 << n) - 1);
+}
+
+/*
+ * Extract/implement a data field from/to a report. We use 64-bit unsigned,
+ * 32-bit aligned, so that we can possibly have alignment problems on some
+ * odd architectures.
+ */
+
+static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
+{
+	report += (offset >> 5) << 2; offset &= 31;
+	return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1);
+}
+
+static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+{
+	report += (offset >> 5) << 2; offset &= 31;
+	*(__u64*)report &= cpu_to_le64(~((((__u64) 1 << n) - 1) << offset));
+	*(__u64*)report |= cpu_to_le64((__u64)value << offset);
+}
+
+static void hid_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage)
+{
+	struct input_dev *input = &device->input;
+	int max;
+	unsigned long *bit;
+
+	switch (usage->hid & HID_USAGE_PAGE) {
+
+		case HID_UP_KEYBOARD:
+
+			set_bit(EV_REP, input->evbit);
+			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+
+			if ((usage->hid & HID_USAGE) < 256) {
+				if (!(usage->code = hid_keyboard[usage->hid & HID_USAGE]))
+					return;
+				clear_bit(usage->code, bit);
+			} else
+				usage->code = KEY_UNKNOWN;
+
+			break; 
+
+		case HID_UP_BUTTON:
+
+			usage->code = ((usage->hid - 1) & 0xf) + 0x100;
+			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+			
+			switch (device->application) {
+				case HID_GD_GAMEPAD:  usage->code += 0x10;
+				case HID_GD_JOYSTICK: usage->code += 0x10;
+				case HID_GD_MOUSE:    usage->code += 0x10; break;
+				default:
+					if (field->physical == HID_GD_POINTER)
+						usage->code += 0x10;
+					break;
+			}
+			break;
+
+		case HID_UP_GENDESK:
+
+			if ((usage->hid & 0xf0) == 0x80) {	/* SystemControl */
+				switch (usage->hid & 0xf) {
+					case 0x1: usage->code = KEY_POWER;  break;
+					case 0x2: usage->code = KEY_SLEEP;  break;
+					case 0x3: usage->code = KEY_WAKEUP; break;
+					default: usage->code = KEY_UNKNOWN; break;
+				}
+				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+				break;
+			}
+
+			usage->code = usage->hid & 0xf;
+
+			if (field->report_size == 1) {
+				usage->code = BTN_MISC;
+				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+				break;
+			}
+
+			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+				usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
+				break;
+			} 
+
+			usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
+
+			if (usage->hid == HID_GD_HATSWITCH) {
+				usage->code = ABS_HAT0X;
+				usage->hat = 1 + (field->logical_maximum == 4);
+			}
+			break;
+
+		case HID_UP_LED:
+
+			usage->code = (usage->hid - 1) & 0xf;
+			usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; 
+			break;
+
+		case HID_UP_DIGITIZER:
+
+			switch (usage->hid & 0xff) {
+
+				case 0x30: /* TipPressure */
+
+					if (!test_bit(BTN_TOUCH, input->keybit)) {
+						device->quirks |= HID_QUIRK_NOTOUCH;
+						set_bit(EV_KEY, input->evbit);
+						set_bit(BTN_TOUCH, input->keybit);
+					}
+					usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; 
+					usage->code = ABS_PRESSURE;
+					clear_bit(usage->code, bit);
+					break;
+
+				case 0x32: /* InRange */
+
+					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+					switch (field->physical & 0xff) {	
+						case 0x21: usage->code = BTN_TOOL_MOUSE; break;
+						case 0x22: usage->code = BTN_TOOL_FINGER; break;
+						default: usage->code = BTN_TOOL_PEN; break;
+					}
+					break;
+
+				case 0x3c: /* Invert */
+
+					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+					usage->code = BTN_TOOL_RUBBER;
+					clear_bit(usage->code, bit);
+					break;
+
+				case 0x33: /* Touch */
+				case 0x42: /* TipSwitch */
+				case 0x43: /* TipSwitch2 */
+
+					device->quirks &= ~HID_QUIRK_NOTOUCH;
+					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+					usage->code = BTN_TOUCH;
+					clear_bit(usage->code, bit);
+					break;
+
+				case 0x44: /* BarrelSwitch */
+
+					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+					usage->code = BTN_STYLUS;
+					clear_bit(usage->code, bit);
+					break;
+
+				default:  goto unknown;
+			}
+			break;
+
+		case HID_UP_CONSUMER:	/* USB HUT v1.1, pages 56-62 */
+			
+			switch (usage->hid & HID_USAGE) {
+
+				case 0x034: usage->code = KEY_SLEEP;		break;
+				case 0x036: usage->code = BTN_MISC;		break;
+				case 0x08a: usage->code = KEY_WWW;		break;
+				case 0x095: usage->code = KEY_HELP;		break;
+
+				case 0x0b4: usage->code = KEY_REWIND;		break;
+				case 0x0b5: usage->code = KEY_NEXTSONG;		break;
+				case 0x0b6: usage->code = KEY_PREVIOUSSONG;	break;
+				case 0x0b7: usage->code = KEY_STOPCD;		break;
+				case 0x0b8: usage->code = KEY_EJECTCD;		break;
+				case 0x0cd: usage->code = KEY_PLAYPAUSE;	break;
+
+				case 0x0e2: usage->code = KEY_MUTE;		break;
+				case 0x0e9: usage->code = KEY_VOLUMEUP;		break;
+				case 0x0ea: usage->code = KEY_VOLUMEDOWN;	break;
+
+				case 0x183: usage->code = KEY_CONFIG;		break;
+				case 0x18a: usage->code = KEY_MAIL;		break;
+				case 0x192: usage->code = KEY_CALC;		break;
+				case 0x194: usage->code = KEY_FILE;		break;
+
+				case 0x21a: usage->code = KEY_UNDO;		break;
+				case 0x21b: usage->code = KEY_COPY;		break;
+				case 0x21c: usage->code = KEY_CUT;		break;
+				case 0x21d: usage->code = KEY_PASTE;		break;
+
+				case 0x221: usage->code = KEY_FIND;		break;
+				case 0x223: usage->code = KEY_HOMEPAGE;		break;
+				case 0x224: usage->code = KEY_BACK;		break;
+				case 0x225: usage->code = KEY_FORWARD;		break;
+				case 0x226: usage->code = KEY_STOP;		break;
+				case 0x227: usage->code = KEY_REFRESH;		break;
+				case 0x22a: usage->code = KEY_BOOKMARKS;	break;
+
+				default:    usage->code = KEY_UNKNOWN;		break;
+
+			}
+		
+			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+			break;
+
+		default:
+		unknown:
+
+			if (field->report_size == 1) {
+				usage->code = BTN_MISC;
+				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+				break;
+			}
+
+			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+				usage->code = REL_MISC;
+				usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
+				break;
+			}
+
+			usage->code = ABS_MISC;
+			usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
+			break;
+	}
+
+	set_bit(usage->type, input->evbit);
+
+	while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
+		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
+	}
+
+	if (usage->type == EV_ABS) {
+		int a = field->logical_minimum;
+		int b = field->logical_maximum;
+
+		input->absmin[usage->code] = a; 
+		input->absmax[usage->code] = b;
+		input->absfuzz[usage->code] = (b - a) >> 8;
+		input->absflat[usage->code] = (b - a) >> 4;
+	}
+
+	if (usage->hat) {
+		int i;
+		for (i = usage->code; i < usage->code + 2; i++) {
+			input->absmax[i] = 1;
+			input->absmin[i] = -1;
+			input->absfuzz[i] = 0;
+			input->absflat[i] = 0;
+		}
+		set_bit(usage->code + 1, input->absbit);
+	}
+}
+
+static void hid_process_event(struct input_dev *input, int *quirks, struct hid_field *field, struct hid_usage *usage, __s32 value)
+{
+	hid_dump_input(usage, value);
+
+	if (usage->hat) {
+		if (usage->hat == 2) value = value * 2;
+		if (value > 8) value = 8;
+		input_event(input, usage->type, usage->code    , hid_hat_to_axis[value].x);
+		input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[value].y);
+		return;
+	}
+
+	if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
+		*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
+		return;
+	}
+
+	if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
+		if (value) {
+			input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
+			return;
+		}
+		input_event(input, usage->type, usage->code, 0);
+		input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
+		return;
+	}
+
+	if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
+		int a = field->logical_minimum;
+		int b = field->logical_maximum;
+		input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
+	}
+
+	input_event(input, usage->type, usage->code, value);
+
+	if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
+		input_event(input, usage->type, usage->code, 0);
+}
+
+/*
+ * Search an array for a value.
+ */
+
+static __inline__ int search(__s32 *array, __s32 value, unsigned n)
+{
+	while (n--) if (*array++ == value) return 0;
+	return -1;
+}
+
+/*
+ * Analyse a received field, and fetch the data from it. The field
+ * content is stored for next report processing (we do differential
+ * reporting to the layer).
+ */
+
+static void hid_input_field(struct hid_device *dev, struct hid_field *field, __u8 *data)
+{
+	unsigned n;
+	unsigned count = field->report_count;
+	unsigned offset = field->report_offset;
+	unsigned size = field->report_size;
+	__s32 min = field->logical_minimum;
+	__s32 max = field->logical_maximum;
+	__s32 value[count]; /* WARNING: gcc specific */
+   
+	for (n = 0; n < count; n++)
+			value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : 
+						    extract(data, offset + n * size, size);
+
+	for (n = 0; n < count; n++) {
+
+		if (HID_MAIN_ITEM_VARIABLE & field->flags) {
+
+			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+				if (!value[n]) continue;
+			} else {
+				if (value[n] == field->value[n]) continue;
+			}
+			hid_process_event(&dev->input, &dev->quirks, field, &field->usage[n], value[n]);
+
+		} else {
+
+			if (field->value[n] >= min && field->value[n] <= max			/* non-NULL value */
+				&& field->usage[field->value[n] - min].hid			/* nonzero usage */
+				&& search(value, field->value[n], count))
+					hid_process_event(&dev->input, &dev->quirks, field,
+						&field->usage[field->value[n] - min], 0);
+
+			if (value[n] >= min && value[n] <= max					/* non-NULL value */
+				&& field->usage[value[n] - min].hid				/* nonzero usage */
+				&& search(field->value, value[n], count))
+					hid_process_event(&dev->input, &dev->quirks,
+						field, &field->usage[value[n] - min], 1);
+		}
+	}
+
+	memcpy(field->value, value, count * sizeof(__s32));
+}
+
+/*
+ * Interrupt input handler - analyse a received report.
+ */
+
+static void hid_irq(struct urb *urb)
+{
+	struct hid_device *device = urb->context;
+	struct hid_report_enum *report_enum = device->report_enum + HID_INPUT_REPORT;
+	struct hid_report *report;
+	__u8 *data = urb->transfer_buffer;
+	int len = urb->actual_length;
+	int n;
+
+	if (urb->status) {
+		dbg("nonzero status in irq %d", urb->status);
+		return;
+	}
+
+	if (!len) {
+		dbg("empty report");
+		return;
+	}
+
+#ifdef DEBUG_DATA
+	printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered) = ", len, report_enum->numbered ? "" : "un");
+	for (n = 0; n < len; n++)
+		printk(" %02x", data[n]);
+	printk("\n");
+#endif
+
+	n = 0;				/* Normally report number is 0 */
+
+	if (report_enum->numbered) {	/* Device uses numbered reports, data[0] is report number */
+		n = *data++;
+		len--;
+	} 
+
+	if (!(report = report_enum->report_id_hash[n])) {
+		dbg("undefined report_id %d received", n);
+#ifdef DEBUG
+			printk(KERN_DEBUG __FILE__ ": report (size %u) = ", len);
+			for (n = 0; n < len; n++)
+				printk(" %02x", data[n]);
+			printk("\n");
+#endif
+	
+		return;
+	}
+
+	if (len < ((report->size - 1) >> 3) + 1) {
+		dbg("report %d is too short, (%d < %d)", report->id, len, ((report->size - 1) >> 3) + 1);
+		return;
+	}
+
+	for (n = 0; n < report->maxfield; n++)
+		hid_input_field(device, report->field[n], data);
+
+	return;
+}
+
+/*
+ * hid_read_report() s intended to read the hid devices values even
+ * before the input device is registered, so that the userland interface
+ * modules start with real values. This is especially important for joydev.c
+ * automagic calibration. Doesn't work yet, though. Don't know why, the control
+ * request just times out on most devices I have and returns nonsense on others.
+ */
+
+static void hid_read_report(struct hid_device *hid, struct hid_report *report)
+{
+#if 0
+	int rlen = ((report->size - 1) >> 3) + 1;
+	char rdata[rlen];
+	struct urb urb;
+	int read, j;
+
+	memset(&urb, 0, sizeof(struct urb));
+	memset(rdata, 0, rlen);
+
+	urb.transfer_buffer = rdata;
+	urb.actual_length = rlen;
+	urb.context = hid;
+
+	dbg("getting report type %d id %d len %d", report->type + 1, report->id, rlen);
+
+	if ((read = usb_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, rdata, rlen)) != rlen) {
+		dbg("reading report failed rlen %d read %d", rlen, read);
+#ifdef DEBUG
+		printk(KERN_DEBUG __FILE__ ": report = ");
+		for (j = 0; j < rlen; j++) printk(" %02x", rdata[j]);
+		printk("\n");
+#endif
+		return;
+	}
+
+	hid_irq(&urb);
+#endif
+}
+
+/*
+ * Output the field into the report.
+ */
+
+static void hid_output_field(struct hid_field *field, __u8 *data)
+{
+	unsigned count = field->report_count;
+	unsigned offset = field->report_offset;
+	unsigned size = field->report_size;
+	unsigned n;
+   
+	for (n = 0; n < count; n++) {
+		if (field->logical_minimum < 0)	/* signed values */
+			implement(data, offset + n * size, size, s32ton(field->value[n], size));
+		 else				/* unsigned values */
+			implement(data, offset + n * size, size, field->value[n]);
+       	}
+}
+
+/*
+ * Create a report.
+ */
+
+void hid_output_report(struct hid_report *report, __u8 *data)
+{
+	unsigned n;
+	for (n = 0; n < report->maxfield; n++)
+		hid_output_field(report->field[n], data);
+};
+
+/*
+ * Set a field value. The report this field belongs to has to be
+ * created and transfered to the device, to set this value in the
+ * device.
+ */
+
+int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
+{
+	unsigned size = field->report_size;
+
+	hid_dump_input(field->usage + offset, value);
+	
+	if (offset >= field->report_count) {
+		dbg("offset exceeds report_count");
+		return -1;
+	}
+	if (field->logical_minimum < 0) {
+		if (value != snto32(s32ton(value, size), size)) {
+			dbg("value %d is out of range", value);
+			return -1;
+		}
+	}
+	if (   (value > field->logical_maximum)
+	    || (value < field->logical_minimum)) {
+		dbg("value %d is invalid", value);
+		return -1;
+	}
+	field->value[offset] = value;
+	return 0;
+}
+
+static int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
+{
+	struct hid_report_enum *report_enum = hid->report_enum + HID_OUTPUT_REPORT;
+	struct list_head *list = report_enum->report_list.next;
+	int i, j;
+
+	while (list != &report_enum->report_list) {
+		struct hid_report *report = (struct hid_report *) list;
+		list = list->next;
+		for (i = 0; i < report->maxfield; i++) {
+			*field = report->field[i];
+			for (j = 0; j < (*field)->maxusage; j++)
+				if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
+					return j;
+		}
+	}
+	return -1;
+}
+
+static void hid_ctrl(struct urb *urb)
+{
+        if (urb->status)
+                warn("ctrl urb status %d received", urb->status);
+}       
+
+static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct hid_device *hid = dev->private;
+	struct hid_field *field = NULL;
+	int offset;
+
+	if ((offset = hid_find_field(hid, type, code, &field)) == -1) {
+		warn("event field not found");
+		return -1;
+	}
+
+	hid_set_field(field, offset, value);
+
+	if (hid->urbout.status == -EINPROGRESS) {
+		warn("had to kill output urb");
+		usb_unlink_urb(&hid->urbout);
+	}
+
+	hid_output_report(field->report, hid->bufout);
+
+	hid->dr.value = 0x200 | field->report->id;
+	hid->dr.length = ((field->report->size - 1) >> 3) + 1;
+	hid->urbout.transfer_buffer_length = hid->dr.length;
+
+	if (usb_submit_urb(&hid->urbout)) {
+		err("usb_submit_urb(out) failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int hid_open(struct input_dev *dev)
+{
+	struct hid_device *hid = dev->private;
+
+	if (hid->open++)
+		return 0;
+
+	 if (usb_submit_urb(&hid->urb))
+		return -EIO;
+
+	return 0;
+}
+
+static void hid_close(struct input_dev *dev)
+{
+	struct hid_device *hid = dev->private;
+
+	if (!--hid->open)
+		usb_unlink_urb(&hid->urb);
+}
+
+/*
+ * Configure the input layer interface
+ * Read all reports and initalize the absoulte field values.
+ */
+
+static void hid_init_input(struct hid_device *hid)
+{
+	struct hid_report_enum *report_enum;
+	struct list_head *list;
+	int i, j, k;
+
+	hid->input.private = hid;
+	hid->input.event = hid_event;
+	hid->input.open = hid_open;
+	hid->input.close = hid_close;
+
+	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+
+		report_enum = hid->report_enum + k;
+		list = report_enum->report_list.next;
+
+		while (list != &report_enum->report_list) {
+
+			struct hid_report *report = (struct hid_report *) list;
+
+			list = list->next;
+
+			for (i = 0; i < report->maxfield; i++)
+				for (j = 0; j < report->field[i]->maxusage; j++)
+					hid_configure_usage(hid, report->field[i], report->field[i]->usage + j);
+
+			if (k == HID_INPUT_REPORT)  {
+				usb_set_idle(hid->dev, hid->ifnum, 0, report->id);
+				hid_read_report(hid, report);
+			}
+		}
+	}
+}
+
+#define USB_VENDOR_ID_WACOM		0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE	0x0010
+#define USB_DEVICE_ID_WACOM_INTUOS	0x0020
+
+struct hid_blacklist {
+	__u16 idVendor;
+	__u16 idProduct;
+} hid_blacklist[] = {
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1},
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2},
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3},
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4},
+	{ 0, 0 }
+};
+
+static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, char *name)
+{
+	struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0;
+	struct hid_descriptor *hdesc;
+	struct hid_device *hid;
+	unsigned rsize = 0;
+	int n;
+
+	for (n = 0; hid_blacklist[n].idVendor; n++)
+		if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) &&
+			(hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL;
+
+	if (interface->bInterfaceClass != USB_INTERFACE_CLASS_HID)
+		return NULL;
+
+	if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc)
+		&& usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc)) {
+			dbg("class descriptor not present\n");
+			return NULL;
+	}
+
+	for (n = 0; n < hdesc->bNumDescriptors; n++)
+		if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT)
+			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
+
+	if (!rsize || rsize > 1024) {
+		dbg("weird size of report descriptor (%u)", rsize);
+		return NULL;
+	}
+
+	{
+		__u8 rdesc[rsize];
+
+		if ((n = usb_get_class_descriptor(dev, interface->bInterfaceNumber, USB_DT_REPORT, 0, rdesc, rsize)) < 0) {
+			dbg("reading report descriptor failed");
+			return NULL;
+		}
+
+#ifdef DEBUG_DATA
+		printk(KERN_DEBUG __FILE__ ": report (size %u, read %d) = ", rsize, n);
+		for (n = 0; n < rsize; n++)
+			printk(" %02x", (unsigned) rdesc[n]);
+		printk("\n");
+#endif
+
+		if (!(hid = hid_parse_report(rdesc, rsize))) {
+			dbg("parsing report descriptor failed");
+			return NULL;
+		}
+	}
+
+	for (n = 0; n < interface->bNumEndpoints; n++) {
+
+		struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n];
+		int pipe, maxp;
+
+		if ((endpoint->bmAttributes & 3) != 3)		/* Not an interrupt endpoint */
+			continue;
+
+		if (!(endpoint->bEndpointAddress & 0x80)) 	/* Not an input endpoint */
+			continue;
+
+		pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+		maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+		FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval);
+	
+		break;
+	}
+
+	if (n == interface->bNumEndpoints) {
+		dbg("couldn't find an input interrupt endpoint");
+		hid_free_device(hid);
+		return NULL;
+	}
+
+	hid->version = hdesc->bcdHID;
+	hid->country = hdesc->bCountryCode;
+	hid->dev = dev;
+	hid->ifnum = interface->bInterfaceNumber;
+
+	hid->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	hid->dr.request = USB_REQ_SET_REPORT;
+	hid->dr.value = 0x200;
+	hid->dr.index = hid->ifnum;
+	hid->dr.length = 1;
+
+	hid->input.name = hid->name;
+	hid->input.idbus = BUS_USB;
+	hid->input.idvendor = dev->descriptor.idVendor;
+	hid->input.idproduct = dev->descriptor.idProduct;
+	hid->input.idversion = dev->descriptor.bcdDevice;
+
+	if (strlen(name)) 
+		strcpy(hid->name, name);
+	else
+		sprintf(hid->name, "USB HID %s %04x:%04x",
+			((hid->application >= 0x00010000) && (hid->application <= 0x00010008)) ?
+			hid_types[hid->application & 0xffff] : "Device",
+			hid->input.idvendor, hid->input.idproduct);
+
+	FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0),
+		(void*) &hid->dr, hid->bufout, 1, hid_ctrl, hid);
+
+	if (interface->bInterfaceSubClass == 1)
+        	usb_set_protocol(dev, hid->ifnum, 1);
+
+	return hid;
+}
+
+static void* hid_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct hid_device *hid;
+	char name[128];
+	char *buf;
+
+	dbg("HID probe called for ifnum %d", ifnum);
+
+	name[0] = 0;
+
+	if (!(buf = kmalloc(63, GFP_KERNEL)))
+		return NULL;
+
+	if (dev->descriptor.iManufacturer &&
+		usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
+			strcat(name, buf);
+	if (dev->descriptor.iProduct &&
+		usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
+			sprintf(name, "%s %s", name, buf);
+
+	kfree(buf);
+
+	if (!(hid = usb_hid_configure(dev, ifnum, name)))
+		return NULL;
+
+	hid_dump_device(hid);
+
+	hid_init_input(hid);
+	input_register_device(&hid->input);
+
+	printk(KERN_INFO "input%d: USB HID v%x.%02x %s",
+		hid->input.number,
+		hid->version >> 8, hid->version & 0xff,
+		((hid->application >= 0x00010000) && (hid->application <= 0x00010008)) ?
+		hid_types[hid->application & 0xffff] : "Device");
+
+	if (strlen(name))
+		printk(" [%s]", name);
+	else
+		printk(" [%04x:%04x]", hid->input.idvendor, hid->input.idproduct);
+	
+	printk(" on usb%d:%d.%d\n", dev->bus->busnum, dev->devnum, ifnum);
+
+	return hid;
+}
+
+static void hid_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct hid_device *hid = ptr;
+
+	dbg("cleanup called");
+	usb_unlink_urb(&hid->urb);
+	input_unregister_device(&hid->input);
+	hid_free_device(hid);
+}
+
+static struct usb_driver hid_driver = {
+	name:		"hid",
+	probe:		hid_probe,
+	disconnect:	hid_disconnect
+};
+
+static int __init hid_init(void)
+{
+	usb_register(&hid_driver);
+	return 0;
+}
+
+static void __exit hid_exit(void)
+{
+	usb_deregister(&hid_driver);
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hid.h linux.18p8/drivers/usb/hid.h
--- linux.vanilla/drivers/usb/hid.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/hid.h	Fri Sep 15 15:12:55 2000
@@ -0,0 +1,330 @@
+#ifndef __HID_H
+#define __HID_H
+
+/*
+ * $Id: hid.h,v 1.4 2000/05/29 09:01:52 vojtech Exp $
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/list.h>
+
+/*
+ * USB HID (Human Interface Device) interface class code
+ */
+
+#define USB_INTERFACE_CLASS_HID		3
+
+/*
+ * We parse each description item into this structure. Short items data
+ * values are expanded to 32-bit signed int, long items contain a pointer
+ * into the data area.
+ */
+
+struct hid_item {
+	unsigned  format;
+	__u8      size;
+	__u8      type;
+	__u8      tag;
+	union {
+	    __u8   u8;
+	    __s8   s8;
+	    __u16  u16;
+	    __s16  s16;
+	    __u32  u32;
+	    __s32  s32;
+	    __u8  *longdata;
+	} data;
+};
+
+/*
+ * HID report item format
+ */
+
+#define HID_ITEM_FORMAT_SHORT	0
+#define HID_ITEM_FORMAT_LONG	1
+
+/*
+ * Special tag indicating long items
+ */
+
+#define HID_ITEM_TAG_LONG	15
+
+/*
+ * HID report descriptor item type (prefix bit 2,3)
+ */
+
+#define HID_ITEM_TYPE_MAIN		0
+#define HID_ITEM_TYPE_GLOBAL		1
+#define HID_ITEM_TYPE_LOCAL		2
+#define HID_ITEM_TYPE_RESERVED		3
+
+/*
+ * HID report descriptor main item tags
+ */
+
+#define HID_MAIN_ITEM_TAG_INPUT			8
+#define HID_MAIN_ITEM_TAG_OUTPUT		9
+#define HID_MAIN_ITEM_TAG_FEATURE		11
+#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION	10
+#define HID_MAIN_ITEM_TAG_END_COLLECTION	12
+
+/*
+ * HID report descriptor main item contents
+ */
+
+#define HID_MAIN_ITEM_CONSTANT		0x001
+#define HID_MAIN_ITEM_VARIABLE		0x002
+#define HID_MAIN_ITEM_RELATIVE		0x004
+#define HID_MAIN_ITEM_WRAP		0x008	
+#define HID_MAIN_ITEM_NONLINEAR		0x010
+#define HID_MAIN_ITEM_NO_PREFERRED	0x020
+#define HID_MAIN_ITEM_NULL_STATE	0x040
+#define HID_MAIN_ITEM_VOLATILE		0x080
+#define HID_MAIN_ITEM_BUFFERED_BYTE	0x100
+
+/*
+ * HID report descriptor collection item types
+ */
+
+#define HID_COLLECTION_PHYSICAL		0
+#define HID_COLLECTION_APPLICATION	1
+#define HID_COLLECTION_LOGICAL		2
+
+/*
+ * HID report descriptor global item tags
+ */
+
+#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE		0
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM	1
+#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM	2
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM	3
+#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM	4
+#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT	5
+#define HID_GLOBAL_ITEM_TAG_UNIT		6
+#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE		7
+#define HID_GLOBAL_ITEM_TAG_REPORT_ID		8
+#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT	9
+#define HID_GLOBAL_ITEM_TAG_PUSH		10
+#define HID_GLOBAL_ITEM_TAG_POP			11
+
+/*
+ * HID report descriptor local item tags
+ */
+
+#define HID_LOCAL_ITEM_TAG_USAGE		0
+#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM	1
+#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM	2
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX	3
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM	4
+#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM	5
+#define HID_LOCAL_ITEM_TAG_STRING_INDEX		7
+#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM	8
+#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM	9
+#define HID_LOCAL_ITEM_TAG_DELIMITER		10
+
+/*
+ * HID usage tables
+ */
+
+#define HID_USAGE_PAGE		0xffff0000
+
+#define HID_UP_GENDESK 		0x00010000
+#define HID_UP_KEYBOARD 	0x00070000
+#define HID_UP_LED 		0x00080000
+#define HID_UP_BUTTON 		0x00090000
+#define HID_UP_CONSUMER		0x000c0000
+#define HID_UP_DIGITIZER 	0x000d0000
+#define HID_UP_PID 		0x000f0000
+
+#define HID_USAGE		0x0000ffff
+
+#define HID_GD_POINTER		0x00010001
+#define HID_GD_MOUSE		0x00010002
+#define HID_GD_JOYSTICK		0x00010004
+#define HID_GD_GAMEPAD		0x00010005
+#define HID_GD_HATSWITCH	0x00010039
+
+/*
+ * HID report types --- Ouch! HID spec says 1 2 3!
+ */
+
+#define HID_INPUT_REPORT	0
+#define HID_OUTPUT_REPORT	1
+#define HID_FEATURE_REPORT	2
+
+/*
+ * HID device quirks.
+ */
+
+#define HID_QUIRK_INVERT	0x01
+#define HID_QUIRK_NOTOUCH	0x02
+
+/*
+ * This is the global enviroment of the parser. This information is
+ * persistent for main-items. The global enviroment can be saved and
+ * restored with PUSH/POP statements.
+ */
+
+struct hid_global {
+	unsigned usage_page;
+	__s32    logical_minimum;
+	__s32    logical_maximum;
+	__s32    physical_minimum;
+	__s32    physical_maximum;
+	unsigned unit_exponent;
+	unsigned unit;
+	unsigned report_id;
+	unsigned report_size;
+	unsigned report_count;
+};
+
+/*
+ * This is the local enviroment. It is resistent up the the next main-item.
+ */
+
+#define MAX_USAGES 1024
+
+struct hid_local {
+	unsigned usage[MAX_USAGES]; /* usage array */
+	unsigned usage_index;
+	unsigned usage_minimum;
+	unsigned delimiter_depth;
+	unsigned delimiter_branch;
+};
+
+/*
+ * This is the collection stack. We climb up the stack to determine
+ * application and function of each field.
+ */
+
+struct hid_collection {
+	unsigned type;
+	unsigned usage;
+};
+
+struct hid_usage {
+	unsigned  hid;			/* hid usage code */
+	__u16     code;			/* input driver code */
+	__u8      type;			/* input driver type */
+	__u8	  hat;			/* hat switch fun */
+};
+
+struct hid_field {
+	unsigned  physical;		/* physical usage for this field */
+	unsigned  logical;		/* logical usage for this field */
+	struct hid_usage *usage;	/* usage table for this function */
+	unsigned  maxusage;		/* maximum usage index */
+	unsigned  flags;		/* main-item flags (i.e. volatile,array,constant) */
+	unsigned  report_offset;	/* bit offset in the report */
+	unsigned  report_size;		/* size of this field in the report */
+	unsigned  report_count;		/* number of this field in the report */
+	unsigned  report_type;		/* (input,output,feature) */
+	__s32    *value;		/* last known value(s) */
+	__s32     logical_minimum;
+	__s32     logical_maximum;
+	__s32     physical_minimum;
+	__s32     physical_maximum;
+	unsigned  unit_exponent;
+	unsigned  unit;
+	struct hid_report *report;	/* associated report */
+};
+
+#define HID_MAX_FIELDS 64
+
+struct hid_report {
+	struct list_head list;
+	unsigned id;					/* id of this report */
+	unsigned type;					/* report type */
+	struct hid_field *field[HID_MAX_FIELDS];	/* fields of the report */
+	unsigned maxfield;				/* maximum valid field index */
+	unsigned size;					/* size of the report (bits) */
+	struct hid_device *device;			/* associated device */
+};
+
+struct hid_report_enum {
+	unsigned numbered;
+	struct list_head report_list;
+	struct hid_report *report_id_hash[256];
+};
+
+#define HID_REPORT_TYPES 3
+
+struct hid_device {							/* device report descriptor */
+	 __u8 *rdesc;
+	unsigned rsize;
+	unsigned application;						/* HID application, i.e. Digitizer */
+	unsigned version;						/* HID version */
+	unsigned country;						/* HID country */
+	struct hid_report_enum report_enum[HID_REPORT_TYPES];
+
+	struct usb_device *dev;						/* USB device */
+	int ifnum;							/* USB interface number */
+
+	char buffer[32];						/* Receive buffer */
+	char bufout[32];						/* Transmit buffer */
+	devrequest dr;							/* Startup packet */
+	struct urb urb;							/* USB URB structure */
+	struct urb urbout;						/* Output URB */
+	struct input_dev input;						/* input device structure */
+	int open;							/* is the device open by input? */
+	int quirks;							/* Various nasty tricks the device can pull on us */
+	char name[128];							/* Device name */
+};
+
+#define HID_GLOBAL_STACK_SIZE 4
+#define HID_COLLECTION_STACK_SIZE 4
+
+struct hid_parser {
+	struct hid_global     global;
+	struct hid_global     global_stack[HID_GLOBAL_STACK_SIZE];
+	unsigned              global_stack_ptr;
+	struct hid_local      local;
+	struct hid_collection collection_stack[HID_COLLECTION_STACK_SIZE];
+	unsigned              collection_stack_ptr;
+	struct hid_device    *device;
+};
+
+struct hid_class_descriptor {
+	__u8  bDescriptorType;
+	__u16 wDescriptorLength;
+} __attribute__ ((packed));
+
+struct hid_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u16 bcdHID;
+	__u8  bCountryCode;
+	__u8  bNumDescriptors;
+
+	struct hid_class_descriptor desc[1];
+} __attribute__ ((packed));
+
+
+#endif
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hub.c linux.18p8/drivers/usb/hub.c
--- linux.vanilla/drivers/usb/hub.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/hub.c	Fri Sep  1 13:55:35 2000
@@ -1,220 +1,317 @@
 /*
  * USB hub driver.
  *
- * This is horrible, it knows about the UHCI driver
- * internals, but it's just meant as a rough example,
- * let's do the virtualization later when this works.
- *
  * (C) Copyright 1999 Linus Torvalds
  * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Gregory P. Smith
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/list.h>
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
 
-#include <asm/spinlock.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
 
-#include "usb.h"
-#include "uhci.h"
 #include "hub.h"
 
-extern struct usb_operations uhci_device_operations;
-
 /* Wakes up khubd */
-static struct wait_queue *usb_hub_wait = NULL;
 static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
+static DECLARE_MUTEX(usb_address0_sem);
+
+static LIST_HEAD(hub_event_list);	/* List of hubs needing servicing */
+static LIST_HEAD(hub_list);		/* List containing all of the hubs (for cleanup) */
+
+static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
+static int khubd_pid = 0;			/* PID of khubd */
+static int khubd_running = 0;
+
+static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
+		USB_DT_HUB << 8, 0, data, size, HZ);
+}
 
-/* List of hubs needing servicing */
-static struct list_head hub_event_list;
+static int usb_clear_hub_feature(struct usb_device *dev, int feature)
+{
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
+}
 
-/* PID of khubd */
-static int khubd_pid = 0;
+static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
+}
+
+static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
+}
+
+static int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
+		data, sizeof(struct usb_hub_status), HZ);
+}
+
+static int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
+		data, sizeof(struct usb_hub_status), HZ);
+}
 
 /*
  * A irq handler returns non-zero to indicate to
  * the low-level driver that it wants to be re-activated,
  * or zero to say "I'm done".
  */
-static int hub_irq(int status, void *__buffer, void *dev_id)
+static void hub_irq(struct urb *urb)
 {
-	struct usb_hub *hub = dev_id;
+	struct usb_hub *hub = (struct usb_hub *)urb->context;
 	unsigned long flags;
 
-	if (waitqueue_active(&usb_hub_wait)) {
+	if (urb->status) {
+		if (urb->status != -ENOENT)
+			dbg("nonzero status in irq %d", urb->status);
+
+		return;
+	}
+
+	/* Something happened, let khubd figure it out */
+	if (waitqueue_active(&khubd_wait)) {
 		/* Add the hub to the event queue */
 		spin_lock_irqsave(&hub_event_lock, flags);
 		if (hub->event_list.next == &hub->event_list) {
 			list_add(&hub->event_list, &hub_event_list);
 			/* Wake up khubd */
-			wake_up(&usb_hub_wait);
+			wake_up(&khubd_wait);
 		}
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 	}
+}
+
+static void usb_hub_power_on(struct usb_hub *hub)
+{
+	int i;
 
-	return 1;
+	/* Enable power to the ports */
+	dbg("enabling power on all ports");
+	for (i = 0; i < hub->nports; i++)
+		usb_set_port_feature(hub->dev, i + 1, USB_PORT_FEAT_POWER);
 }
 
-static void usb_hub_configure(struct usb_hub *hub)
+static int usb_hub_configure(struct usb_hub *hub)
 {
 	struct usb_device *dev = hub->dev;
-	unsigned char hubdescriptor[8], buf[4];
-	int charac, i;
+	unsigned char buffer[HUB_DESCRIPTOR_MAX_SIZE], *bitmap;
+	struct usb_hub_descriptor *descriptor;
+	struct usb_descriptor_header *header;
+	struct usb_hub_status *hubsts;
+	int i, ret;
+
+	/* Request the entire hub descriptor. */
+	header = (struct usb_descriptor_header *)buffer;
+	ret = usb_get_hub_descriptor(dev, buffer, sizeof(buffer));
+		/* <buffer> is large enough for a hub with 127 ports;
+		 * the hub can/will return fewer bytes here. */
+	if (ret < 0) {
+		err("Unable to get hub descriptor (err = %d)", ret);
+		return -1;
+	}
 
-	usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+	bitmap = kmalloc(header->bLength, GFP_KERNEL);
+	if (!bitmap) {
+		err("Unable to kmalloc %d bytes for bitmap", header->bLength);
+		return -1;
+	}
 
-	if (usb_get_hub_descriptor(dev, hubdescriptor, 8))
-		return;
+	memcpy (bitmap, buffer, header->bLength);
+	descriptor = (struct usb_hub_descriptor *)bitmap;
 
-	hub->nports = dev->maxchild = hubdescriptor[2];
-	printk("hub: %d-port%s detected\n", hub->nports,
-		(hub->nports == 1) ? "" : "s");
+	hub->nports = dev->maxchild = descriptor->bNbrPorts;
+	info("%d port%s detected", hub->nports, (hub->nports == 1) ? "" : "s");
 
-	charac = (hubdescriptor[4] << 8) + hubdescriptor[3];
-	switch (charac & HUB_CHAR_LPSM) {
+	switch (descriptor->wHubCharacteristics & HUB_CHAR_LPSM) {
 		case 0x00:
-			printk("hub: ganged power switching\n");
+			dbg("ganged power switching");
 			break;
 		case 0x01:
-			printk("hub: individual port power switching\n");
+			dbg("individual port power switching");
 			break;
 		case 0x02:
 		case 0x03:
-			printk("hub: unknown reserved power switching mode\n");
+			dbg("unknown reserved power switching mode");
 			break;
 	}
 
-	if (charac & HUB_CHAR_COMPOUND)
-		printk("hub: part of a compound device\n");
+	if (descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND)
+		dbg("part of a compound device");
 	else
-		printk("hub: standalone hub\n");
+		dbg("standalone hub");
 
-	switch (charac & HUB_CHAR_OCPM) {
+	switch (descriptor->wHubCharacteristics & HUB_CHAR_OCPM) {
 		case 0x00:
-			printk("hub: global over current protection\n");
+			dbg("global over-current protection");
 			break;
 		case 0x08:
-			printk("hub: individual port over current protection\n");
+			dbg("individual port over-current protection");
 			break;
 		case 0x10:
 		case 0x18:
-			printk("hub: no over current protection\n");
+			dbg("no over-current protection");
                         break;
 	}
 
-	printk("hub: power on to power good time: %dms\n",
-		hubdescriptor[5] * 2);
-
-	printk("hub: hub controller current requirement: %dmA\n",
-		hubdescriptor[6]);
+	dbg("power on to power good time: %dms", descriptor->bPwrOn2PwrGood * 2);
+	dbg("hub controller current requirement: %dmA", descriptor->bHubContrCurrent);
 
 	for (i = 0; i < dev->maxchild; i++)
-		printk("hub:  port %d is%s removable\n", i + 1,
-			hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8))
+		dbg("port %d is%s removable", i + 1,
+			bitmap[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8))
 			? " not" : "");
 
-	if (usb_get_hub_status(dev, buf))
-		return;
+	kfree(bitmap);
 
-	printk("hub: local power source is %s\n",
-		(buf[0] & 1) ? "lost (inactive)" : "good");
+	ret = usb_get_hub_status(dev, buffer);
+	if (ret < 0) {
+		err("Unable to get hub status (err = %d)", ret);
+		return -1;
+	}
 
-	printk("hub: %sover current condition exists\n",
-		(buf[0] & 2) ? "" : "no ");
+	hubsts = (struct usb_hub_status *)buffer;
+	dbg("local power source is %s",
+		(le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
 
-#if 0
-	for (i = 0; i < hub->nports; i++) {
-		int portstat, portchange;
-		unsigned char portstatus[4];
+	dbg("%sover-current condition exists",
+		(le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? "" : "no ");
 
-		if (usb_get_port_status(dev, i + 1, portstatus))
-			return;
-		portstat = (portstatus[1] << 8) + portstatus[0];
-		portchange = (portstatus[3] << 8) + portstatus[2];
+	usb_hub_power_on(hub);
 
-		printk("hub: port %d status\n", i + 1);
-		printk("hub:  %sdevice present\n", (portstat & 1) ? "" : "no ");
-		printk("hub:  %s\n", (portstat & 2) ? "enabled" : "disabled");
-		printk("hub:  %ssuspended\n", (portstat & 4) ? "" : "not ");
-		printk("hub:  %sover current\n", (portstat & 8) ? "" : "not ");
-		printk("hub:  has %spower\n", (portstat & 0x100) ? "" : "no ");
-		printk("hub:  %s speed\n", (portstat & 0x200) ? "low" : "full");
-	}
-#endif
-
-	/* Enable power to the ports */
-	printk("enabling power on all ports\n");
-	for (i = 0; i < hub->nports; i++)
-		usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+	return 0;
 }
 
-static int hub_probe(struct usb_device *dev)
+static void *hub_probe(struct usb_device *dev, unsigned int i)
 {
 	struct usb_interface_descriptor *interface;
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_hub *hub;
+	unsigned long flags;
+	unsigned int pipe;
+	int maxp, ret;
 
-	/* We don't handle multi-config hubs */
-	if (dev->descriptor.bNumConfigurations != 1)
-		return -1;
-
-	/* We don't handle multi-interface hubs */
-	if (dev->config[0].bNumInterfaces != 1)
-		return -1;
-
-	interface = &dev->config[0].interface[0];
+	interface = &dev->actconfig->interface[i].altsetting[0];
 
 	/* Is it a hub? */
-	if (interface->bInterfaceClass != 9)
-		return -1;
+	if (interface->bInterfaceClass != USB_CLASS_HUB)
+		return NULL;
+
+	/* Some hubs have a subclass of 1, which AFAICT according to the */
+	/*  specs is not defined, but it works */
 	if ((interface->bInterfaceSubClass != 0) &&
 	    (interface->bInterfaceSubClass != 1))
-		return -1;
+		return NULL;
 
 	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
 	if (interface->bNumEndpoints != 1)
-		return -1;
+		return NULL;
 
 	endpoint = &interface->endpoint[0];
 
 	/* Output endpoint? Curiousier and curiousier.. */
-	if (!(endpoint->bEndpointAddress & 0x80))
-		return -1;
+	if (!(endpoint->bEndpointAddress & USB_DIR_IN)) {
+		err("Device is hub class, but has output endpoint?");
+		return NULL;
+	}
 
 	/* If it's not an interrupt endpoint, we'd better punt! */
-	if ((endpoint->bmAttributes & 3) != 3)
-		return -1;
+	if ((endpoint->bmAttributes & 3) != 3) {
+		err("Device is hub class, but has endpoint other than interrupt?");
+		return NULL;
+	}
 
 	/* We found a hub */
-	printk("USB hub found\n");
+	info("USB hub found");
 
-	if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) {
-		printk("couldn't kmalloc hub struct\n");
-		return -1;
+	hub = kmalloc(sizeof(*hub), GFP_KERNEL);
+	if (!hub) {
+		err("couldn't kmalloc hub struct");
+		return NULL;
 	}
 
 	memset(hub, 0, sizeof(*hub));
 
-	dev->private = hub;
-
 	INIT_LIST_HEAD(&hub->event_list);
 	hub->dev = dev;
 
-	usb_hub_configure(hub);
+	/* Record the new hub's existence */
+	spin_lock_irqsave(&hub_event_lock, flags);
+	INIT_LIST_HEAD(&hub->hub_list);
+	list_add(&hub->hub_list, &hub_list);
+	spin_unlock_irqrestore(&hub_event_lock, flags);
 
-	usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
+	if (usb_hub_configure(hub) >= 0) {
+		pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+		maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+		if (maxp > sizeof(hub->buffer))
+			maxp = sizeof(hub->buffer);
+
+		hub->urb = usb_alloc_urb(0);
+		if (!hub->urb) {
+			err("couldn't allocate interrupt urb");
+			goto fail;
+		}
 
-	/* Wake up khubd */
-	wake_up(&usb_hub_wait);
+		FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq,
+			hub, endpoint->bInterval);
+		ret = usb_submit_urb(hub->urb);
+		if (ret) {
+			err("usb_submit_urb failed (%d)", ret);
+			goto fail;
+		}
 
-	return 0;
+		/* Wake up khubd */
+		wake_up(&khubd_wait);
+	}
+
+	return hub;
+
+fail:
+	/* free hub, but first clean up its list. */
+	spin_lock_irqsave(&hub_event_lock, flags);
+
+	/* Delete it and then reset it */
+	list_del(&hub->event_list);
+	INIT_LIST_HEAD(&hub->event_list);
+	list_del(&hub->hub_list);
+	INIT_LIST_HEAD(&hub->hub_list);
+
+	spin_unlock_irqrestore(&hub_event_lock, flags);
+
+	kfree(hub);
+
+	return NULL;
 }
 
-static void hub_disconnect(struct usb_device *dev)
+static void hub_disconnect(struct usb_device *dev, void *ptr)
 {
-	struct usb_hub *hub = dev->private;
+	struct usb_hub *hub = (struct usb_hub *)ptr;
 	unsigned long flags;
 
 	spin_lock_irqsave(&hub_event_lock, flags);
@@ -222,201 +319,478 @@
 	/* Delete it and then reset it */
 	list_del(&hub->event_list);
 	INIT_LIST_HEAD(&hub->event_list);
+	list_del(&hub->hub_list);
+	INIT_LIST_HEAD(&hub->hub_list);
 
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 
+	if (hub->urb) {
+		usb_unlink_urb(hub->urb);
+		usb_free_urb(hub->urb);
+		hub->urb = NULL;
+	}
+
 	/* Free the memory */
 	kfree(hub);
 }
 
+static int hub_ioctl (struct usb_device *hub, unsigned int code, void *user_data)
+{
+	/* assert ifno == 0 (part of hub spec) */
+	switch (code) {
+	case USBDEVFS_HUB_PORTINFO: {
+		struct usbdevfs_hub_portinfo *info = user_data;
+		unsigned long flags;
+		int i;
+
+		spin_lock_irqsave (&hub_event_lock, flags);
+		if (hub->devnum <= 0)
+			info->nports = 0;
+		else {
+			info->nports = hub->maxchild;
+			for (i = 0; i < info->nports; i++) {
+				if (hub->children [i] == NULL)
+					info->port [i] = 0;
+				else
+					info->port [i] = hub->children [i]->devnum;
+			}
+		}
+		spin_unlock_irqrestore (&hub_event_lock, flags);
+
+		return info->nports + 1;
+		}
+
+	default:
+		return -ENOSYS;
+	}
+}
+
 static void usb_hub_port_connect_change(struct usb_device *hub, int port)
 {
 	struct usb_device *usb;
-	unsigned char buf[4];
+ 	struct usb_port_status portsts;
 	unsigned short portstatus, portchange;
+	int ret, tries;
 
-	usb_disconnect(&hub->children[port]);
+	wait_ms(100);
 
-	usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
-
-	wait_ms(50);	/* FIXME: This is from the *BSD stack, thanks! :) */
-
-	if (usb_get_port_status(hub, port + 1, buf)) {
-		printk("get_port_status failed\n");
+	ret = usb_get_port_status(hub, port + 1, &portsts);
+	if (ret < 0) {
+		err("get_port_status(%d) failed (err = %d)", port + 1, ret);
 		return;
 	}
 
-	portstatus = *((unsigned short *)buf + 0);
-	portchange = *((unsigned short *)buf + 1);
+	portstatus = le16_to_cpu(portsts.wPortStatus);
+	portchange = le16_to_cpu(portsts.wPortChange);
+	dbg("portstatus %x, change %x, %s", portstatus, portchange,
+		portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s");
+
+	/* Clear the connection change status */
+	usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
+
+	/* Disconnect any existing devices under this port */
+	if (((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
+	     (!(portstatus & USB_PORT_STAT_ENABLE)))|| (hub->children[port])) {
+		usb_disconnect(&hub->children[port]);
+		/* Return now if nothing is connected */
+		if (!(portstatus & USB_PORT_STAT_CONNECTION))
+			return;
+	}
+	wait_ms(400);
+
+	down(&usb_address0_sem);
 
-	if ((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
-		(!(portstatus & USB_PORT_STAT_ENABLE))) {
-		/* We're done now, we already disconnected the device */
-		/* printk("not connected/enabled\n"); */
-		return;
+#define MAX_TRIES 5
+	/* Reset the port */
+	for (tries = 0; tries < MAX_TRIES ; tries++) {
+		usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
+		wait_ms(200);
+
+		ret = usb_get_port_status(hub, port + 1, &portsts);
+		if (ret < 0) {
+			err("get_port_status(%d) failed (err = %d)", port + 1, ret);
+			goto out;
+		}
+
+		portstatus = le16_to_cpu(portsts.wPortStatus);
+		portchange = le16_to_cpu(portsts.wPortChange);
+		dbg("portstatus %x, change %x, %s", portstatus ,portchange,
+			portstatus&(1<<USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s");
+
+		if ((portchange & USB_PORT_STAT_C_CONNECTION) ||
+		    !(portstatus & USB_PORT_STAT_CONNECTION))
+			goto out;
+
+		if (portstatus & USB_PORT_STAT_ENABLE)
+			break;
+
+		wait_ms(200);
 	}
 
-	usb = hub->bus->op->allocate(hub);
-	if (!usb) {
-		printk("couldn't allocate usb_device\n");
-		return;
+	if (tries >= MAX_TRIES) {
+		err("Cannot enable port %i after %i retries, disabling port.", port+1, MAX_TRIES);
+		err("Maybe the USB cable is bad?");
+		goto out;
 	}
 
-	usb_connect(usb);
+	usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET);
+
+	/* Allocate a new device struct for it */
+	usb = usb_alloc_dev(hub, hub->bus);
+	if (!usb) {
+		err("couldn't allocate usb_device");
+		goto out;
+	}
 
 	usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
 
 	hub->children[port] = usb;
 
-	usb_new_device(usb);
+	/* Find a new device ID for it */
+	usb_connect(usb);
+
+	/* Run it through the hoops (find a driver, etc) */
+	ret = usb_new_device(usb);
+	if (ret && usb->devnum != -1) {
+		/* Try resetting the device. Windows does this and it */
+		/*  gets some devices working correctly */
+		usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
+
+		ret = usb_new_device(usb);
+		if (ret) {
+			usb_disconnect(&hub->children[port]);
+
+			/* Woops, disable the port */
+			dbg("hub: disabling port %d", port + 1);
+			usb_clear_port_feature(hub, port + 1,
+				USB_PORT_FEAT_ENABLE);
+		}
+	}
+
+out:
+	up(&usb_address0_sem);
 }
 
 static void usb_hub_events(void)
 {
 	unsigned long flags;
-	unsigned char buf[4];
-	unsigned short portstatus, portchange;
 	int i;
-	struct list_head *next, *tmp, *head = &hub_event_list;
+	struct list_head *tmp;
 	struct usb_device *dev;
 	struct usb_hub *hub;
+	struct usb_hub_status hubsts;
+	unsigned short hubstatus, hubchange;
 
-	spin_lock_irqsave(&hub_event_lock, flags);
+	/*
+	 *  We restart the list everytime to avoid a deadlock with
+	 * deleting hubs downstream from this one. This should be
+	 * safe since we delete the hub from the event list.
+	 * Not the most efficient, but avoids deadlocks.
+	 */
+	while (1) {
+		spin_lock_irqsave(&hub_event_lock, flags);
+
+		if (list_empty(&hub_event_list))
+			goto he_unlock;
+
+		/* Grab the next entry from the beginning of the list */
+		tmp = hub_event_list.next;
 
-	tmp = head->next;
-	while (tmp != head) {
 		hub = list_entry(tmp, struct usb_hub, event_list);
 		dev = hub->dev;
 
-		next = tmp->next;
-
 		list_del(tmp);
 		INIT_LIST_HEAD(tmp);
 
+		spin_unlock_irqrestore(&hub_event_lock, flags);
+
 		for (i = 0; i < hub->nports; i++) {
-			if (usb_get_port_status(dev, i + 1, buf)) {
-				printk("get_port_status failed\n");
+			struct usb_port_status portsts;
+			unsigned short portstatus, portchange;
+
+			if (usb_get_port_status(dev, i + 1, &portsts) < 0) {
+				err("get_port_status failed");
 				continue;
 			}
 
-			portstatus = *((unsigned short *)buf + 0);
-			portchange = *((unsigned short *)buf + 1);
+			portstatus = le16_to_cpu(portsts.wPortStatus);
+			portchange = le16_to_cpu(portsts.wPortChange);
 
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
-				printk("hub: port %d connection change\n", i + 1);
-
-				usb_clear_port_feature(dev, i + 1,
-					USB_PORT_FEAT_C_CONNECTION);
+				dbg("port %d connection change", i + 1);
 
 				usb_hub_port_connect_change(dev, i);
 			}
 
 			if (portchange & USB_PORT_STAT_C_ENABLE) {
-				printk("hub: port %d enable change\n", i + 1);
-				usb_clear_port_feature(dev, i + 1,
-					USB_PORT_FEAT_C_ENABLE);
-			}
+				dbg("port %d enable change, status %x", i + 1, portstatus);
+				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
 
-			if (portchange & USB_PORT_STAT_C_SUSPEND)
-				printk("hub: port %d suspend change\n", i + 1);
+				// EM interference sometimes causes bad shielded USB devices to 
+				// be shutdown by the hub, this hack enables them again.
+				// Works at least with mouse driver. 
+				if (!(portstatus & USB_PORT_STAT_ENABLE) && 
+				    (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) {
+					err("already running port %i disabled by hub (EMI?), re-enabling...",
+						i + 1);
+					usb_hub_port_connect_change(dev, i);
+				}
+			}
 
-			if (portchange & USB_PORT_STAT_C_OVERCURRENT)
-				printk("hub: port %d over-current change\n", i + 1);
+			if (portstatus & USB_PORT_STAT_SUSPEND) {
+				dbg("port %d suspend change", i + 1);
+				usb_clear_port_feature(dev, i + 1,  USB_PORT_FEAT_SUSPEND);
+			}
+			
+			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
+				err("port %d over-current change", i + 1);
+				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+				usb_hub_power_on(hub);
+			}
 
 			if (portchange & USB_PORT_STAT_C_RESET) {
-				printk("hub: port %d reset change\n", i + 1);
-				usb_clear_port_feature(dev, i + 1,
-					USB_PORT_FEAT_C_RESET);
+				dbg("port %d reset change", i + 1);
+				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
 			}
+		} /* end for i */
 
-#if 0
-			if (!portchange)
-				continue;
-
-			if (usb_get_port_status(dev, i + 1, buf))
-				return;
-
-			portstatus = (buf[1] << 8) + buf[0];
-			portchange = (buf[3] << 8) + buf[2];
-
-			printk("hub: port %d status\n", i + 1);
-			printk("hub:  %sdevice present\n", (portstatus & 1) ? "" : "no ");
-			printk("hub:  %s\n", (portstatus & 2) ? "enabled" : "disabled");
-			printk("hub:  %ssuspended\n", (portstatus & 4) ? "" : "not ");
-			printk("hub:  %sover current\n", (portstatus & 8) ? "" : "not ");
-			printk("hub:  has %spower\n", (portstatus & 0x100) ? "" : "no ");
-			printk("hub:  %s speed\n", (portstatus & 0x200) ? "low" : "full");
-#endif
+		/* deal with hub status changes */
+		if (usb_get_hub_status(dev, &hubsts) < 0) {
+			err("get_hub_status failed");
+		} else {
+			hubstatus = le16_to_cpup(&hubsts.wHubStatus);
+			hubchange = le16_to_cpup(&hubsts.wHubChange);
+			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
+				dbg("hub power change");
+				usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
+			}
+			if (hubchange & HUB_CHANGE_OVERCURRENT) {
+				dbg("hub overcurrent change");
+				wait_ms(500); //Cool down
+				usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
+                        	usb_hub_power_on(hub);
+			}
 		}
-		tmp = next;
-#if 0
-		wait_ms(1000);
-#endif
-        }
+        } /* end while (1) */
 
+he_unlock:
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 }
 
 static int usb_hub_thread(void *__hub)
 {
+	khubd_running = 1;
+
 	lock_kernel();
 
 	/*
 	 * This thread doesn't need any user-level access,
 	 * so get rid of all our resources
 	 */
-	printk("usb_hub_thread at %p\n", &usb_hub_thread);
-	exit_mm(current);
-	exit_files(current);
-	exit_fs(current);
+	exit_files(current);  /* daemonize doesn't do exit_files */
+	daemonize();
 
 	/* Setup a nice name */
 	strcpy(current->comm, "khubd");
 
 	/* Send me a signal to get me die (for debugging) */
 	do {
-		interruptible_sleep_on(&usb_hub_wait);
 		usb_hub_events();
+		interruptible_sleep_on(&khubd_wait);
 	} while (!signal_pending(current));
 
-	printk("usb_hub_thread exiting\n");
+	dbg("usb_hub_thread exiting");
+	khubd_running = 0;
 
 	return 0;
 }
 
 static struct usb_driver hub_driver = {
-	"hub",
-	hub_probe,
-	hub_disconnect,
-	{ NULL, NULL }
+	name:		"hub",
+	probe:		hub_probe,
+	ioctl:		hub_ioctl,
+	disconnect:	hub_disconnect
 };
 
 /*
  * This should be a separate module.
  */
-int hub_init(void)
+int usb_hub_init(void)
 {
 	int pid;
 
-	INIT_LIST_HEAD(&hub_event_list);
+	if (usb_register(&hub_driver) < 0) {
+		err("Unable to register USB hub driver");
+		return -1;
+	}
 
-	usb_register(&hub_driver);
-	pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	pid = kernel_thread(usb_hub_thread, NULL,
+		CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	if (pid >= 0) {
 		khubd_pid = pid;
+
 		return 0;
 	}
 
 	/* Fall through if kernel_thread failed */
 	usb_deregister(&hub_driver);
 
-	return 0;
+	return -1;
 }
 
-void hub_cleanup(void)
+void usb_hub_cleanup(void)
 {
-	if (khubd_pid >= 0)
-		kill_proc(khubd_pid, SIGINT, 1);
+	int ret;
+
+	/* Kill the thread */
+	ret = kill_proc(khubd_pid, SIGTERM, 1);
+	if (!ret) {
+		/* Wait 10 seconds */
+		int count = 10 * 100;
+
+		while (khubd_running && --count) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+
+		if (!count)
+			err("giving up on killing khubd");
+	}
 
+	/*
+	 * Hub resources are freed for us by usb_deregister.  It
+	 * usb_driver_purge on every device which in turn calls that
+	 * devices disconnect function if it is using this driver.
+	 * The hub_disconnect function takes care of releasing the
+	 * individual hub resources. -greg
+	 */
 	usb_deregister(&hub_driver);
+} /* usb_hub_cleanup() */
+
+/*
+ * WARNING - If a driver calls usb_reset_device, you should simulate a
+ * disconnect() and probe() for other interfaces you doesn't claim. This
+ * is left up to the driver writer right now. This insures other drivers
+ * have a chance to re-setup their interface.
+ *
+ * Take a look at proc_resetdevice in devio.c for some sample code to
+ * do this.
+ */
+int usb_reset_device(struct usb_device *dev)
+{
+	struct usb_device *parent = dev->parent;
+	struct usb_device_descriptor descriptor;
+	int i, ret, port = -1;
+
+	if (!parent) {
+		err("attempting to reset root hub!");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < parent->maxchild; i++)
+		if (parent->children[i] == dev) {
+			port = i;
+			break;
+		}
+
+	if (port < 0)
+		return -ENOENT;
+
+	down(&usb_address0_sem);
+
+	/* Send a reset to the device */
+	usb_set_port_feature(parent, port + 1, USB_PORT_FEAT_RESET);
+
+	wait_ms(200);
+
+	usb_clear_port_feature(parent, port + 1, USB_PORT_FEAT_C_RESET);
+
+	/* Reprogram the Address */
+	ret = usb_set_address(dev);
+	if (ret < 0) {
+		err("USB device not accepting new address (error=%d)", ret);
+		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+		dev->devnum = -1;
+		up(&usb_address0_sem);
+		return ret;
+	}
+
+	wait_ms(10);	/* Let the SET_ADDRESS settle */
+
+	up(&usb_address0_sem);
+
+	/*
+	 * Now we fetch the configuration descriptors for the device and
+	 * see if anything has changed. If it has, we dump the current
+	 * parsed descriptors and reparse from scratch. Then we leave
+	 * the device alone for the caller to finish setting up.
+	 *
+	 * If nothing changed, we reprogram the configuration and then
+	 * the alternate settings.
+	 */
+	ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &descriptor,
+			sizeof(descriptor));
+	if (ret < 0)
+		return ret;
+
+	le16_to_cpus(&descriptor.bcdUSB);
+	le16_to_cpus(&descriptor.idVendor);
+	le16_to_cpus(&descriptor.idProduct);
+	le16_to_cpus(&descriptor.bcdDevice);
+
+	if (memcmp(&dev->descriptor, &descriptor, sizeof(descriptor))) {
+		usb_destroy_configuration(dev);
+
+		ret = usb_get_device_descriptor(dev);
+		if (ret < sizeof(dev->descriptor)) {
+			if (ret < 0)
+				err("unable to get device descriptor (error=%d)", ret);
+			else
+				err("USB device descriptor short read (expected %i, got %i)", sizeof(dev->descriptor), ret);
+        
+			clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+			dev->devnum = -1;
+			return -EIO;
+		}
+
+		ret = usb_get_configuration(dev);
+		if (ret < 0) {
+			err("unable to get configuration (error=%d)", ret);
+			clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+			dev->devnum = -1;
+			return 1;
+		}
+
+		dev->actconfig = dev->config;
+		usb_set_maxpacket(dev);
+
+		return 1;
+	} else {
+		ret = usb_set_configuration(dev,
+			dev->actconfig->bConfigurationValue);
+		if (ret < 0) {
+			err("failed to set active configuration (error=%d)",
+				ret);
+			return ret;
+		}
+
+		for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+			struct usb_interface *intf =
+				&dev->actconfig->interface[i];
+			struct usb_interface_descriptor *as =
+				&intf->altsetting[intf->act_altsetting];
+
+			ret = usb_set_interface(dev, as->bInterfaceNumber,
+				as->bAlternateSetting);
+			if (ret < 0) {
+				err("failed to set active alternate setting for interface %d (error=%d)", i, ret);
+				return ret;
+			}
+		}
+
+		return 0;
+	}
+
+	return 0;
 }
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hub.h linux.18p8/drivers/usb/hub.h
--- linux.vanilla/drivers/usb/hub.h	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/hub.h	Fri Sep  8 17:20:01 2000
@@ -4,7 +4,14 @@
 #include <linux/list.h>
 
 /*
- * Hub feature numbers
+ * Hub request types
+ */
+
+#define USB_RT_HUB	(USB_TYPE_CLASS | USB_RECIP_DEVICE)
+#define USB_RT_PORT	(USB_TYPE_CLASS | USB_RECIP_OTHER)
+
+/*
+ * Hub Class feature numbers
  */
 #define C_HUB_LOCAL_POWER	0
 #define C_HUB_OVER_CURRENT	1
@@ -12,6 +19,7 @@
 /*
  * Port feature numbers
  */
+#define USB_PORT_FEAT_CONNECTION	0
 #define USB_PORT_FEAT_ENABLE		1
 #define USB_PORT_FEAT_SUSPEND		2
 #define USB_PORT_FEAT_OVER_CURRENT	3
@@ -24,7 +32,12 @@
 #define USB_PORT_FEAT_C_OVER_CURRENT	19
 #define USB_PORT_FEAT_C_RESET		20
 
-/* wPortStatus */
+struct usb_port_status {
+	__u16 wPortStatus;
+	__u16 wPortChange;	
+} __attribute__ ((packed));
+
+/* wPortStatus bits */
 #define USB_PORT_STAT_CONNECTION	0x0001
 #define USB_PORT_STAT_ENABLE		0x0002
 #define USB_PORT_STAT_SUSPEND		0x0004
@@ -33,18 +46,46 @@
 #define USB_PORT_STAT_POWER		0x0100
 #define USB_PORT_STAT_LOW_SPEED		0x0200
 
-/* wPortChange */
+/* wPortChange bits */
 #define USB_PORT_STAT_C_CONNECTION	0x0001
 #define USB_PORT_STAT_C_ENABLE		0x0002
 #define USB_PORT_STAT_C_SUSPEND		0x0004
 #define USB_PORT_STAT_C_OVERCURRENT	0x0008
 #define USB_PORT_STAT_C_RESET		0x0010
 
-/* Characteristics */
+/* wHubCharacteristics (masks) */
 #define HUB_CHAR_LPSM		0x0003
 #define HUB_CHAR_COMPOUND	0x0004
 #define HUB_CHAR_OCPM		0x0018
 
+struct usb_hub_status {
+	__u16 wHubStatus;
+	__u16 wHubChange;
+} __attribute__ ((packed));
+
+/*
+ *Hub Status & Hub Change bit masks
+ */
+#define HUB_STATUS_LOCAL_POWER	0x0001
+#define HUB_STATUS_OVERCURRENT	0x0002
+
+#define HUB_CHANGE_LOCAL_POWER	0x0001
+#define HUB_CHANGE_OVERCURRENT	0x0002
+
+#define HUB_DESCRIPTOR_MAX_SIZE	39	/* enough for 127 ports on a hub */
+
+/* Hub descriptor */
+struct usb_hub_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bNbrPorts;
+	__u16 wHubCharacteristics;
+	__u8  bPwrOn2PwrGood;
+	__u8  bHubContrCurrent;
+	/* DeviceRemovable and PortPwrCtrlMask want to be variable-length 
+	   bitmaps that hold max 256 entries, but for now they're ignored */
+} __attribute__ ((packed));
+
 struct usb_device;
 
 typedef enum {
@@ -67,6 +108,14 @@
 	/* Device structure */
 	struct usb_device *dev;
 
+	/* Interrupt polling pipe */
+	struct urb *urb;
+
+	char buffer[USB_MAXCHILDREN / 8];
+
+	/* List of hubs */
+	struct list_head hub_list;
+
 	/* Temporary event list */
 	struct list_head event_list;
 
@@ -77,4 +126,3 @@
 };
 
 #endif
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ibmcam.c linux.18p8/drivers/usb/ibmcam.c
--- linux.vanilla/drivers/usb/ibmcam.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/ibmcam.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,3146 @@
+/*
+ * USB IBM C-It Video Camera driver
+ *
+ * Supports IBM C-It Video Camera.
+ *
+ * This driver is based on earlier work of:
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ *
+ * 5/24/00 Removed optional (and unnecessary) locking of the driver while
+ * the device remains plugged in. Corrected race conditions in ibmcam_open
+ * and ibmcam_probe() routines using this as a guideline:
+ *
+ * (2) The big kernel lock is automatically released when a process sleeps
+ *   in the kernel and is automatically reacquired on reschedule if the
+ *   process had the lock originally.  Any code that can be compiled as
+ *   a module and is entered with the big kernel lock held *MUST*
+ *   increment the use count to activate the indirect module protection
+ *   before doing anything that might sleep.
+ *
+ *   In practice, this means that all routines that live in modules and
+ *   are invoked under the big kernel lock should do MOD_INC_USE_COUNT
+ *   as their very first action.  And all failure paths from that
+ *   routine must do MOD_DEC_USE_COUNT before returning.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/videodev.h>
+#include <linux/vmalloc.h>
+#include <linux/wrapper.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#include <asm/io.h>
+
+#include "ibmcam.h"
+
+#define	ENABLE_HEXDUMP	0	/* Enable if you need it */
+static int debug = 0;
+
+/* Completion states of the data parser */
+typedef enum {
+	scan_Continue,		/* Just parse next item */
+	scan_NextFrame,		/* Frame done, send it to V4L */
+	scan_Out,		/* Not enough data for frame */
+	scan_EndParse		/* End parsing */
+} scan_state_t;
+
+/* Bit flags (options) */
+#define FLAGS_RETRY_VIDIOCSYNC		(1 << 0)
+#define	FLAGS_MONOCHROME		(1 << 1)
+#define FLAGS_DISPLAY_HINTS		(1 << 2)
+#define FLAGS_OVERLAY_STATS		(1 << 3)
+#define FLAGS_FORCE_TESTPATTERN		(1 << 4)
+#define FLAGS_SEPARATE_FRAMES		(1 << 5)
+#define FLAGS_CLEAN_FRAMES		(1 << 6)
+
+static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
+
+/* This is the size of V4L frame that we provide */
+static const int imgwidth = V4L_FRAME_WIDTH_USED;
+static const int imgheight = V4L_FRAME_HEIGHT;
+static const int min_imgwidth  = 8;
+static const int min_imgheight = 4;
+
+static int lighting = 1; /* Medium */
+
+#define SHARPNESS_MIN	0
+#define SHARPNESS_MAX	6
+static int sharpness = 4; /* Low noise, good details */
+
+#define FRAMERATE_MIN	0
+#define FRAMERATE_MAX	6
+static int framerate = 2; /* Lower, reliable frame rate (8-12 fps) */
+
+enum {
+	VIDEOSIZE_128x96 = 0,
+	VIDEOSIZE_176x144,
+	VIDEOSIZE_352x288,
+	VIDEOSIZE_320x240,
+	VIDEOSIZE_352x240,
+};
+
+static int videosize = VIDEOSIZE_352x288;
+
+/*
+ * The value of 'scratchbufsize' affects quality of the picture
+ * in many ways. Shorter buffers may cause loss of data when client
+ * is too slow. Larger buffers are memory-consuming and take longer
+ * to work with. This setting can be adjusted, but the default value
+ * should be OK for most desktop users.
+ */
+#define DEFAULT_SCRATCH_BUF_SIZE	(0x10000)	/* 64 KB */
+static const int scratchbufsize = DEFAULT_SCRATCH_BUF_SIZE;
+
+/*
+ * Here we define several initialization variables. They may
+ * be used to automatically set color, hue, brightness and
+ * contrast to desired values. This is particularly useful in
+ * case of webcams (which have no controls and no on-screen
+ * output) and also when a client V4L software is used that
+ * does not have some of those controls. In any case it's
+ * good to have startup values as options.
+ *
+ * These values are all in [0..255] range. This simplifies
+ * operation. Note that actual values of V4L variables may
+ * be scaled up (as much as << 8). User can see that only
+ * on overlay output, however, or through a V4L client.
+ */
+static int init_brightness = 128;
+static int init_contrast = 192;
+static int init_color = 128;
+static int init_hue = 128;
+static int hue_correction = 128;
+
+/* Settings for camera model 2 */
+static int init_model2_rg = -1;
+static int init_model2_rg2 = -1;
+static int init_model2_sat = -1;
+static int init_model2_yb = -1;
+
+MODULE_PARM(debug, "i");
+MODULE_PARM(flags, "i");
+MODULE_PARM(framerate, "i");
+MODULE_PARM(lighting, "i");
+MODULE_PARM(sharpness, "i");
+MODULE_PARM(videosize, "i");
+MODULE_PARM(init_brightness, "i");
+MODULE_PARM(init_contrast, "i");
+MODULE_PARM(init_color, "i");
+MODULE_PARM(init_hue, "i");
+MODULE_PARM(hue_correction, "i");
+
+MODULE_PARM(init_model2_rg, "i");
+MODULE_PARM(init_model2_rg2, "i");
+MODULE_PARM(init_model2_sat, "i");
+MODULE_PARM(init_model2_yb, "i");
+
+MODULE_AUTHOR ("module author");
+MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");
+
+/* Still mysterious i2c commands */
+static const unsigned short unknown_88 = 0x0088;
+static const unsigned short unknown_89 = 0x0089;
+static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 };
+static const unsigned short contrast_14 = 0x0014;
+static const unsigned short light_27 = 0x0027;
+static const unsigned short sharp_13 = 0x0013;
+
+/* i2c commands for Model 2 cameras */
+static const unsigned short mod2_brightness = 0x001a;		/* $5b .. $ee; default=$5a */
+static const unsigned short mod2_set_framerate = 0x001c;	/* 0 (fast).. $1F (slow) */
+static const unsigned short mod2_color_balance_rg2 = 0x001e;	/* 0 (red) .. $7F (green) */
+static const unsigned short mod2_saturation = 0x0020;		/* 0 (b/w) - $7F (full color) */
+static const unsigned short mod2_color_balance_yb = 0x0022;	/* 0..$7F, $50 is about right */
+static const unsigned short mod2_color_balance_rg = 0x0024;	/* 0..$7F, $70 is about right */
+static const unsigned short mod2_sensitivity = 0x0028;		/* 0 (min) .. $1F (max) */
+
+#define MAX_IBMCAM	4
+
+struct usb_ibmcam cams[MAX_IBMCAM];
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+#define MDEBUG(x)	do { } while(0)		/* Debug memory management */
+
+static struct usb_driver ibmcam_driver;
+static void usb_ibmcam_release(struct usb_ibmcam *ibmcam);
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+	unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+
+	if (!pgd_none(*pgd)) {
+		pmd = pmd_offset(pgd, adr);
+		if (!pmd_none(*pmd)) {
+			ptep = pte_offset(pmd, adr);
+			pte = *ptep;
+			if (pte_present(pte))
+				ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1));
+		}
+	}
+	MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));
+	return ret;
+}
+
+static inline unsigned long uvirt_to_bus(unsigned long adr)
+{
+	unsigned long kva, ret;
+
+	kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);
+	ret = virt_to_bus((void *)kva);
+	MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
+	return ret;
+}
+
+static inline unsigned long kvirt_to_bus(unsigned long adr)
+{
+	unsigned long va, kva, ret;
+
+	va = VMALLOC_VMADDR(adr);
+	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = virt_to_bus((void *)kva);
+	MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long va, kva, ret;
+
+	va = VMALLOC_VMADDR(adr);
+	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = __pa(kva);
+	MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));
+	return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr, page;
+
+	/* Round it off to PAGE_SIZE */
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	mem = vmalloc_32(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+		mem_map_reserve(MAP_NR(__va(page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+	unsigned long adr, page;
+
+	if (!mem)
+		return;
+
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	adr=(unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+		mem_map_unreserve(MAP_NR(__va(page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+	vfree(mem);
+}
+
+#if ENABLE_HEXDUMP
+static void ibmcam_hexdump(const unsigned char *data, int len)
+{
+	char tmp[80];
+	int i, k;
+
+	for (i=k=0; len > 0; i++, len--) {
+		if (i > 0 && (i%16 == 0)) {
+			printk("%s\n", tmp);
+			k=0;
+		}
+		k += sprintf(&tmp[k], "%02x ", data[i]);
+	}
+	if (k > 0)
+		printk("%s\n", tmp);
+}
+#endif
+
+/*
+ * usb_ibmcam_overlaychar()
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+void usb_ibmcam_overlaychar(
+	struct usb_ibmcam *ibmcam,
+	struct ibmcam_frame *frame,
+	int x, int y, int ch)
+{
+	static const unsigned short digits[16] = {
+		0xF6DE, /* 0 */
+		0x2492, /* 1 */
+		0xE7CE, /* 2 */
+		0xE79E, /* 3 */
+		0xB792, /* 4 */
+		0xF39E, /* 5 */
+		0xF3DE, /* 6 */
+		0xF492, /* 7 */
+		0xF7DE, /* 8 */
+		0xF79E, /* 9 */
+		0x77DA, /* a */
+		0xD75C, /* b */
+		0xF24E, /* c */
+		0xD6DC, /* d */
+		0xF34E, /* e */
+		0xF348  /* f */
+	};
+	unsigned short digit;
+	int ix, iy;
+
+	if ((ibmcam == NULL) || (frame == NULL))
+		return;
+
+	if (ch >= '0' && ch <= '9')
+		ch -= '0';
+	else if (ch >= 'A' && ch <= 'F')
+		ch = 10 + (ch - 'A');
+	else if (ch >= 'a' && ch <= 'f')
+		ch = 10 + (ch - 'a');
+	else
+		return;
+	digit = digits[ch];
+
+	for (iy=0; iy < 5; iy++) {
+		for (ix=0; ix < 3; ix++) {
+			if (digit & 0x8000) {
+				IBMCAM_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
+			}
+			digit = digit << 1;
+		}
+	}
+}
+
+/*
+ * usb_ibmcam_overlaystring()
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+void usb_ibmcam_overlaystring(
+	struct usb_ibmcam *ibmcam,
+	struct ibmcam_frame *frame,
+	int x, int y, const char *str)
+{
+	while (*str) {
+		usb_ibmcam_overlaychar(ibmcam, frame, x, y, *str);
+		str++;
+		x += 4; /* 3 pixels character + 1 space */
+	}
+}
+
+/*
+ * usb_ibmcam_overlaystats()
+ *
+ * Overlays important debugging information.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+void usb_ibmcam_overlaystats(struct usb_ibmcam *ibmcam, struct ibmcam_frame *frame)
+{
+	const int y_diff = 8;
+	char tmp[16];
+	int x = 10;
+	int y = 10;
+
+	sprintf(tmp, "%8x", ibmcam->frame_num);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8lx", ibmcam->urb_count);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8lx", ibmcam->urb_length);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8lx", ibmcam->data_count);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8lx", ibmcam->header_count);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8lx", ibmcam->scratch_ovf_count);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8lx", ibmcam->iso_skip_count);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8lx", ibmcam->iso_err_count);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8x", ibmcam->vpic.colour);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8x", ibmcam->vpic.hue);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8x", ibmcam->vpic.brightness >> 8);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8x", ibmcam->vpic.contrast >> 12);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+
+	sprintf(tmp, "%8d", ibmcam->vpic.whiteness >> 8);
+	usb_ibmcam_overlaystring(ibmcam, frame, x, y, tmp);
+	y += y_diff;
+}
+
+/*
+ * usb_ibmcam_testpattern()
+ *
+ * Procedure forms a test pattern (yellow grid on blue background).
+ *
+ * Parameters:
+ * fullframe:   if TRUE then entire frame is filled, otherwise the procedure
+ *	      continues from the current scanline.
+ * pmode	0: fill the frame with solid blue color (like on VCR or TV)
+ *	      1: Draw a colored grid
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+void usb_ibmcam_testpattern(struct usb_ibmcam *ibmcam, int fullframe, int pmode)
+{
+	static const char proc[] = "usb_ibmcam_testpattern";
+	struct ibmcam_frame *frame;
+	unsigned char *f;
+	int num_cell = 0;
+	int scan_length = 0;
+	static int num_pass = 0;
+
+	if (ibmcam == NULL) {
+		printk(KERN_ERR "%s: ibmcam == NULL\n", proc);
+		return;
+	}
+	if ((ibmcam->curframe < 0) || (ibmcam->curframe >= IBMCAM_NUMFRAMES)) {
+		printk(KERN_ERR "%s: ibmcam->curframe=%d.\n", proc, ibmcam->curframe);
+		return;
+	}
+
+	/* Grab the current frame */
+	frame = &ibmcam->frame[ibmcam->curframe];
+
+	/* Optionally start at the beginning */
+	if (fullframe) {
+		frame->curline = 0;
+		frame->scanlength = 0;
+	}
+
+	/* Form every scan line */
+	for (; frame->curline < imgheight; frame->curline++) {
+		int i;
+
+		f = frame->data + (imgwidth * 3 * frame->curline);
+		for (i=0; i < imgwidth; i++) {
+			unsigned char cb=0x80;
+			unsigned char cg = 0;
+			unsigned char cr = 0;
+
+			if (pmode == 1) {
+				if (frame->curline % 32 == 0)
+					cb = 0, cg = cr = 0xFF;
+				else if (i % 32 == 0) {
+					if (frame->curline % 32 == 1)
+						num_cell++;
+					cb = 0, cg = cr = 0xFF;
+				} else {
+					cb = ((num_cell*7) + num_pass) & 0xFF;
+					cg = ((num_cell*5) + num_pass*2) & 0xFF;
+					cr = ((num_cell*3) + num_pass*3) & 0xFF;
+				}
+			} else {
+				/* Just the blue screen */
+			}
+				
+			*f++ = cb;
+			*f++ = cg;
+			*f++ = cr;
+			scan_length += 3;
+		}
+	}
+
+	frame->grabstate = FRAME_DONE;
+	frame->scanlength += scan_length;
+	++num_pass;
+
+	/* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */
+	usb_ibmcam_overlaystats(ibmcam, frame);
+}
+
+static unsigned char *ibmcam_model1_find_header(unsigned char hdr_sig, unsigned char *data, int len)
+{
+	while (len >= 4)
+	{
+		if ((data[0] == 0x00) && (data[1] == 0xFF) && (data[2] == 0x00))
+		{
+#if 0
+			/* This code helps to detect new frame markers */
+			printk(KERN_DEBUG "Header sig: 00 FF 00 %02X\n", data[3]);
+#endif
+			if (data[3] == hdr_sig) {
+				if (debug > 2)
+					printk(KERN_DEBUG "Header found.\n");
+				return data+4;
+			}
+		}
+		++data;
+		--len;
+	}
+	return NULL;
+}
+
+static unsigned char *ibmcam_model2_find_header(unsigned char hdr_sig, unsigned char *data, int len)
+{
+	int marker_len = 0;
+
+	switch (videosize) {
+	case VIDEOSIZE_176x144:
+		marker_len = 10;
+		break;
+	default:
+		marker_len = 2;
+		break;
+	}
+	while (len >= marker_len)
+	{
+		if ((data[0] == 0x00) && (data[1] == 0xFF))
+		{
+#if 0
+			/* This code helps to detect new frame markers */
+			static int pass = 0;
+			if (pass++ == 0)
+				ibmcam_hexdump(data, (len > 16) ? 16 : len);
+#endif
+			if (debug > 2)
+				printk(KERN_DEBUG "Header found.\n");
+			return data+marker_len;
+		}
+		++data;
+		--len;
+	}
+	return NULL;
+}
+
+/* How much data is left in the scratch buf? */
+#define scratch_left(x)	(ibmcam->scratchlen - (int)((char *)x - (char *)ibmcam->scratch))
+
+/* Grab the remaining */
+static void usb_ibmcam_align_scratch(struct usb_ibmcam *ibmcam, unsigned char *data)
+{
+	unsigned long left;
+
+	left = scratch_left(data);
+	memmove(ibmcam->scratch, data, left);
+	ibmcam->scratchlen = left;
+}
+
+/*
+ * usb_ibmcam_find_header()
+ *
+ * Locate one of supported header markers in the scratch buffer.
+ * Once found, remove all preceding bytes AND the marker (4 bytes)
+ * from the scratch buffer. Whatever follows must be video lines.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static scan_state_t usb_ibmcam_find_header(struct usb_ibmcam *ibmcam)
+{
+	struct ibmcam_frame *frame;
+	unsigned char *data, *tmp;
+
+	data = ibmcam->scratch;
+	frame = &ibmcam->frame[ibmcam->curframe];
+
+	if (ibmcam->camera_model == IBMCAM_MODEL_1)
+		tmp = ibmcam_model1_find_header(frame->hdr_sig, data, scratch_left(data));
+	else if (ibmcam->camera_model == IBMCAM_MODEL_2)
+		tmp = ibmcam_model2_find_header(frame->hdr_sig, data, scratch_left(data));
+	else
+		tmp = NULL;
+
+	if (tmp == NULL) {
+		/* No header - entire scratch buffer is useless! */
+		if (debug > 2)
+			printk(KERN_DEBUG "Skipping frame, no header\n");
+		ibmcam->scratchlen = 0;
+		return scan_EndParse;
+	}
+	/* Header found */
+	data = tmp;
+
+	ibmcam->has_hdr = 1;
+	ibmcam->header_count++;
+	frame->scanstate = STATE_LINES;
+	frame->curline = 0;
+
+	if (flags & FLAGS_FORCE_TESTPATTERN) {
+		usb_ibmcam_testpattern(ibmcam, 1, 1);
+		return scan_NextFrame;
+	}
+	usb_ibmcam_align_scratch(ibmcam, data);
+	return scan_Continue;
+}
+
+/*
+ * usb_ibmcam_parse_lines()
+ *
+ * Parse one line (TODO: more than one!) from the scratch buffer, put
+ * decoded RGB value into the current frame buffer and add the written
+ * number of bytes (RGB) to the *pcopylen.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static scan_state_t usb_ibmcam_parse_lines(struct usb_ibmcam *ibmcam, long *pcopylen)
+{
+	struct ibmcam_frame *frame;
+	unsigned char *data, *f, *chromaLine;
+	unsigned int len;
+	const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL;	/* V4L line offset */
+	const int hue_corr  = (ibmcam->vpic.hue - 0x8000) >> 10;	/* -32..+31 */
+	const int hue2_corr = (hue_correction - 128) / 4;		/* -32..+31 */
+	const int ccm = 128; /* Color correction median - see below */
+	int y, u, v, i, frame_done=0, mono_plane, color_corr;
+
+	color_corr = (ibmcam->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
+	RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
+	data = ibmcam->scratch;
+	frame = &ibmcam->frame[ibmcam->curframe];
+
+	len = frame->frmwidth * 3; /* 1 line of mono + 1 line of color */
+	/*printk(KERN_DEBUG "len=%d. left=%d.\n",len,scratch_left(data));*/
+
+	mono_plane = ((frame->curline & 1) == 0);
+
+	/*
+	 * Lines are organized this way (or are they?)
+	 *
+	 * I420:
+	 * ~~~~
+	 * ___________________________________
+	 * |-----Y-----|---UVUVUV...UVUV-----| \
+	 * |-----------+---------------------|  \
+	 * |<-- 176 -->|<------ 176*2 ------>|  Total 72. pairs of lines
+	 * |...	   ...	     ...|  /
+	 * |___________|_____________________| /
+	 *  - odd line- ------- even line ---
+	 *
+	 * another format:
+	 * ~~~~~~~~~~~~~~
+	 * ___________________________________
+	 * |-----Y-----|---UVUVUV...UVUV-----| \
+	 * |-----------+---------------------|  \
+	 * |<-- 352 -->|<------ 352*2 ------>|  Total 144. pairs of lines
+	 * |...	   ...	     ...|  /
+	 * |___________|_____________________| /
+	 *  - odd line- ------- even line ---
+	 */
+
+	/* Make sure there's enough data for the entire line */
+	if (scratch_left(data) < (len+1024)) {
+		/*printk(KERN_DEBUG "out of data, need %u.\n", len);*/
+		return scan_Out;
+	}
+
+#if 0
+	{	/* This code prints beginning of the source frame */
+		static int pass = 0;
+		if ((pass++ % 3000) == 0)
+			ibmcam_hexdump(data, 16);
+	}
+#endif
+
+#if 0
+	if (frame->curline == 10 || frame->curline == 11) {
+		/* This code prints beginning of 10th (mono), 11th (chroma) line */
+		static int pass = 0;
+		if ((pass % 100) == 0)
+			ibmcam_hexdump(data, 16);
+		if (frame->curline == 11)
+			pass++;
+	}
+#endif
+	/*
+	 * Make sure that our writing into output buffer
+	 * will not exceed the buffer. Mind that we may write
+	 * not into current output scanline but in several after
+	 * it as well (if we enlarge image vertically.)
+	 */
+	if ((frame->curline + 1) >= V4L_FRAME_HEIGHT)
+		return scan_NextFrame;
+
+	/*
+	 * Now we are sure that entire line (representing all 'frame->frmwidth'
+	 * pixels from the camera) is available in the scratch buffer. We
+	 * start copying the line left-aligned to the V4L buffer (which
+	 * might be larger - not smaller, hopefully). If the camera
+	 * line is shorter then we should pad the V4L buffer with something
+	 * (black in this case) to complete the line.
+	 */
+	f = frame->data + (v4l_linesize * frame->curline);
+
+	/*
+	 * chromaLine points to 1st pixel of the line with chrominance.
+	 * If current line is monochrome then chromaLine points to next
+	 * line after monochrome one. If current line has chrominance
+	 * then chromaLine points to this very line. Such method allows
+	 * to access chrominance data uniformly.
+	 *
+	 * To obtain chrominance data from the 'chromaLine' use this:
+	 *   v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]...
+	 *   u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]...
+	 *
+	 * Indices must be calculated this way:
+	 * v_index = (i >> 1) << 2;
+	 * u_index = (i >> 1) << 2 + 2;
+	 *
+	 * where 'i' is the column number [0..frame->frmwidth-1]
+	 */
+	chromaLine = data;
+	if (mono_plane)
+		chromaLine += frame->frmwidth;
+
+	for (i = 0; i < frame->frmwidth; i++, data += (mono_plane ? 1 : 2))
+	{
+		unsigned char rv, gv, bv;	/* RGB components */
+
+		/*
+		 * Search for potential Start-Of-Frame marker. It should
+		 * not be here, of course, but if your formats don't match
+		 * you might exceed the frame. We must match the marker to
+		 * each byte of multi-byte data element if it is multi-byte.
+		 */
+#if 1
+		if ((ibmcam->camera_model == IBMCAM_MODEL_1) && (scratch_left(data) >= (4+2))) {
+			unsigned char *dp;
+			int j;
+
+			for (j=0, dp=data; j < 2; j++, dp++) {
+				if ((dp[0] == 0x00) && (dp[1] == 0xFF) &&
+				    (dp[2] == 0x00) && (dp[3] == frame->hdr_sig)) {
+					ibmcam->has_hdr = 2;
+					frame_done++;
+					break;
+				}
+			}
+		}
+#endif
+
+		/* Check for various visual debugging hints (colorized pixels) */
+		if ((flags & FLAGS_DISPLAY_HINTS) && (ibmcam->has_hdr)) {
+			/*
+			 * This is bad and should not happen. This means that
+			 * we somehow overshoot the line and encountered new
+			 * frame! Obviously our camera/V4L frame size is out
+			 * of whack. This cyan dot will help you to figure
+			 * out where exactly the new frame arrived.
+			 */
+			if (ibmcam->has_hdr == 1) {
+				bv = 0; /* Yellow marker */
+				gv = 0xFF;
+				rv = 0xFF;
+			} else {
+				bv = 0xFF; /* Cyan marker */
+				gv = 0xFF;
+				rv = 0;
+			}
+			ibmcam->has_hdr = 0;
+			goto make_pixel;
+		}
+
+		if (mono_plane || frame->order_yc)
+			y = data[0];
+		else
+			y = data[1];
+
+		if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
+			rv = gv = bv = y;
+		else {
+			int off_0, off_2;
+
+			off_0 = (i >> 1) << 2;
+			off_2 = off_0 + 2;
+
+			if (frame->order_yc) {
+				off_0++;
+				off_2++;
+			}
+			if (!frame->order_uv) {
+				off_0 += 2;
+				off_2 -= 2;
+			}
+			u = chromaLine[off_0] + hue_corr;
+			v = chromaLine[off_2] + hue2_corr;
+
+			/* Apply color correction */
+			if (color_corr != 0) {
+				/* Magnify up to 2 times, reduce down to zero saturation */
+				u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
+				v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
+			}
+			YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+		}
+
+	make_pixel:
+		/*
+		 * The purpose of creating the pixel here, in one,
+		 * dedicated place is that we may need to make the
+		 * pixel wider and taller than it actually is. This
+		 * may be used if camera generates small frames for
+		 * sake of frame rate (or any other reason.)
+		 *
+		 * The output data consists of B, G, R bytes
+		 * (in this order).
+		 */
+#if USES_IBMCAM_PUTPIXEL
+		IBMCAM_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+#else
+		*f++ = bv;
+		*f++ = gv;
+		*f++ = rv;
+#endif
+		/*
+		 * Typically we do not decide within a legitimate frame
+		 * that we want to end the frame. However debugging code
+		 * may detect marker of new frame within the data. Then
+		 * this condition activates. The 'data' pointer is already
+		 * pointing at the new marker, so we'd better leave it as is.
+		 */
+		if (frame_done)
+			break;	/* End scanning of lines */
+	}
+	/*
+	 * Account for number of bytes that we wrote into output V4L frame.
+	 * We do it here, after we are done with the scanline, because we
+	 * may fill more than one output scanline if we do vertical
+	 * enlargement.
+	 */
+	frame->curline++;
+	*pcopylen += v4l_linesize;
+	usb_ibmcam_align_scratch(ibmcam, data);
+
+	if (frame_done || (frame->curline >= frame->frmheight))
+		return scan_NextFrame;
+	else
+		return scan_Continue;
+}
+
+/*
+ * usb_ibmcam_model2_parse_lines()
+ *
+ * This procedure deals with a weird RGB format that is produced by IBM
+ * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175,
+ * depending on horizontal size of the picture:
+ *
+ * <--- 160 or 176 pairs of RA,RB bytes ----->
+ * *-----------------------------------------* \
+ * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx |  \
+ * |-----+-----+-----+-----+ ... +-----+-----|   *- This is pair of horizontal lines,
+ * | B0  | G0  | B1  | G1  | ... | Bx  | Gx  |  /   total 240 or 288 lines (120 or 144
+ * |=====+=====+=====+=====+ ... +=====+=====| /    such pairs).
+ *
+ * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1
+ * defines ONE pixel. Therefore this format yields 176x144 "decoded"
+ * resolution at best. I do not know why camera sends such format - the
+ * previous model just used I420 and everyone was happy.
+ *
+ * I do not know what is the difference between RAi and RBi bytes. Both
+ * seemingly represent R component, but slightly vary in value (so that
+ * the picture looks a bit colored if one or another is used). I use
+ * them both as R component in attempt to at least partially recover the
+ * lost resolution.
+ */
+static scan_state_t usb_ibmcam_model2_parse_lines(struct usb_ibmcam *ibmcam, long *pcopylen)
+{
+	struct ibmcam_frame *frame;
+	unsigned char *data, *f, *la, *lb;
+	unsigned int len;
+	const int v4l_linesize = imgwidth * V4L_BYTES_PER_PIXEL;	/* V4L line offset */
+	int i, j, frame_done=0, color_corr;
+
+	color_corr = (ibmcam->vpic.colour) >> 8; /* 0..+255 */
+
+	data = ibmcam->scratch;
+	frame = &ibmcam->frame[ibmcam->curframe];
+
+	/* Here we deal with pairs of horizontal lines */
+
+	len = frame->frmwidth * 2; /* 2 lines */
+	/*printk(KERN_DEBUG "len=%d. left=%d.\n",len,scratch_left(data));*/
+
+	/* Make sure there's enough data for the entire line */
+	if (scratch_left(data) < (len+32)) {
+		/*printk(KERN_DEBUG "out of data, need %u.\n", len);*/
+		return scan_Out;
+	}
+
+	/*
+	 * Make sure that our writing into output buffer
+	 * will not exceed the buffer. Mind that we may write
+	 * not into current output scanline but in several after
+	 * it as well (if we enlarge image vertically.)
+	 */
+	if ((frame->curline + 1) >= V4L_FRAME_HEIGHT)
+		return scan_NextFrame;
+
+	if ((frame->curline & 1) == 0) {
+		la = data;
+		lb = data + frame->frmwidth;
+	} else {
+		la = data + frame->frmwidth;
+		lb = data;
+	}
+
+	/*
+	 * Now we are sure that entire line (representing all 'frame->frmwidth'
+	 * pixels from the camera) is available in the scratch buffer. We
+	 * start copying the line left-aligned to the V4L buffer (which
+	 * might be larger - not smaller, hopefully). If the camera
+	 * line is shorter then we should pad the V4L buffer with something
+	 * (black in this case) to complete the line.
+	 */
+	f = frame->data + (v4l_linesize * frame->curline);
+
+	/* Fill the 2-line strip */
+	for (i = 0; i < frame->frmwidth; i++) {
+		int y, rv, gv, bv;	/* RGB components */
+
+		j = i & (~1);
+
+		/* Check for various visual debugging hints (colorized pixels) */
+		if ((flags & FLAGS_DISPLAY_HINTS) && (ibmcam->has_hdr)) {
+			if (ibmcam->has_hdr == 1) {
+				bv = 0; /* Yellow marker */
+				gv = 0xFF;
+				rv = 0xFF;
+			} else {
+				bv = 0xFF; /* Cyan marker */
+				gv = 0xFF;
+				rv = 0;
+			}
+			ibmcam->has_hdr = 0;
+			goto make_pixel;
+		}
+
+		/*
+		 * Here I use RA and RB components, one per physical pixel.
+		 * This causes fine vertical grid on the picture but may improve
+		 * horizontal resolution. If you prefer replicating, use this:
+		 *   rv = la[j + 0];   ... or ... rv = la[j + 1];
+		 * then the pixel will be replicated.
+		 */
+		rv = la[i];
+		gv = lb[j + 1];
+		bv = lb[j + 0];
+
+		y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */
+
+		if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
+			rv = gv = bv = y;
+		else if (color_corr != 128) {
+
+			/* Calculate difference between color and brightness */
+			rv -= y;
+			gv -= y;
+			bv -= y;
+
+			/* Scale differences */
+			rv = (rv * color_corr) / 128;
+			gv = (gv * color_corr) / 128;
+			bv = (bv * color_corr) / 128;
+
+			/* Reapply brightness */
+			rv += y;
+			gv += y;
+			bv += y;
+
+			/* Watch for overflows */
+			RESTRICT_TO_RANGE(rv, 0, 255);
+			RESTRICT_TO_RANGE(gv, 0, 255);
+			RESTRICT_TO_RANGE(bv, 0, 255);
+		}
+
+	make_pixel:
+		IBMCAM_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
+		IBMCAM_PUTPIXEL(frame, i, frame->curline+1, rv, gv, bv);
+	}
+	/*
+	 * Account for number of bytes that we wrote into output V4L frame.
+	 * We do it here, after we are done with the scanline, because we
+	 * may fill more than one output scanline if we do vertical
+	 * enlargement.
+	 */
+	frame->curline += 2;
+	*pcopylen += v4l_linesize * 2;
+	data += frame->frmwidth * 2;
+	usb_ibmcam_align_scratch(ibmcam, data);
+
+	if (frame_done || (frame->curline >= frame->frmheight))
+		return scan_NextFrame;
+	else
+		return scan_Continue;
+}
+
+/*
+ * ibmcam_parse_data()
+ *
+ * Generic routine to parse the scratch buffer. It employs either
+ * usb_ibmcam_find_header() or usb_ibmcam_parse_lines() to do most
+ * of work.
+ *
+ * History:
+ * 1/21/00  Created.
+ */
+static void ibmcam_parse_data(struct usb_ibmcam *ibmcam)
+{
+	struct ibmcam_frame *frame;
+	unsigned char *data = ibmcam->scratch;
+	scan_state_t newstate;
+	long copylen = 0;
+
+	/* Grab the current frame and the previous frame */
+	frame = &ibmcam->frame[ibmcam->curframe];
+
+	/* printk(KERN_DEBUG "parsing %u.\n", ibmcam->scratchlen); */
+
+	while (1) {
+
+		newstate = scan_Out;
+		if (scratch_left(data)) {
+			if (frame->scanstate == STATE_SCANNING)
+				newstate = usb_ibmcam_find_header(ibmcam);
+			else if (frame->scanstate == STATE_LINES) {
+				if ((ibmcam->camera_model == IBMCAM_MODEL_2) &&
+				    (videosize >= VIDEOSIZE_352x288)) {
+					newstate = usb_ibmcam_model2_parse_lines(ibmcam, &copylen);
+				}
+				else {
+					newstate = usb_ibmcam_parse_lines(ibmcam, &copylen);
+				}
+			}
+		}
+		if (newstate == scan_Continue)
+			continue;
+		else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
+			break;
+		else
+			return; /* scan_EndParse */
+	}
+
+	if (newstate == scan_NextFrame) {
+		frame->grabstate = FRAME_DONE;
+		ibmcam->curframe = -1;
+		ibmcam->frame_num++;
+
+		/* Optionally display statistics on the screen */
+		if (flags & FLAGS_OVERLAY_STATS)
+			usb_ibmcam_overlaystats(ibmcam, frame);
+
+		/* This will cause the process to request another frame. */
+		if (waitqueue_active(&frame->wq))
+			wake_up_interruptible(&frame->wq);
+	}
+
+	/* Update the frame's uncompressed length. */
+	frame->scanlength += copylen;
+}
+
+/*
+ * Make all of the blocks of data contiguous
+ */
+static int ibmcam_compress_isochronous(struct usb_ibmcam *ibmcam, urb_t *urb)
+{
+	unsigned char *cdata, *data, *data0;
+	int i, totlen = 0;
+
+	data = data0 = ibmcam->scratch + ibmcam->scratchlen;
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int n = urb->iso_frame_desc[i].actual_length;
+		int st = urb->iso_frame_desc[i].status;
+		
+		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		/* Detect and ignore errored packets */
+		if (st < 0) {
+			if (debug >= 1) {
+				printk(KERN_ERR "ibmcam data error: [%d] len=%d, status=%X\n",
+				       i, n, st);
+			}
+			ibmcam->iso_err_count++;
+			continue;
+		}
+
+		/* Detect and ignore empty packets */
+		if (n <= 0) {
+			ibmcam->iso_skip_count++;
+			continue;
+		}
+
+		/*
+		 * If camera continues to feed us with data but there is no
+		 * consumption (if, for example, V4L client fell asleep) we
+		 * may overflow the buffer. We have to move old data over to
+		 * free room for new data. This is bad for old data. If we
+		 * just drop new data then it's bad for new data... choose
+		 * your favorite evil here.
+		 */
+		if ((ibmcam->scratchlen + n) > scratchbufsize) {
+#if 0
+			ibmcam->scratch_ovf_count++;
+			if (debug >= 3)
+				printk(KERN_ERR "ibmcam: scratch buf overflow! "
+				       "scr_len: %d, n: %d\n", ibmcam->scratchlen, n );
+			return totlen;
+#else
+			int mv;
+
+			ibmcam->scratch_ovf_count++;
+			if (debug >= 3) {
+				printk(KERN_ERR "ibmcam: scratch buf overflow! "
+				       "scr_len: %d, n: %d\n", ibmcam->scratchlen, n );
+			}
+			mv  = (ibmcam->scratchlen + n) - scratchbufsize;
+			if (ibmcam->scratchlen >= mv) {
+				int newslen = ibmcam->scratchlen - mv;
+				memmove(ibmcam->scratch, ibmcam->scratch + mv, newslen);
+				ibmcam->scratchlen = newslen;
+				data = data0 = ibmcam->scratch + ibmcam->scratchlen;
+			} else {
+				printk(KERN_ERR "ibmcam: scratch buf too small\n");
+				return totlen;
+			}
+#endif
+		}
+
+		/* Now we know that there is enough room in scratch buffer */
+		memmove(data, cdata, n);
+		data += n;
+		totlen += n;
+		ibmcam->scratchlen += n;
+	}
+#if 0
+	if (totlen > 0) {
+		static int foo=0;
+		if (foo < 1) {
+			printk(KERN_DEBUG "+%d.\n", totlen);
+			ibmcam_hexdump(data0, (totlen > 64) ? 64:totlen);
+			++foo;
+		}
+	}
+#endif
+	return totlen;
+}
+
+static void ibmcam_isoc_irq(struct urb *urb)
+{
+	int len;
+	struct usb_ibmcam *ibmcam = urb->context;
+	struct ibmcam_sbuf *sbuf;
+	int i;
+
+	/* We don't want to do anything if we are about to be removed! */
+	if (!IBMCAM_IS_OPERATIONAL(ibmcam))
+		return;
+
+#if 0
+	if (urb->actual_length > 0) {
+		printk(KERN_DEBUG "ibmcam_isoc_irq: %p status %d, "
+		       " errcount = %d, length = %d\n", urb, urb->status,
+		       urb->error_count, urb->actual_length);
+	} else {
+		static int c = 0;
+		if (c++ % 100 == 0)
+			printk(KERN_DEBUG "ibmcam_isoc_irq: no data\n");
+	}
+#endif
+
+	if (!ibmcam->streaming) {
+		if (debug >= 1)
+			printk(KERN_DEBUG "ibmcam: oops, not streaming, but interrupt\n");
+		return;
+	}
+	
+	sbuf = &ibmcam->sbuf[ibmcam->cursbuf];
+
+	/* Copy the data received into our scratch buffer */
+	len = ibmcam_compress_isochronous(ibmcam, urb);
+
+	ibmcam->urb_count++;
+	ibmcam->urb_length = len;
+	ibmcam->data_count += len;
+
+#if 0   /* This code prints few initial bytes of ISO data: used to decode markers */
+	if (ibmcam->urb_count % 64 == 1) {
+		if (ibmcam->urb_count == 1) {
+			ibmcam_hexdump(ibmcam->scratch,
+				       (ibmcam->scratchlen > 32) ? 32 : ibmcam->scratchlen);
+		}
+	}
+#endif
+
+	/* If we collected enough data let's parse! */
+	if (ibmcam->scratchlen) {
+		/* If we don't have a frame we're current working on, complain */
+		if (ibmcam->curframe >= 0)
+			ibmcam_parse_data(ibmcam);
+		else {
+			if (debug >= 1)
+				printk(KERN_DEBUG "ibmcam: received data, but no frame available\n");
+		}
+	}
+
+	for (i = 0; i < FRAMES_PER_DESC; i++) {
+		sbuf->urb->iso_frame_desc[i].status = 0;
+		sbuf->urb->iso_frame_desc[i].actual_length = 0;
+	}
+
+	/* Move to the next sbuf */
+	ibmcam->cursbuf = (ibmcam->cursbuf + 1) % IBMCAM_NUMSBUF;
+
+	return;
+}
+
+/*
+ * usb_ibmcam_veio()
+ *
+ * History:
+ * 1/27/00  Added check for dev == NULL; this happens if camera is unplugged.
+ */
+static int usb_ibmcam_veio(
+	struct usb_ibmcam *ibmcam,
+	unsigned char req,
+	unsigned short value,
+	unsigned short index)
+{
+	static const char proc[] = "usb_ibmcam_veio";
+	unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
+	int i;
+
+	if (!IBMCAM_IS_OPERATIONAL(ibmcam))
+		return 0;
+
+	if (req == 1) {
+		i = usb_control_msg(
+			ibmcam->dev,
+			usb_rcvctrlpipe(ibmcam->dev, 0),
+			req,
+			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+			value,
+			index,
+			cp,
+			sizeof(cp),
+			HZ);
+#if 0
+		printk(KERN_DEBUG "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
+		       "(req=$%02x val=$%04x ind=$%04x)\n",
+		       cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
+		       req, value, index);
+#endif
+	} else {
+		i = usb_control_msg(
+			ibmcam->dev,
+			usb_sndctrlpipe(ibmcam->dev, 0),
+			req,
+			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+			value,
+			index,
+			NULL,
+			0,
+			HZ);
+	}
+	if (i < 0) {
+		printk(KERN_ERR "%s: ERROR=%d. Camera stopped - "
+		       "reconnect or reload driver.\n", proc, i);
+		ibmcam->last_error = i;
+	}
+	return i;
+}
+
+/*
+ * usb_ibmcam_calculate_fps()
+ *
+ * This procedure roughly calculates the real frame rate based
+ * on FPS code (framerate=NNN option). Actual FPS differs
+ * slightly depending on lighting conditions, so that actual frame
+ * rate is determined by the camera. Since I don't know how to ask
+ * the camera what FPS is now I have to use the FPS code instead.
+ *
+ * The FPS code is in range [0..6], 0 is slowest, 6 is fastest.
+ * Corresponding real FPS should be in range [3..30] frames per second.
+ * The conversion formula is obvious:
+ *
+ * real_fps = 3 + (fps_code * 4.5)
+ *
+ * History:
+ * 1/18/00  Created.
+ */
+static int usb_ibmcam_calculate_fps(void)
+{
+	return 3 + framerate*4 + framerate/2;
+}
+
+/*
+ * usb_ibmcam_send_FF_04_02()
+ *
+ * This procedure sends magic 3-command prefix to the camera.
+ * The purpose of this prefix is not known.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void usb_ibmcam_send_FF_04_02(struct usb_ibmcam *ibmcam)
+{
+	usb_ibmcam_veio(ibmcam, 0, 0x00FF, 0x0127);
+	usb_ibmcam_veio(ibmcam, 0, 0x0004, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124);
+}
+
+static void usb_ibmcam_send_00_04_06(struct usb_ibmcam *ibmcam)
+{
+	usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0127);
+	usb_ibmcam_veio(ibmcam, 0, 0x0004, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0006, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00(struct usb_ibmcam *ibmcam, unsigned short x)
+{
+	usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
+	usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00_05(struct usb_ibmcam *ibmcam, unsigned short x)
+{
+	usb_ibmcam_send_x_00(ibmcam, x);
+	usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00_05_02(struct usb_ibmcam *ibmcam, unsigned short x)
+{
+	usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
+	usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124);
+}
+
+static void usb_ibmcam_send_x_01_00_05(struct usb_ibmcam *ibmcam, unsigned short x)
+{
+	usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
+	usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00_05_02_01(struct usb_ibmcam *ibmcam, unsigned short x)
+{
+	usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
+	usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124);
+}
+
+static void usb_ibmcam_send_x_00_05_02_08_01(struct usb_ibmcam *ibmcam, unsigned short x)
+{
+	usb_ibmcam_veio(ibmcam, 0, x,      0x0127);
+	usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0005, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0008, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0124);
+}
+
+static void usb_ibmcam_Packet_Format1(struct usb_ibmcam *ibmcam, unsigned char fkey, unsigned char val)
+{
+	usb_ibmcam_send_x_01_00_05	(ibmcam, unknown_88);
+	usb_ibmcam_send_x_00_05		(ibmcam, fkey);
+	usb_ibmcam_send_x_00_05_02_08_01(ibmcam, val);
+	usb_ibmcam_send_x_00_05		(ibmcam, unknown_88);
+	usb_ibmcam_send_x_00_05_02_01	(ibmcam, fkey);
+	usb_ibmcam_send_x_00_05		(ibmcam, unknown_89);
+	usb_ibmcam_send_x_00		(ibmcam, fkey);
+	usb_ibmcam_send_00_04_06	(ibmcam);
+	usb_ibmcam_veio			(ibmcam, 1, 0x0000, 0x0126);
+	usb_ibmcam_send_FF_04_02	(ibmcam);
+}
+
+static void usb_ibmcam_PacketFormat2(struct usb_ibmcam *ibmcam, unsigned char fkey, unsigned char val)
+{
+	usb_ibmcam_send_x_01_00_05	(ibmcam, unknown_88);
+	usb_ibmcam_send_x_00_05		(ibmcam, fkey);
+	usb_ibmcam_send_x_00_05_02	(ibmcam, val);
+}
+
+static void usb_ibmcam_model2_Packet2(struct usb_ibmcam *ibmcam)
+{
+	usb_ibmcam_veio(ibmcam, 0, 0x00ff, 0x012d);
+	usb_ibmcam_veio(ibmcam, 0, 0xfea3, 0x0124);
+}
+
+static void usb_ibmcam_model2_Packet1(struct usb_ibmcam *ibmcam, unsigned short v1, unsigned short v2)
+{
+	usb_ibmcam_veio(ibmcam, 0, 0x00aa, 0x012d);
+	usb_ibmcam_veio(ibmcam, 0, 0x00ff, 0x012e);
+	usb_ibmcam_veio(ibmcam, 0, v1, 	   0x012f);
+	usb_ibmcam_veio(ibmcam, 0, 0x00ff, 0x0130);
+	usb_ibmcam_veio(ibmcam, 0, 0xc719, 0x0124);
+	usb_ibmcam_veio(ibmcam, 0, v2,     0x0127);
+
+	usb_ibmcam_model2_Packet2(ibmcam);
+}
+
+/*
+ * usb_ibmcam_adjust_contrast()
+ *
+ * The contrast value changes from 0 (high contrast) to 15 (low contrast).
+ * This is in reverse to usual order of things (such as TV controls), so
+ * we reverse it again here.
+ *
+ * TODO: we probably don't need to send the setup 5 times...
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void usb_ibmcam_adjust_contrast(struct usb_ibmcam *ibmcam)
+{
+	unsigned char new_contrast = ibmcam->vpic.contrast >> 12;
+	const int ntries = 5;
+
+	if (new_contrast >= 16)
+		new_contrast = 15;
+	new_contrast = 15 - new_contrast;
+	if (new_contrast != ibmcam->vpic_old.contrast) {
+		ibmcam->vpic_old.contrast = new_contrast;
+		if (ibmcam->camera_model == IBMCAM_MODEL_1) {
+			int i;
+			for (i=0; i < ntries; i++) {
+				usb_ibmcam_Packet_Format1(ibmcam, contrast_14, new_contrast);
+				usb_ibmcam_send_FF_04_02(ibmcam);
+			}
+		} else {
+			/* Camera model 2 does not have this control; implemented in software. */
+		}
+	}
+}
+
+/*
+ * usb_ibmcam_change_lighting_conditions()
+ *
+ * Camera model 1:
+ * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
+ *
+ * Camera model 2:
+ * We have 16 levels of lighting, 0 for bright light and up to 15 for
+ * low light. But values above 5 or so are useless because camera is
+ * not really capable to produce anything worth viewing at such light.
+ * This setting may be altered only in certain camera state.
+ *
+ * Low lighting forces slower FPS. Lighting is set as a module parameter.
+ *
+ * History:
+ * 1/5/00   Created.
+ * 2/20/00  Added support for Model 2 cameras.
+ */
+static void usb_ibmcam_change_lighting_conditions(struct usb_ibmcam *ibmcam)
+{
+	static const char proc[] = "usb_ibmcam_change_lighting_conditions";
+
+	if (debug > 0)
+		printk(KERN_INFO "%s: Set lighting to %hu.\n", proc, lighting);
+
+	if (ibmcam->camera_model == IBMCAM_MODEL_1) {
+		const int ntries = 5;
+		int i;
+		for (i=0; i < ntries; i++)
+			usb_ibmcam_Packet_Format1(ibmcam, light_27, (unsigned short) lighting);
+	} else {
+		/*
+		 * This command apparently requires camera to be stopped. My
+		 * experiments showed that it -is- possible to alter the lighting
+		 * conditions setting "on the fly", but why bother? This setting does
+		 * not work reliably in all cases, so I decided simply to leave the
+		 * setting where Xirlink put it - in the camera setup phase. This code
+		 * is commented out because it does not work at -any- moment, so its
+		 * presence makes no sense. You may use it for experiments.
+		 */
+#if 0
+		usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x010c);	/* Stop camera */
+		usb_ibmcam_model2_Packet1(ibmcam, mod2_sensitivity, lighting);
+		usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c);	/* Start camera */
+#endif
+	}
+}
+
+/*
+ * usb_ibmcam_set_sharpness()
+ *
+ * Cameras model 1 have internal smoothing feature. It is controlled by value in
+ * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
+ * Recommended value is 4. Cameras model 2 do not have this feature at all.
+ */
+static void usb_ibmcam_set_sharpness(struct usb_ibmcam *ibmcam)
+{
+	static const char proc[] = "usb_ibmcam_set_sharpness";
+
+	if (ibmcam->camera_model == IBMCAM_MODEL_1) {
+		static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
+		unsigned short i, sv;
+
+		RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
+		if (debug > 0)
+			printk(KERN_INFO "%s: Set sharpness to %hu.\n", proc, sharpness);
+
+		sv = sa[sharpness - SHARPNESS_MIN];
+		for (i=0; i < 2; i++) {
+			usb_ibmcam_send_x_01_00_05	(ibmcam, unknown_88);
+			usb_ibmcam_send_x_00_05		(ibmcam, sharp_13);
+			usb_ibmcam_send_x_00_05_02	(ibmcam, sv);
+		}
+	} else {
+		/* Camera model 2 does not have this control */
+	}
+}
+
+/*
+ * usb_ibmcam_set_brightness()
+ *
+ * This procedure changes brightness of the picture.
+ */
+static void usb_ibmcam_set_brightness(struct usb_ibmcam *ibmcam)
+{
+	static const char proc[] = "usb_ibmcam_set_brightness";
+	static const unsigned short n = 1;
+	unsigned short i, j, bv[3];
+
+	bv[0] = bv[1] = bv[2] = ibmcam->vpic.brightness >> 10;
+	if (bv[0] == (ibmcam->vpic_old.brightness >> 10))
+		return;
+	ibmcam->vpic_old.brightness = ibmcam->vpic.brightness;
+
+	if (debug > 0)
+		printk(KERN_INFO "%s: Set brightness to (%hu,%hu,%hu)\n",
+		       proc, bv[0], bv[1], bv[2]);
+
+	if (ibmcam->camera_model == IBMCAM_MODEL_1) {
+		for (j=0; j < 3; j++)
+			for (i=0; i < n; i++)
+				usb_ibmcam_Packet_Format1(ibmcam, bright_3x[j], bv[j]);
+	} else {
+		i = ibmcam->vpic.brightness >> 12;	/* 0 .. 15 */
+		j = 0x60 + i * ((0xee - 0x60) / 16);	/* 0x60 .. 0xee or so */
+		usb_ibmcam_model2_Packet1(ibmcam, mod2_brightness, j);
+	}
+}
+
+static void usb_ibmcam_model2_set_hue(struct usb_ibmcam *ibmcam)
+{
+	unsigned short hue = ibmcam->vpic.hue >> 9; /* 0 .. 7F */
+
+	usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_rg, hue);
+	/* usb_ibmcam_model2_Packet1(ibmcam, mod2_saturation, sat); */
+}
+
+/*
+ * usb_ibmcam_adjust_picture()
+ *
+ * This procedure gets called from V4L interface to update picture settings.
+ * Here we change brightness and contrast.
+ */
+static void usb_ibmcam_adjust_picture(struct usb_ibmcam *ibmcam)
+{
+	usb_ibmcam_adjust_contrast(ibmcam);
+	usb_ibmcam_set_brightness(ibmcam);
+	if (ibmcam->camera_model == IBMCAM_MODEL_2) {
+		usb_ibmcam_model2_set_hue(ibmcam);
+	}
+}
+
+static int usb_ibmcam_model1_setup(struct usb_ibmcam *ibmcam)
+{
+	const int ntries = 5;
+	int i;
+
+	usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0128);
+	usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100);
+	usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100);	/* LED On  */
+	usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100);
+	usb_ibmcam_veio(ibmcam, 0, 0x81, 0x0100);	/* LED Off */
+	usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100);
+	usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100);	/* LED On  */
+	usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0108);
+
+	usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0112);
+	usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0115);
+	usb_ibmcam_veio(ibmcam, 0, 0x06, 0x0115);
+	usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0116);
+	usb_ibmcam_veio(ibmcam, 0, 0x44, 0x0116);
+	usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0116);
+	usb_ibmcam_veio(ibmcam, 0, 0x40, 0x0116);
+	usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0115);
+	usb_ibmcam_veio(ibmcam, 0, 0x0e, 0x0115);
+	usb_ibmcam_veio(ibmcam, 0, 0x19, 0x012c);
+
+	usb_ibmcam_Packet_Format1(ibmcam, 0x00, 0x1e);
+	usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x0d);
+	usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x09);
+	usb_ibmcam_Packet_Format1(ibmcam, 0x3b, 0x00);
+	usb_ibmcam_Packet_Format1(ibmcam, 0x28, 0x22);
+	usb_ibmcam_Packet_Format1(ibmcam, light_27, 0);
+	usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1f);
+	usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x08);
+
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x2c, 0x00);
+
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x30, 0x14);
+
+	usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x01, 0xe1);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x02, 0xcd);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x03, 0xcd);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x04, 0xfa);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00);
+
+	usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x0a, 0x37);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x0b, 0xb8);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x0c, 0xf3);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x0d, 0xe3);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x0e, 0x0d);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x0f, 0xf2);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x10, 0xd5);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x11, 0xba);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x12, 0x53);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00);
+
+	usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x02);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x16, 0x00);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x17, 0x28);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x18, 0x7d);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x19, 0xbe);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x3f, 0xff);
+	usb_ibmcam_PacketFormat2(ibmcam, 0x39, 0x00);
+
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x00, 0x18);
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x13, 0x18);
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x14, 0x06);
+
+	/* This is default brightness */
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x31, 0x37);
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x32, 0x46);
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x33, 0x55);
+
+	usb_ibmcam_Packet_Format1(ibmcam, 0x2e, 0x04);
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x2d, 0x04);
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x29, 0x80);
+	usb_ibmcam_Packet_Format1(ibmcam, 0x2c, 0x01);
+	usb_ibmcam_Packet_Format1(ibmcam, 0x30, 0x17);
+	usb_ibmcam_Packet_Format1(ibmcam, 0x39, 0x08);
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x34, 0x00);
+
+	usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0101);
+	usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010a);
+
+	switch (videosize) {
+	case VIDEOSIZE_128x96:
+		usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0103);
+		usb_ibmcam_veio(ibmcam, 0, 0x60, 0x0105);
+		usb_ibmcam_veio(ibmcam, 0, 0x0c, 0x010b);
+		usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x0b, 0x011d);
+		usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0129);
+		break;
+	case VIDEOSIZE_176x144:
+		usb_ibmcam_veio(ibmcam, 0, 0xb0, 0x0103);
+		usb_ibmcam_veio(ibmcam, 0, 0x8f, 0x0105);
+		usb_ibmcam_veio(ibmcam, 0, 0x06, 0x010b);
+		usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x0d, 0x011d);
+		usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0129);
+		break;
+	case VIDEOSIZE_352x288:
+		usb_ibmcam_veio(ibmcam, 0, 0xb0, 0x0103);
+		usb_ibmcam_veio(ibmcam, 0, 0x90, 0x0105);
+		usb_ibmcam_veio(ibmcam, 0, 0x02, 0x010b);
+		usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011b);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x05, 0x011d);
+		usb_ibmcam_veio(ibmcam, 0, 0x00, 0x011e);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0129);
+		break;
+	}
+
+	usb_ibmcam_veio(ibmcam, 0, 0xff, 0x012b);
+
+	/* This is another brightness - don't know why */
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x31, 0xc3);
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x32, 0xd2);
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, 0x33, 0xe1);
+
+	/* Default contrast */
+	for (i=0; i < ntries; i++)
+		usb_ibmcam_Packet_Format1(ibmcam, contrast_14, 0x0a);
+
+	/* Default sharpness */
+	for (i=0; i < 2; i++)
+		usb_ibmcam_PacketFormat2(ibmcam, sharp_13, 0x1a);	/* Level 4 FIXME */
+
+	/* Default lighting conditions */
+	usb_ibmcam_Packet_Format1(ibmcam, light_27, lighting); /* 0=Bright 2=Low */
+
+	/* Assorted init */
+
+	switch (videosize) {
+	case VIDEOSIZE_128x96:
+		usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1e);
+		usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x36, 0x0102);
+		usb_ibmcam_veio(ibmcam, 0, 0x1a, 0x0104);
+		usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x2b, 0x011c);
+		usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a);	/* Same everywhere */
+#if 0
+		usb_ibmcam_veio(ibmcam, 0, 0x00, 0x0106);
+		usb_ibmcam_veio(ibmcam, 0, 0x38, 0x0107);
+#else
+		usb_ibmcam_veio(ibmcam, 0, 0x02, 0x0106);
+		usb_ibmcam_veio(ibmcam, 0, 0x2a, 0x0107);
+#endif
+		break;
+	case VIDEOSIZE_176x144:
+		usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1e);
+		usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x04, 0x0102);
+		usb_ibmcam_veio(ibmcam, 0, 0x02, 0x0104);
+		usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x2b, 0x011c);
+		usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0106);
+		usb_ibmcam_veio(ibmcam, 0, 0xca, 0x0107);
+		break;
+	case VIDEOSIZE_352x288:
+		usb_ibmcam_Packet_Format1(ibmcam, 0x2b, 0x1f);
+		usb_ibmcam_veio(ibmcam, 0, 0xc9, 0x0119);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x80, 0x0109);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x08, 0x0102);
+		usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0104);
+		usb_ibmcam_veio(ibmcam, 0, 0x04, 0x011a);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x2f, 0x011c);
+		usb_ibmcam_veio(ibmcam, 0, 0x23, 0x012a);	/* Same everywhere */
+		usb_ibmcam_veio(ibmcam, 0, 0x03, 0x0106);
+		usb_ibmcam_veio(ibmcam, 0, 0xf6, 0x0107);
+		break;
+	}
+	return IBMCAM_IS_OPERATIONAL(ibmcam);
+}
+
+static int usb_ibmcam_model2_setup(struct usb_ibmcam *ibmcam)
+{
+	usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0100);	/* LED on */
+	usb_ibmcam_veio(ibmcam, 1, 0x0000, 0x0116);
+	usb_ibmcam_veio(ibmcam, 0, 0x0060, 0x0116);
+	usb_ibmcam_veio(ibmcam, 0, 0x0002, 0x0112);
+	usb_ibmcam_veio(ibmcam, 0, 0x00bc, 0x012c);
+	usb_ibmcam_veio(ibmcam, 0, 0x0008, 0x012b);
+	usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0108);
+	usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0133);
+	usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0102);
+	switch (videosize) {
+	case VIDEOSIZE_176x144:
+		usb_ibmcam_veio(ibmcam, 0, 0x002c, 0x0103);	/* All except 320x240 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104);	/* Same */
+		usb_ibmcam_veio(ibmcam, 0, 0x0024, 0x0105);	/* 176x144, 352x288 */
+		usb_ibmcam_veio(ibmcam, 0, 0x00b9, 0x010a);	/* Unique to this mode */
+		usb_ibmcam_veio(ibmcam, 0, 0x0038, 0x0119);	/* Unique to this mode */
+		usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106);	/* Same */
+		usb_ibmcam_veio(ibmcam, 0, 0x0090, 0x0107);	/* Unique to every mode*/
+		break;
+	case VIDEOSIZE_320x240:
+		usb_ibmcam_veio(ibmcam, 0, 0x0028, 0x0103);	/* Unique to this mode */
+		usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104);	/* Same */
+		usb_ibmcam_veio(ibmcam, 0, 0x001e, 0x0105);	/* 320x240, 352x240 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0039, 0x010a);	/* All except 176x144 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0070, 0x0119);	/* All except 176x144 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106);	/* Same */
+		usb_ibmcam_veio(ibmcam, 0, 0x0098, 0x0107);	/* Unique to every mode*/
+		break;
+	case VIDEOSIZE_352x240:
+		usb_ibmcam_veio(ibmcam, 0, 0x002c, 0x0103);	/* All except 320x240 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104);	/* Same */
+		usb_ibmcam_veio(ibmcam, 0, 0x001e, 0x0105);	/* 320x240, 352x240 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0039, 0x010a);	/* All except 176x144 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0070, 0x0119);	/* All except 176x144 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106);	/* Same */
+		usb_ibmcam_veio(ibmcam, 0, 0x00da, 0x0107);	/* Unique to every mode*/
+		break;
+	case VIDEOSIZE_352x288:
+		usb_ibmcam_veio(ibmcam, 0, 0x002c, 0x0103);	/* All except 320x240 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0104);	/* Same */
+		usb_ibmcam_veio(ibmcam, 0, 0x0024, 0x0105);	/* 176x144, 352x288 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0039, 0x010a);	/* All except 176x144 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0070, 0x0119);	/* All except 176x144 */
+		usb_ibmcam_veio(ibmcam, 0, 0x0003, 0x0106);	/* Same */
+		usb_ibmcam_veio(ibmcam, 0, 0x00fe, 0x0107);	/* Unique to every mode*/
+		break;
+	}
+	return IBMCAM_IS_OPERATIONAL(ibmcam);
+}
+
+/*
+ * usb_ibmcam_model1_setup_after_video_if()
+ *
+ * This code adds finishing touches to the video data interface.
+ * Here we configure the frame rate and turn on the LED.
+ */
+static void usb_ibmcam_model1_setup_after_video_if(struct usb_ibmcam *ibmcam)
+{
+	unsigned short internal_frame_rate;
+
+	RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
+	internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */
+	usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0100);	/* LED On  */
+	usb_ibmcam_veio(ibmcam, 0, internal_frame_rate, 0x0111);
+	usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0114);
+	usb_ibmcam_veio(ibmcam, 0, 0xc0, 0x010c);
+}
+
+static void usb_ibmcam_model2_setup_after_video_if(struct usb_ibmcam *ibmcam)
+{
+	unsigned short setup_model2_rg, setup_model2_rg2, setup_model2_sat, setup_model2_yb;
+
+	usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0100);	/* LED on */
+
+	switch (videosize) {
+	case VIDEOSIZE_176x144:
+		usb_ibmcam_veio(ibmcam, 0, 0x0050, 0x0111);
+		usb_ibmcam_veio(ibmcam, 0, 0x00d0, 0x0111);
+		break;
+	case VIDEOSIZE_320x240:
+	case VIDEOSIZE_352x240:
+	case VIDEOSIZE_352x288:
+		usb_ibmcam_veio(ibmcam, 0, 0x0040, 0x0111);
+		usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x0111);
+		break;
+	}
+	usb_ibmcam_veio(ibmcam, 0, 0x009b, 0x010f);
+	usb_ibmcam_veio(ibmcam, 0, 0x00bb, 0x010f);
+
+	/*
+	 * Hardware settings, may affect CMOS sensor; not user controls!
+	 * -------------------------------------------------------------
+	 * 0x0004: no effect
+	 * 0x0006: hardware effect
+	 * 0x0008: no effect
+	 * 0x000a: stops video stream, probably important h/w setting
+	 * 0x000c: changes color in hardware manner (not user setting)
+	 * 0x0012: changes number of colors (does not affect speed)
+	 * 0x002a: no effect
+	 * 0x002c: hardware setting (related to scan lines)
+	 * 0x002e: stops video stream, probably important h/w setting
+	 */
+	usb_ibmcam_model2_Packet1(ibmcam, 0x000a, 0x005c);
+	usb_ibmcam_model2_Packet1(ibmcam, 0x0004, 0x0000);
+	usb_ibmcam_model2_Packet1(ibmcam, 0x0006, 0x00fb);
+	usb_ibmcam_model2_Packet1(ibmcam, 0x0008, 0x0000);
+	usb_ibmcam_model2_Packet1(ibmcam, 0x000c, 0x0009);
+	usb_ibmcam_model2_Packet1(ibmcam, 0x0012, 0x000a);
+	usb_ibmcam_model2_Packet1(ibmcam, 0x002a, 0x0000);
+	usb_ibmcam_model2_Packet1(ibmcam, 0x002c, 0x0000);
+	usb_ibmcam_model2_Packet1(ibmcam, 0x002e, 0x0008);
+
+	/*
+	 * Function 0x0030 pops up all over the place. Apparently
+	 * it is a hardware control register, with every bit assigned to
+	 * do something.
+	 */
+	usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0000);
+
+	/*
+	 * Magic control of CMOS sensor. Only lower values like
+	 * 0-3 work, and picture shifts left or right. Don't change.
+	 */
+	switch (videosize) {
+	case VIDEOSIZE_176x144:
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0002);
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0002); /* Horizontal shift */
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x004a); /* Another hardware setting */
+		break;
+	case VIDEOSIZE_320x240:
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0009);
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0005); /* Horizontal shift */
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x0044); /* Another hardware setting */
+		break;
+	case VIDEOSIZE_352x240:
+		/* This mode doesn't work as Windows programs it; changed to work */
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0009); /* Windows sets this to 8 */
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0003); /* Horizontal shift */
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
+		break;
+	case VIDEOSIZE_352x288:
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0014, 0x0003);
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0016, 0x0002); /* Horizontal shift */
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0018, 0x004a); /* Another hardware setting */
+		break;
+	}
+
+	usb_ibmcam_model2_Packet1(ibmcam, mod2_brightness, 0x005a);
+
+	/*
+	 * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest).
+	 * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the
+	 * slowest setting. However for all practical reasons high settings make no
+	 * sense because USB is not fast enough to support high FPS. Be aware that
+	 * the picture datastream will be severely disrupted if you ask for
+	 * frame rate faster than allowed for the video size - see below:
+	 *
+	 * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz):
+	 * -----------------------------------------------------------------
+	 * 176x144: [6..31]
+	 * 320x240: [8..31]
+	 * 352x240: [10..31]
+	 * 352x288: [16..31] I have to raise lower threshold for stability...
+	 *
+	 * As usual, slower FPS provides better sensitivity.
+	 */
+	{
+		short hw_fps=31, i_framerate;
+
+		RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
+		i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN;
+		switch (videosize) {
+		case VIDEOSIZE_176x144:
+			hw_fps = 6 + i_framerate*4;
+			break;
+		case VIDEOSIZE_320x240:
+			hw_fps = 8 + i_framerate*3;
+			break;
+		case VIDEOSIZE_352x240:
+			hw_fps = 10 + i_framerate*2;
+			break;
+		case VIDEOSIZE_352x288:
+			hw_fps = 28 + i_framerate/2;
+			break;
+		}
+		if (debug > 0)
+			printk(KERN_DEBUG "Framerate (hardware): %hd.\n", hw_fps);
+		RESTRICT_TO_RANGE(hw_fps, 0, 31);
+		usb_ibmcam_model2_Packet1(ibmcam, mod2_set_framerate, hw_fps);
+	}
+
+	/*
+	 * This setting does not visibly affect pictures; left it here
+	 * because it was present in Windows USB data stream. This function
+	 * does not allow arbitrary values and apparently is a bit mask, to
+	 * be activated only at appropriate time. Don't change it randomly!
+	 */
+	switch (videosize) {
+	case VIDEOSIZE_176x144:
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x00c2);
+		break;
+	case VIDEOSIZE_320x240:
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x0044);
+		break;
+	case VIDEOSIZE_352x240:
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x0046);
+		break;
+	case VIDEOSIZE_352x288:
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0026, 0x0048);
+		break;
+	}
+
+	usb_ibmcam_model2_Packet1(ibmcam, mod2_sensitivity, lighting);
+
+	if (init_model2_rg >= 0) {
+		RESTRICT_TO_RANGE(init_model2_rg, 0, 255);
+		setup_model2_rg = init_model2_rg;
+	} else
+		setup_model2_rg = 0x0070;
+
+	if (init_model2_rg2 >= 0) {
+		RESTRICT_TO_RANGE(init_model2_rg2, 0, 255);
+		setup_model2_rg2 = init_model2_rg2;
+	} else
+		setup_model2_rg2 = 0x002f;
+
+	if (init_model2_sat >= 0) {
+		RESTRICT_TO_RANGE(init_model2_sat, 0, 255);
+		setup_model2_sat = init_model2_sat;
+	} else
+		setup_model2_sat = 0x0034;
+
+	if (init_model2_yb >= 0) {
+		RESTRICT_TO_RANGE(init_model2_yb, 0, 255);
+		setup_model2_yb = init_model2_yb;
+	} else
+		setup_model2_yb = 0x00a0;
+
+	usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_rg2, setup_model2_rg2);
+	usb_ibmcam_model2_Packet1(ibmcam, mod2_saturation, setup_model2_sat);
+	usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_yb, setup_model2_yb);
+	usb_ibmcam_model2_Packet1(ibmcam, mod2_color_balance_rg, setup_model2_rg);
+
+	/* Hardware control command */
+	usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0004);
+
+	usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c);	/* Go camera, go! */
+	usb_clear_halt(ibmcam->dev, ibmcam->video_endp);
+}
+
+/*
+ * usb_ibmcam_setup_video_stop()
+ *
+ * This code tells camera to stop streaming. The interface remains
+ * configured and bandwidth - claimed.
+ */
+static void usb_ibmcam_setup_video_stop(struct usb_ibmcam *ibmcam)
+{
+	if (ibmcam->camera_model == IBMCAM_MODEL_1) {
+		usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c);
+		usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c);
+		usb_ibmcam_veio(ibmcam, 0, 0x01, 0x0114);
+		usb_ibmcam_veio(ibmcam, 0, 0xc0, 0x010c);
+		usb_ibmcam_veio(ibmcam, 0, 0x00, 0x010c);
+		usb_ibmcam_send_FF_04_02(ibmcam);
+		usb_ibmcam_veio(ibmcam, 1, 0x00, 0x0100);
+		usb_ibmcam_veio(ibmcam, 0, 0x81, 0x0100);	/* LED Off */
+	} else if (ibmcam->camera_model == IBMCAM_MODEL_2) {
+		usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x010c);	/* Stop the camera */
+
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0004);
+
+		usb_ibmcam_veio(ibmcam, 0, 0x0080, 0x0100);	/* LED Off */
+		usb_ibmcam_veio(ibmcam, 0, 0x0020, 0x0111);
+		usb_ibmcam_veio(ibmcam, 0, 0x00a0, 0x0111);
+
+		usb_ibmcam_model2_Packet1(ibmcam, 0x0030, 0x0002);
+
+		usb_ibmcam_veio(ibmcam, 0, 0x0020, 0x0111);
+		usb_ibmcam_veio(ibmcam, 0, 0x0000, 0x0112);
+	}
+}
+
+/*
+ * usb_ibmcam_reinit_iso()
+ *
+ * This procedure sends couple of commands to the camera and then
+ * resets the video pipe. This sequence was observed to reinit the
+ * camera or, at least, to initiate ISO data stream.
+ *
+ * History:
+ * 1/2/00   Created.
+ */
+static void usb_ibmcam_reinit_iso(struct usb_ibmcam *ibmcam, int do_stop)
+{
+	if (ibmcam->camera_model == IBMCAM_MODEL_1) {
+		if (do_stop)
+			usb_ibmcam_setup_video_stop(ibmcam);
+		usb_ibmcam_veio(ibmcam, 0, 0x0001, 0x0114);
+		usb_ibmcam_veio(ibmcam, 0, 0x00c0, 0x010c);
+		usb_clear_halt(ibmcam->dev, ibmcam->video_endp);
+		usb_ibmcam_model1_setup_after_video_if(ibmcam);
+	} else if (ibmcam->camera_model == IBMCAM_MODEL_2) {
+		usb_ibmcam_model2_setup_after_video_if(ibmcam);
+	}
+}
+
+/*
+ * ibmcam_init_isoc()
+ *
+ * History:
+ * 1/27/00  Used ibmcam->iface, ibmcam->ifaceAltActive instead of hardcoded values.
+ *          Simplified by using for loop, allowed any number of URBs.
+ */
+static int ibmcam_init_isoc(struct usb_ibmcam *ibmcam)
+{
+	struct usb_device *dev = ibmcam->dev;
+	int i, err;
+
+	if (!IBMCAM_IS_OPERATIONAL(ibmcam))
+		return -EFAULT;
+
+	ibmcam->compress = 0;
+	ibmcam->curframe = -1;
+	ibmcam->cursbuf = 0;
+	ibmcam->scratchlen = 0;
+
+	/* Alternate interface 1 is is the biggest frame size */
+	i = usb_set_interface(dev, ibmcam->iface, ibmcam->ifaceAltActive);
+	if (i < 0) {
+		printk(KERN_ERR "usb_set_interface error\n");
+		ibmcam->last_error = i;
+		return -EBUSY;
+	}
+	usb_ibmcam_change_lighting_conditions(ibmcam);
+	usb_ibmcam_set_sharpness(ibmcam);
+	usb_ibmcam_reinit_iso(ibmcam, 0);
+
+	/* We double buffer the Iso lists */
+
+	for (i=0; i < IBMCAM_NUMSBUF; i++) {
+		int j, k;
+		urb_t *urb;
+
+		urb = usb_alloc_urb(FRAMES_PER_DESC);
+		if (urb == NULL) {
+			printk(KERN_ERR "ibmcam_init_isoc: usb_init_isoc() failed.\n");
+			return -ENOMEM;
+		}
+		ibmcam->sbuf[i].urb = urb;
+		urb->dev = dev;
+		urb->context = ibmcam;
+		urb->pipe = usb_rcvisocpipe(dev, ibmcam->video_endp);
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->transfer_buffer = ibmcam->sbuf[i].data;
+		urb->complete = ibmcam_isoc_irq;
+		urb->number_of_packets = FRAMES_PER_DESC;
+		urb->transfer_buffer_length = ibmcam->iso_packet_len * FRAMES_PER_DESC;
+		for (j=k=0; j < FRAMES_PER_DESC; j++, k += ibmcam->iso_packet_len) {
+			urb->iso_frame_desc[j].offset = k;
+			urb->iso_frame_desc[j].length = ibmcam->iso_packet_len;
+		}
+	}
+
+	/* Link URBs into a ring so that they invoke each other infinitely */
+	for (i=0; i < IBMCAM_NUMSBUF; i++) {
+		if ((i+1) < IBMCAM_NUMSBUF)
+			ibmcam->sbuf[i].urb->next = ibmcam->sbuf[i+1].urb;
+		else
+			ibmcam->sbuf[i].urb->next = ibmcam->sbuf[0].urb;
+	}
+
+	/* Submit all URBs */
+	for (i=0; i < IBMCAM_NUMSBUF; i++) {
+		err = usb_submit_urb(ibmcam->sbuf[i].urb);
+		if (err)
+			printk(KERN_ERR "ibmcam_init_isoc: usb_run_isoc(%d) ret %d\n",
+			       i, err);
+	}
+
+	ibmcam->streaming = 1;
+	/* printk(KERN_DEBUG "streaming=1 ibmcam->video_endp=$%02x\n", ibmcam->video_endp); */
+	return 0;
+}
+
+/*
+ * ibmcam_stop_isoc()
+ *
+ * This procedure stops streaming and deallocates URBs. Then it
+ * activates zero-bandwidth alt. setting of the video interface.
+ *
+ * History:
+ * 1/22/00  Corrected order of actions to work after surprise removal.
+ * 1/27/00  Used ibmcam->iface, ibmcam->ifaceAltInactive instead of hardcoded values.
+ */
+static void ibmcam_stop_isoc(struct usb_ibmcam *ibmcam)
+{
+	static const char proc[] = "ibmcam_stop_isoc";
+	int i, j;
+
+	if (!ibmcam->streaming || (ibmcam->dev == NULL))
+		return;
+
+	/* Unschedule all of the iso td's */
+	for (i=0; i < IBMCAM_NUMSBUF; i++) {
+		j = usb_unlink_urb(ibmcam->sbuf[i].urb);
+		if (j < 0)
+			printk(KERN_ERR "%s: usb_unlink_urb() error %d.\n", proc, j);
+	}
+	/* printk(KERN_DEBUG "streaming=0\n"); */
+	ibmcam->streaming = 0;
+
+	/* Delete them all */
+	for (i=0; i < IBMCAM_NUMSBUF; i++)
+		usb_free_urb(ibmcam->sbuf[i].urb);
+
+	if (!ibmcam->remove_pending) {
+		usb_ibmcam_setup_video_stop(ibmcam);
+
+		/* Set packet size to 0 */
+		j = usb_set_interface(ibmcam->dev, ibmcam->iface, ibmcam->ifaceAltInactive);
+		if (j < 0) {
+			printk(KERN_ERR "%s: usb_set_interface() error %d.\n", proc, j);
+			ibmcam->last_error = j;
+		}
+	}
+}
+
+/*
+ * ibmcam_new_frame()
+ *
+ * History:
+ * 29-Mar-00 Added copying of previous frame into the current one.
+ */
+static int ibmcam_new_frame(struct usb_ibmcam *ibmcam, int framenum)
+{
+	struct ibmcam_frame *frame;
+	int n, width, height;
+
+	/* If we're not grabbing a frame right now and the other frame is */
+	/*  ready to be grabbed into, then use it instead */
+	if (ibmcam->curframe != -1)
+		return 0;
+
+	n = (framenum - 1 + IBMCAM_NUMFRAMES) % IBMCAM_NUMFRAMES;
+	if (ibmcam->frame[n].grabstate == FRAME_READY)
+		framenum = n;
+
+	frame = &ibmcam->frame[framenum];
+
+	frame->grabstate = FRAME_GRABBING;
+	frame->scanstate = STATE_SCANNING;
+	frame->scanlength = 0;		/* Accumulated in ibmcam_parse_data() */
+	ibmcam->curframe = framenum;
+
+	/*
+	 * Normally we would want to copy previous frame into the current one
+	 * before we even start filling it with data; this allows us to stop
+	 * filling at any moment; top portion of the frame will be new and
+	 * bottom portion will stay as it was in previous frame. If we don't
+	 * do that then missing chunks of video stream will result in flickering
+	 * portions of old data whatever it was before.
+	 *
+	 * If we choose not to copy previous frame (to, for example, save few
+	 * bus cycles - the frame can be pretty large!) then we have an option
+	 * to clear the frame before using. If we experience losses in this
+	 * mode then missing picture will be black (no flickering).
+	 *
+	 * Finally, if user chooses not to clean the current frame before
+	 * filling it with data then the old data will be visible if we fail
+	 * to refill entire frame with new data.
+	 */
+	if (!(flags & FLAGS_SEPARATE_FRAMES)) {
+		/* This copies previous frame into this one to mask losses */
+		memmove(frame->data, ibmcam->frame[1-framenum].data,  MAX_FRAME_SIZE);
+	} else {
+		if (flags & FLAGS_CLEAN_FRAMES) {
+			/* This provides a "clean" frame but slows things down */
+			memset(frame->data, 0, MAX_FRAME_SIZE);
+		}
+	}
+	switch (videosize) {
+	case VIDEOSIZE_128x96:
+		frame->frmwidth = 128;
+		frame->frmheight = 96;
+		frame->order_uv = 1;	/* U Y V Y ... */
+		frame->hdr_sig = 0x06;	/* 00 FF 00 06 */
+		break;
+	case VIDEOSIZE_176x144:
+		frame->frmwidth = 176;
+		frame->frmheight = 144;
+		frame->order_uv = 1;	/* U Y V Y ... */
+		frame->hdr_sig = 0x0E;	/* 00 FF 00 0E */
+		break;
+	case VIDEOSIZE_320x240:		/* For model 2 only */
+		frame->frmwidth = 320;
+		frame->frmheight = 240;
+		break;
+	case VIDEOSIZE_352x240:		/* For model 2 only */
+		frame->frmwidth = 352;
+		frame->frmheight = 240;
+		break;
+	case VIDEOSIZE_352x288:
+		frame->frmwidth = 352;
+		frame->frmheight = 288;
+		frame->order_uv = 0;	/* V Y U Y ... */
+		frame->hdr_sig = 0x00;	/* 00 FF 00 00 */
+		break;
+	}
+	frame->order_yc = (ibmcam->camera_model == IBMCAM_MODEL_2);
+
+	width = frame->width;
+	RESTRICT_TO_RANGE(width, min_imgwidth, imgwidth);
+	width &= ~7;		/* Multiple of 8 */
+
+	height = frame->height;
+	RESTRICT_TO_RANGE(height, min_imgheight, imgheight);
+	height &= ~3;		/* Multiple of 4 */
+
+	return 0;
+}
+
+/*
+ * ibmcam_open()
+ *
+ * This is part of Video 4 Linux API. The driver can be opened by one
+ * client only (checks internal counter 'ibmcam->user'). The procedure
+ * then allocates buffers needed for video processing.
+ *
+ * History:
+ * 1/22/00  Rewrote, moved scratch buffer allocation here. Now the
+ *          camera is also initialized here (once per connect), at
+ *          expense of V4L client (it waits on open() call).
+ * 1/27/00  Used IBMCAM_NUMSBUF as number of URB buffers.
+ * 5/24/00  Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ */
+static int ibmcam_open(struct video_device *dev, int flags)
+{
+	struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+	const int sb_size = FRAMES_PER_DESC * ibmcam->iso_packet_len;
+	int i, err = 0;
+
+	MOD_INC_USE_COUNT;
+	down(&ibmcam->lock);
+
+	if (ibmcam->user)
+		err = -EBUSY;
+	else {
+		/* Clean pointers so we know if we allocated something */
+		for (i=0; i < IBMCAM_NUMSBUF; i++)
+			ibmcam->sbuf[i].data = NULL;
+
+		/* Allocate memory for the frame buffers */
+		ibmcam->fbuf_size = IBMCAM_NUMFRAMES * MAX_FRAME_SIZE;
+		ibmcam->fbuf = rvmalloc(ibmcam->fbuf_size);
+		ibmcam->scratch = kmalloc(scratchbufsize, GFP_KERNEL);
+		ibmcam->scratchlen = 0;
+		if ((ibmcam->fbuf == NULL) || (ibmcam->scratch == NULL))
+			err = -ENOMEM;
+		else {
+			/* Allocate all buffers */
+			for (i=0; i < IBMCAM_NUMFRAMES; i++) {
+				ibmcam->frame[i].grabstate = FRAME_UNUSED;
+				ibmcam->frame[i].data = ibmcam->fbuf + i*MAX_FRAME_SIZE;
+				/*
+				 * Set default sizes in case IOCTL (VIDIOCMCAPTURE)
+				 * is not used (using read() instead).
+				 */
+				ibmcam->frame[i].width = imgwidth;
+				ibmcam->frame[i].height = imgheight;
+				ibmcam->frame[i].bytes_read = 0;
+			}
+			for (i=0; i < IBMCAM_NUMSBUF; i++) {
+				ibmcam->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL);
+				if (ibmcam->sbuf[i].data == NULL) {
+					err = -ENOMEM;
+					break;
+				}
+			}
+		}
+		if (err) {
+			/* Have to free all that memory */
+			if (ibmcam->fbuf != NULL) {
+				rvfree(ibmcam->fbuf, ibmcam->fbuf_size);
+				ibmcam->fbuf = NULL;
+			}
+			if (ibmcam->scratch != NULL) {
+				kfree(ibmcam->scratch);
+				ibmcam->scratch = NULL;
+			}
+			for (i=0; i < IBMCAM_NUMSBUF; i++) {
+				if (ibmcam->sbuf[i].data != NULL) {
+					kfree (ibmcam->sbuf[i].data);
+					ibmcam->sbuf[i].data = NULL;
+				}
+			}
+		}
+	}
+
+	/* If so far no errors then we shall start the camera */
+	if (!err) {
+		err = ibmcam_init_isoc(ibmcam);
+		if (!err) {
+			/* Send init sequence only once, it's large! */
+			if (!ibmcam->initialized) {
+				int setup_ok = 0;
+				if (ibmcam->camera_model == IBMCAM_MODEL_1)
+					setup_ok = usb_ibmcam_model1_setup(ibmcam);
+				else if (ibmcam->camera_model == IBMCAM_MODEL_2)
+					setup_ok = usb_ibmcam_model2_setup(ibmcam);
+				if (setup_ok)
+					ibmcam->initialized = 1;
+				else
+					err = -EBUSY;
+			}
+			if (!err)
+				ibmcam->user++;
+		}
+	}
+	up(&ibmcam->lock);
+	if (err)
+		MOD_DEC_USE_COUNT;
+	return err;
+}
+
+/*
+ * ibmcam_close()
+ *
+ * This is part of Video 4 Linux API. The procedure
+ * stops streaming and deallocates all buffers that were earlier
+ * allocated in ibmcam_open().
+ *
+ * History:
+ * 1/22/00  Moved scratch buffer deallocation here.
+ * 1/27/00  Used IBMCAM_NUMSBUF as number of URB buffers.
+ * 5/24/00  Moved MOD_DEC_USE_COUNT outside of code that can sleep.
+ */
+static void ibmcam_close(struct video_device *dev)
+{
+	struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+	int i;
+
+	down(&ibmcam->lock);	
+
+	ibmcam_stop_isoc(ibmcam);
+
+	rvfree(ibmcam->fbuf, ibmcam->fbuf_size);
+	kfree(ibmcam->scratch);
+	for (i=0; i < IBMCAM_NUMSBUF; i++)
+		kfree(ibmcam->sbuf[i].data);
+
+	ibmcam->user--;
+
+	if (ibmcam->remove_pending) {
+		printk(KERN_INFO "ibmcam_close: Final disconnect.\n");
+		usb_ibmcam_release(ibmcam);
+	}
+	up(&ibmcam->lock);
+	MOD_DEC_USE_COUNT;
+}
+
+static int ibmcam_init_done(struct video_device *dev)
+{
+	return 0;
+}
+
+static long ibmcam_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
+{
+	return -EINVAL;
+}
+
+/*
+ * ibmcam_ioctl()
+ *
+ * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ *
+ * History:
+ * 1/22/00  Corrected VIDIOCSPICT to reject unsupported settings.
+ */
+static int ibmcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+
+	if (!IBMCAM_IS_OPERATIONAL(ibmcam))
+		return -EFAULT;
+
+	switch (cmd) {
+		case VIDIOCGCAP:
+		{
+			if (copy_to_user(arg, &ibmcam->vcap, sizeof(ibmcam->vcap)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCGCHAN:
+		{
+			if (copy_to_user(arg, &ibmcam->vchan, sizeof(ibmcam->vchan)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSCHAN:
+		{
+			int v;
+
+			if (copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if ((v < 0) || (v >= 3)) /* 3 grades of lighting conditions */
+				return -EINVAL;
+			if (v != ibmcam->vchan.channel) {
+				ibmcam->vchan.channel = v;
+				usb_ibmcam_change_lighting_conditions(ibmcam);
+			}
+			return 0;
+		}
+		case VIDIOCGPICT:
+		{
+			if (copy_to_user(arg, &ibmcam->vpic, sizeof(ibmcam->vpic)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSPICT:
+		{
+			struct video_picture tmp;
+			/*
+			 * Use temporary 'video_picture' structure to preserve our
+			 * own settings (such as color depth, palette) that we
+			 * aren't allowing everyone (V4L client) to change.
+			 */
+			if (copy_from_user(&tmp, arg, sizeof(tmp)))
+				return -EFAULT;
+			ibmcam->vpic.brightness = tmp.brightness;
+			ibmcam->vpic.hue = tmp.hue;
+			ibmcam->vpic.colour = tmp.colour;
+			ibmcam->vpic.contrast = tmp.contrast;
+			usb_ibmcam_adjust_picture(ibmcam);
+			return 0;
+		}
+		case VIDIOCSWIN:
+		{
+			struct video_window vw;
+
+			if (copy_from_user(&vw, arg, sizeof(vw)))
+				return -EFAULT;
+			if (vw.flags)
+				return -EINVAL;
+			if (vw.clipcount)
+				return -EINVAL;
+			if (vw.height != imgheight)
+				return -EINVAL;
+			if (vw.width != imgwidth)
+				return -EINVAL;
+
+			ibmcam->compress = 0;
+
+			return 0;
+		}
+		case VIDIOCGWIN:
+		{
+			struct video_window vw;
+
+			vw.x = 0;
+			vw.y = 0;
+			vw.width = imgwidth;
+			vw.height = imgheight;
+			vw.chromakey = 0;
+			vw.flags = usb_ibmcam_calculate_fps();
+
+			if (copy_to_user(arg, &vw, sizeof(vw)))
+				return -EFAULT;
+
+			return 0;
+		}
+		case VIDIOCGMBUF:
+		{
+			struct video_mbuf vm;
+
+			memset(&vm, 0, sizeof(vm));
+			vm.size = MAX_FRAME_SIZE * 2;
+			vm.frames = 2;
+			vm.offsets[0] = 0;
+			vm.offsets[1] = MAX_FRAME_SIZE;
+
+			if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+				return -EFAULT;
+
+			return 0;
+		}
+		case VIDIOCMCAPTURE:
+		{
+			struct video_mmap vm;
+
+			if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
+				return -EFAULT;
+
+			if (debug >= 1)
+				printk(KERN_DEBUG "frame: %d, size: %dx%d, format: %d\n",
+					vm.frame, vm.width, vm.height, vm.format);
+
+			if (vm.format != VIDEO_PALETTE_RGB24)
+				return -EINVAL;
+
+			if ((vm.frame != 0) && (vm.frame != 1))
+				return -EINVAL;
+
+			if (ibmcam->frame[vm.frame].grabstate == FRAME_GRABBING)
+				return -EBUSY;
+
+			/* Don't compress if the size changed */
+			if ((ibmcam->frame[vm.frame].width != vm.width) ||
+			    (ibmcam->frame[vm.frame].height != vm.height))
+				ibmcam->compress = 0;
+
+			ibmcam->frame[vm.frame].width = vm.width;
+			ibmcam->frame[vm.frame].height = vm.height;
+
+			/* Mark it as ready */
+			ibmcam->frame[vm.frame].grabstate = FRAME_READY;
+
+			return ibmcam_new_frame(ibmcam, vm.frame);
+		}
+		case VIDIOCSYNC:
+		{
+			int frame;
+
+			if (copy_from_user((void *)&frame, arg, sizeof(int)))
+				return -EFAULT;
+
+			if (debug >= 1)
+				printk(KERN_DEBUG "ibmcam: syncing to frame %d\n", frame);
+
+			switch (ibmcam->frame[frame].grabstate) {
+			case FRAME_UNUSED:
+				return -EINVAL;
+			case FRAME_READY:
+			case FRAME_GRABBING:
+			case FRAME_ERROR:
+			{
+				int ntries;
+		redo:
+				if (!IBMCAM_IS_OPERATIONAL(ibmcam))
+					return -EIO;
+				ntries = 0; 
+				do {
+					interruptible_sleep_on(&ibmcam->frame[frame].wq);
+					if (signal_pending(current)) {
+						if (flags & FLAGS_RETRY_VIDIOCSYNC) {
+							/* Polling apps will destroy frames with that! */
+							ibmcam_new_frame(ibmcam, frame);
+							usb_ibmcam_testpattern(ibmcam, 1, 0);
+							ibmcam->curframe = -1;
+							ibmcam->frame_num++;
+
+							/* This will request another frame. */
+							if (waitqueue_active(&ibmcam->frame[frame].wq))
+								wake_up_interruptible(&ibmcam->frame[frame].wq);
+							return 0;
+						} else {
+							/* Standard answer: not ready yet! */
+							return -EINTR;
+						}
+					}
+				} while (ibmcam->frame[frame].grabstate == FRAME_GRABBING);
+
+				if (ibmcam->frame[frame].grabstate == FRAME_ERROR) {
+					int ret = ibmcam_new_frame(ibmcam, frame);
+					if (ret < 0)
+						return ret;
+					goto redo;
+				}
+			}
+			case FRAME_DONE:
+				ibmcam->frame[frame].grabstate = FRAME_UNUSED;
+				break;
+			}
+
+			ibmcam->frame[frame].grabstate = FRAME_UNUSED;
+
+			return 0;
+		}
+		case VIDIOCGFBUF:
+		{
+			struct video_buffer vb;
+
+			memset(&vb, 0, sizeof(vb));
+			vb.base = NULL;	/* frame buffer not supported, not used */
+
+			if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+				return -EFAULT;
+
+ 			return 0;
+ 		}
+		case VIDIOCKEY:
+			return 0;
+
+		case VIDIOCCAPTURE:
+			return -EINVAL;
+
+		case VIDIOCSFBUF:
+
+		case VIDIOCGTUNER:
+		case VIDIOCSTUNER:
+
+		case VIDIOCGFREQ:
+		case VIDIOCSFREQ:
+
+		case VIDIOCGAUDIO:
+		case VIDIOCSAUDIO:
+			return -EINVAL;
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static long ibmcam_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
+{
+	struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+	int frmx = -1;
+	volatile struct ibmcam_frame *frame;
+
+	if (debug >= 1)
+		printk(KERN_DEBUG "ibmcam_read: %ld bytes, noblock=%d\n", count, noblock);
+
+	if (!IBMCAM_IS_OPERATIONAL(ibmcam) || (buf == NULL))
+		return -EFAULT;
+
+	/* See if a frame is completed, then use it. */
+	if (ibmcam->frame[0].grabstate >= FRAME_DONE)	/* _DONE or _ERROR */
+		frmx = 0;
+	else if (ibmcam->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
+		frmx = 1;
+
+	if (noblock && (frmx == -1))
+		return -EAGAIN;
+
+	/* If no FRAME_DONE, look for a FRAME_GRABBING state. */
+	/* See if a frame is in process (grabbing), then use it. */
+	if (frmx == -1) {
+		if (ibmcam->frame[0].grabstate == FRAME_GRABBING)
+			frmx = 0;
+		else if (ibmcam->frame[1].grabstate == FRAME_GRABBING)
+			frmx = 1;
+	}
+
+	/* If no frame is active, start one. */
+	if (frmx == -1)
+		ibmcam_new_frame(ibmcam, frmx = 0);
+
+	frame = &ibmcam->frame[frmx];
+
+restart:
+	if (!IBMCAM_IS_OPERATIONAL(ibmcam))
+		return -EIO;
+	while (frame->grabstate == FRAME_GRABBING) {
+		interruptible_sleep_on((void *)&frame->wq);
+		if (signal_pending(current))
+			return -EINTR;
+	}
+
+	if (frame->grabstate == FRAME_ERROR) {
+		frame->bytes_read = 0;
+		if (ibmcam_new_frame(ibmcam, frmx))
+			printk(KERN_ERR "ibmcam_read: ibmcam_new_frame error\n");
+		goto restart;
+	}
+
+	if (debug >= 1)
+		printk(KERN_DEBUG "ibmcam_read: frmx=%d, bytes_read=%ld, scanlength=%ld\n",
+			frmx, frame->bytes_read, frame->scanlength);
+
+	/* copy bytes to user space; we allow for partials reads */
+	if ((count + frame->bytes_read) > frame->scanlength)
+		count = frame->scanlength - frame->bytes_read;
+
+	if (copy_to_user(buf, frame->data + frame->bytes_read, count))
+		return -EFAULT;
+
+	frame->bytes_read += count;
+	if (debug >= 1)
+		printk(KERN_DEBUG "ibmcam_read: {copy} count used=%ld, new bytes_read=%ld\n",
+			count, frame->bytes_read);
+
+	if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
+		frame->bytes_read = 0;
+
+		/* Mark it as available to be used again. */
+		ibmcam->frame[frmx].grabstate = FRAME_UNUSED;
+		if (ibmcam_new_frame(ibmcam, frmx ? 0 : 1))
+			printk(KERN_ERR "ibmcam_read: ibmcam_new_frame returned error\n");
+	}
+
+	return count;
+}
+
+static int ibmcam_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+	struct usb_ibmcam *ibmcam = (struct usb_ibmcam *)dev;
+	unsigned long start = (unsigned long)adr;
+	unsigned long page, pos;
+
+	if (!IBMCAM_IS_OPERATIONAL(ibmcam))
+		return -EFAULT;
+
+	if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+		return -EINVAL;
+
+	pos = (unsigned long)ibmcam->fbuf;
+	while (size > 0) {
+		page = kvirt_to_pa(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	return 0;
+}
+
+static struct video_device ibmcam_template = {
+	"CPiA USB Camera",
+	VID_TYPE_CAPTURE,
+	VID_HARDWARE_CPIA,
+	ibmcam_open,
+	ibmcam_close,
+	ibmcam_read,
+	ibmcam_write,
+	NULL,
+	ibmcam_ioctl,
+	ibmcam_mmap,
+	ibmcam_init_done,
+	NULL,
+	0,
+	0
+};
+
+static void usb_ibmcam_configure_video(struct usb_ibmcam *ibmcam)
+{
+	if (ibmcam == NULL)
+		return;
+
+	RESTRICT_TO_RANGE(init_brightness, 0, 255);
+	RESTRICT_TO_RANGE(init_contrast, 0, 255);
+	RESTRICT_TO_RANGE(init_color, 0, 255);
+	RESTRICT_TO_RANGE(init_hue, 0, 255);
+	RESTRICT_TO_RANGE(hue_correction, 0, 255);
+
+	memset(&ibmcam->vpic, 0, sizeof(ibmcam->vpic));
+	memset(&ibmcam->vpic_old, 0x55, sizeof(ibmcam->vpic_old));
+
+	ibmcam->vpic.colour = init_color << 8;
+	ibmcam->vpic.hue = init_hue << 8;
+	ibmcam->vpic.brightness = init_brightness << 8;
+	ibmcam->vpic.contrast = init_contrast << 8;
+	ibmcam->vpic.whiteness = 105 << 8; /* This one isn't used */
+	ibmcam->vpic.depth = 24;
+	ibmcam->vpic.palette = VIDEO_PALETTE_RGB24;
+
+	memset(&ibmcam->vcap, 0, sizeof(ibmcam->vcap));
+	strcpy(ibmcam->vcap.name, "IBM USB Camera");
+	ibmcam->vcap.type = VID_TYPE_CAPTURE;
+	ibmcam->vcap.channels = 1;
+	ibmcam->vcap.audios = 0;
+	ibmcam->vcap.maxwidth = imgwidth;
+	ibmcam->vcap.maxheight = imgheight;
+	ibmcam->vcap.minwidth = min_imgwidth;
+	ibmcam->vcap.minheight = min_imgheight;
+
+	memset(&ibmcam->vchan, 0, sizeof(ibmcam->vchan));
+	ibmcam->vchan.flags = 0;
+	ibmcam->vchan.tuners = 0;
+	ibmcam->vchan.channel = 0;
+	ibmcam->vchan.type = VIDEO_TYPE_CAMERA;
+	strcpy(ibmcam->vchan.name, "Camera");
+}
+
+/*
+ * ibmcam_find_struct()
+ *
+ * This code searches the array of preallocated (static) structures
+ * and returns index of the first one that isn't in use. Returns -1
+ * if there are no free structures.
+ *
+ * History:
+ * 1/27/00  Created.
+ */
+static int ibmcam_find_struct(void)
+{
+	int i, u;
+
+	for (u = 0; u < MAX_IBMCAM; u++) {
+		struct usb_ibmcam *ibmcam = &cams[u];
+		if (!ibmcam->ibmcam_used) /* This one is free */
+		{
+			ibmcam->ibmcam_used = 1;	/* In use now */
+			for (i=0; i < IBMCAM_NUMFRAMES; i++)
+				init_waitqueue_head(&ibmcam->frame[i].wq);
+			init_MUTEX(&ibmcam->lock);	/* to 1 == available */
+			ibmcam->dev = NULL;
+			memcpy(&ibmcam->vdev, &ibmcam_template, sizeof(ibmcam_template));
+			return u;
+		}
+	}
+	return -1;
+}
+
+/*
+ * usb_ibmcam_probe()
+ *
+ * This procedure queries device descriptor and accepts the interface
+ * if it looks like IBM C-it camera.
+ *
+ * History:
+ * 1/22/00  Moved camera init code to ibmcam_open()
+ * 1/27/00  Changed to use static structures, added locking.
+ * 5/24/00  Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ */
+static void *usb_ibmcam_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_ibmcam *ibmcam = NULL;
+	const unsigned char *p_rev;
+	const struct usb_interface_descriptor *interface;
+	const struct usb_endpoint_descriptor *endpoint;
+	int devnum, model=0;
+
+	if (debug >= 1)
+		printk(KERN_DEBUG "ibmcam_probe(%p,%u.)\n", dev, ifnum);
+
+	/* We don't handle multi-config cameras */
+	if (dev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	/* Is it an IBM camera? */
+	if ((dev->descriptor.idVendor != 0x0545) ||
+	    (dev->descriptor.idProduct != 0x8080))
+		return NULL;
+
+	/* Check the version/revision */
+	p_rev = (const unsigned char *) &dev->descriptor.bcdDevice;
+	if (p_rev[1] == 0x00 && p_rev[0] == 0x02) {
+		if (ifnum != 2)
+			return NULL;
+		printk(KERN_INFO "IBM USB camera found (model 1).\n");
+		model = IBMCAM_MODEL_1;
+	} else if (p_rev[1] == 0x03 && p_rev[0] == 0x0A) {
+		if (ifnum != 0)
+			return NULL;
+		printk(KERN_INFO "IBM USB camera found (model 2).\n");
+		model = IBMCAM_MODEL_2;
+	} else {
+		printk(KERN_ERR "IBM camera revision=%02x.%02x not supported\n",
+		       p_rev[1], p_rev[0]);
+		return NULL;
+	}
+
+	/* Validate found interface: must have one ISO endpoint */
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	if (interface->bNumEndpoints != 1) {
+		printk(KERN_ERR "IBM camera: interface %d. has %u. endpoints!\n",
+		       ifnum, (unsigned)(interface->bNumEndpoints));
+		return NULL;
+	}
+	endpoint = &interface->endpoint[0];
+	if ((endpoint->bmAttributes & 0x03) != 0x01) {
+		printk(KERN_ERR "IBM camera: interface %d. has non-ISO endpoint!\n", ifnum);
+		return NULL;
+	}
+	if ((endpoint->bEndpointAddress & 0x80) == 0) {
+		printk(KERN_ERR "IBM camera: interface %d. has ISO OUT endpoint!\n", ifnum);
+		return NULL;
+	}
+
+	/* Validate options */
+	if (model == IBMCAM_MODEL_1) {
+		RESTRICT_TO_RANGE(lighting, 0, 2);
+		RESTRICT_TO_RANGE(videosize, VIDEOSIZE_128x96, VIDEOSIZE_352x288);
+	} else {
+		RESTRICT_TO_RANGE(lighting, 0, 15);
+		RESTRICT_TO_RANGE(videosize, VIDEOSIZE_176x144, VIDEOSIZE_352x240);
+	}
+
+	/* Code below may sleep, need to lock module while we are here */
+	MOD_INC_USE_COUNT;
+
+	devnum = ibmcam_find_struct();
+	if (devnum == -1) {
+		printk(KERN_INFO "IBM USB camera driver: Too many devices!\n");
+		ibmcam = NULL; /* Do not free, it's preallocated */
+		goto probe_done;
+	}
+	ibmcam = &cams[devnum];
+
+	down(&ibmcam->lock);
+	ibmcam->camera_model = model;
+	ibmcam->remove_pending = 0;
+	ibmcam->last_error = 0;
+	ibmcam->dev = dev;
+	ibmcam->iface = ifnum;
+	ibmcam->ifaceAltInactive = 0;
+	ibmcam->ifaceAltActive = 1;
+	ibmcam->video_endp = endpoint->bEndpointAddress;
+	ibmcam->iso_packet_len = 1014;
+	ibmcam->compress = 0;
+	ibmcam->user=0; 
+
+	usb_ibmcam_configure_video(ibmcam);
+	up (&ibmcam->lock);
+
+	if (video_register_device(&ibmcam->vdev, VFL_TYPE_GRABBER) == -1) {
+		printk(KERN_ERR "video_register_device failed\n");
+		ibmcam = NULL; /* Do not free, it's preallocated */
+	}
+	if (debug > 1)
+		printk(KERN_DEBUG "video_register_device() successful\n");
+probe_done:
+	MOD_DEC_USE_COUNT;
+	return ibmcam;
+}
+
+/*
+ * usb_ibmcam_release()
+ *
+ * This code does final release of struct usb_ibmcam. This happens
+ * after the device is disconnected -and- all clients closed their files.
+ *
+ * History:
+ * 1/27/00  Created.
+ */
+static void usb_ibmcam_release(struct usb_ibmcam *ibmcam)
+{
+	video_unregister_device(&ibmcam->vdev);
+	if (debug > 0)
+		printk(KERN_DEBUG "usb_ibmcam_release: Video unregistered.\n");
+	ibmcam->ibmcam_used = 0;
+}
+
+/*
+ * usb_ibmcam_disconnect()
+ *
+ * This procedure stops all driver activity, deallocates interface-private
+ * structure (pointed by 'ptr') and after that driver should be removable
+ * with no ill consequences.
+ *
+ * This code handles surprise removal. The ibmcam->user is a counter which
+ * increments on open() and decrements on close(). If we see here that
+ * this counter is not 0 then we have a client who still has us opened.
+ * We set ibmcam->remove_pending flag as early as possible, and after that
+ * all access to the camera will gracefully fail. These failures should
+ * prompt client to (eventually) close the video device, and then - in
+ * ibmcam_close() - we decrement ibmcam->ibmcam_used and usage counter.
+ *
+ * History:
+ * 1/22/00  Added polling of MOD_IN_USE to delay removal until all users gone.
+ * 1/27/00  Reworked to allow pending disconnects; see ibmcam_close()
+ * 5/24/00  Corrected to prevent race condition (MOD_xxx_USE_COUNT).
+ */
+static void usb_ibmcam_disconnect(struct usb_device *dev, void *ptr)
+{
+	static const char proc[] = "usb_ibmcam_disconnect";
+	struct usb_ibmcam *ibmcam = (struct usb_ibmcam *) ptr;
+
+	MOD_INC_USE_COUNT;
+
+	if (debug > 0)
+		printk(KERN_DEBUG "%s(%p,%p.)\n", proc, dev, ptr);
+
+	down(&ibmcam->lock);
+	ibmcam->remove_pending = 1; /* Now all ISO data will be ignored */
+
+	/* At this time we ask to cancel outstanding URBs */
+	ibmcam_stop_isoc(ibmcam);
+
+	ibmcam->dev = NULL;    	    /* USB device is no more */
+
+	if (ibmcam->user)
+		printk(KERN_INFO "%s: In use, disconnect pending.\n", proc);
+	else
+		usb_ibmcam_release(ibmcam);
+	up(&ibmcam->lock);
+	printk(KERN_INFO "IBM USB camera disconnected.\n");
+
+	MOD_DEC_USE_COUNT;
+}
+
+static struct usb_driver ibmcam_driver = {
+	"ibmcam",
+	usb_ibmcam_probe,
+	usb_ibmcam_disconnect,
+	{ NULL, NULL }
+};
+
+/*
+ * usb_ibmcam_init()
+ *
+ * This code is run to initialize the driver.
+ *
+ * History:
+ * 1/27/00  Reworked to use statically allocated usb_ibmcam structures.
+ */
+int usb_ibmcam_init(void)
+{
+	unsigned u;
+
+	/* Initialize struct */
+	for (u = 0; u < MAX_IBMCAM; u++) {
+		struct usb_ibmcam *ibmcam = &cams[u];
+		memset (ibmcam, 0, sizeof(struct usb_ibmcam));
+	}
+	return usb_register(&ibmcam_driver);
+}
+
+void usb_ibmcam_cleanup(void)
+{
+	usb_deregister(&ibmcam_driver);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return usb_ibmcam_init();
+}
+
+void cleanup_module(void)
+{
+	usb_ibmcam_cleanup();
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ibmcam.h linux.18p8/drivers/usb/ibmcam.h
--- linux.vanilla/drivers/usb/ibmcam.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/ibmcam.h	Fri Sep  8 17:19:39 2000
@@ -0,0 +1,240 @@
+/*
+ * Header file for USB IBM C-It Video Camera driver.
+ *
+ * Supports IBM C-It Video Camera.
+ *
+ * This driver is based on earlier work of:
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ */
+
+#ifndef __LINUX_IBMCAM_H
+#define __LINUX_IBMCAM_H
+
+#include <linux/list.h>
+
+#define USES_IBMCAM_PUTPIXEL    0       /* 0=Fast/oops 1=Slow/secure */
+
+/* Video Size 384 x 288 x 3 bytes for RGB */
+/* 384 because xawtv tries to grab 384 even though we tell it 352 is our max */
+#define V4L_FRAME_WIDTH         384
+#define V4L_FRAME_WIDTH_USED	352
+#define V4L_FRAME_HEIGHT        288
+#define V4L_BYTES_PER_PIXEL     3
+#define MAX_FRAME_SIZE          (V4L_FRAME_WIDTH * V4L_FRAME_HEIGHT * V4L_BYTES_PER_PIXEL)
+
+/* Camera capabilities (maximum) */
+#define CAMERA_IMAGE_WIDTH      352
+#define CAMERA_IMAGE_HEIGHT     288
+#define CAMERA_IMAGE_LINE_SZ    ((CAMERA_IMAGE_WIDTH * 3) / 2) /* Bytes */
+#define CAMERA_URB_FRAMES       32
+#define CAMERA_MAX_ISO_PACKET   1023 /* 1022 actually sent by camera */
+
+#define IBMCAM_NUMFRAMES	2
+#define IBMCAM_NUMSBUF		2
+
+#define FRAMES_PER_DESC		(CAMERA_URB_FRAMES)
+#define FRAME_SIZE_PER_DESC	(CAMERA_MAX_ISO_PACKET)
+
+/* This macro restricts an int variable to an inclusive range */
+#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
+
+/*
+ * This macro performs bounds checking - use it when working with
+ * new formats, or else you may get oopses all over the place.
+ * If pixel falls out of bounds then it gets shoved back (as close
+ * to place of offence as possible) and is painted bright red.
+ */
+#define IBMCAM_PUTPIXEL(fr, ix, iy, vr, vg, vb) { \
+	register unsigned char *pf; \
+	int limiter = 0, mx, my; \
+	mx = ix; \
+	my = iy; \
+	if (mx < 0) { \
+		mx=0; \
+		limiter++; \
+	} else if (mx >= 352) { \
+		mx=351; \
+		limiter++; \
+	} \
+	if (my < 0) { \
+		my = 0; \
+		limiter++; \
+	} else if (my >= V4L_FRAME_HEIGHT) { \
+		my = V4L_FRAME_HEIGHT - 1; \
+		limiter++; \
+	} \
+	pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*352 + (ix)); \
+	if (limiter) { \
+		*pf++ = 0; \
+		*pf++ = 0; \
+		*pf++ = 0xFF; \
+	} else { \
+		*pf++ = (vb); \
+		*pf++ = (vg); \
+		*pf++ = (vr); \
+	} \
+}
+
+/*
+ * We use macros to do YUV -> RGB conversion because this is
+ * very important for speed and totally unimportant for size.
+ *
+ * YUV -> RGB Conversion
+ * ---------------------
+ *
+ * B = 1.164*(Y-16)		    + 2.018*(V-128)
+ * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
+ * R = 1.164*(Y-16) + 1.596*(U-128)
+ *
+ * If you fancy integer arithmetics (as you should), hear this:
+ *
+ * 65536*B = 76284*(Y-16)		  + 132252*(V-128)
+ * 65536*G = 76284*(Y-16) -  53281*(U-128) -  25625*(V-128)
+ * 65536*R = 76284*(Y-16) + 104595*(U-128)
+ *
+ * Make sure the output values are within [0..255] range.
+ */
+#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
+#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
+    int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
+    mm_y = (my) - 16;  \
+    mm_u = (mu) - 128; \
+    mm_v = (mv) - 128; \
+    mm_yc= mm_y * 76284; \
+    mm_b = (mm_yc		+ 132252*mm_v	) >> 16; \
+    mm_g = (mm_yc -  53281*mm_u -  25625*mm_v	) >> 16; \
+    mm_r = (mm_yc + 104595*mm_u			) >> 16; \
+    mb = LIMIT_RGB(mm_b); \
+    mg = LIMIT_RGB(mm_g); \
+    mr = LIMIT_RGB(mm_r); \
+}
+
+/* Debugging aid */
+#define IBMCAM_SAY_AND_WAIT(what) { \
+	wait_queue_head_t wq; \
+	init_waitqueue_head(&wq); \
+	printk(KERN_INFO "Say: %s\n", what); \
+	interruptible_sleep_on_timeout (&wq, HZ*3); \
+}
+
+/*
+ * This macro checks if ibmcam is still operational. The 'ibmcam'
+ * pointer must be valid, ibmcam->dev must be valid, we are not
+ * removing the device and the device has not erred on us.
+ */
+#define IBMCAM_IS_OPERATIONAL(ibm_cam) (\
+	(ibm_cam != NULL) && \
+	((ibm_cam)->dev != NULL) && \
+	((ibm_cam)->last_error == 0) && \
+	(!(ibm_cam)->remove_pending))
+
+enum {
+	STATE_SCANNING,		/* Scanning for header */
+	STATE_LINES,		/* Parsing lines */
+};
+
+enum {
+	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
+	FRAME_READY,		/* Ready to start grabbing */
+	FRAME_GRABBING,		/* In the process of being grabbed into */
+	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
+	FRAME_ERROR,		/* Something bad happened while processing */
+};
+
+struct usb_device;
+
+struct ibmcam_sbuf {
+	char *data;
+	urb_t *urb;
+};
+
+struct ibmcam_frame {
+	char *data;		/* Frame buffer */
+	int order_uv;		/* True=UV False=VU */
+	int order_yc;		/* True=Yc False=cY ('c'=either U or V) */
+	unsigned char hdr_sig;	/* "00 FF 00 ??" where 'hdr_sig' is '??' */
+
+	int width;		/* Width application is expecting */
+	int height;		/* Height */
+
+	int frmwidth;		/* Width the frame actually is */
+	int frmheight;		/* Height */
+
+	volatile int grabstate;	/* State of grabbing */
+	int scanstate;		/* State of scanning */
+
+	int curline;		/* Line of frame we're working on */
+
+	long scanlength;	/* uncompressed, raw data length of frame */
+	long bytes_read;	/* amount of scanlength that has been read from *data */
+
+	wait_queue_head_t wq;	/* Processes waiting */
+};
+
+#define	IBMCAM_MODEL_1	1	/* XVP-501, 3 interfaces, rev. 0.02 */
+#define IBMCAM_MODEL_2	2	/* KSX-X9903, 2 interfaces, rev. 3.0a */
+
+struct usb_ibmcam {
+	struct video_device vdev;
+
+	/* Device structure */
+	struct usb_device *dev;
+
+	unsigned char iface;                            /* Video interface number */
+	unsigned char ifaceAltActive, ifaceAltInactive; /* Alt settings */
+
+	struct semaphore lock;
+	int user;		/* user count for exclusive use */
+
+	int ibmcam_used;        /* Is this structure in use? */
+	int initialized;	/* Had we already sent init sequence? */
+	int camera_model;	/* What type of IBM camera we got? */
+	int streaming;		/* Are we streaming Isochronous? */
+	int grabbing;		/* Are we grabbing? */
+	int last_error;		/* What calamity struck us? */
+
+	int compress;		/* Should the next frame be compressed? */
+
+	char *fbuf;		/* Videodev buffer area */
+	int fbuf_size;		/* Videodev buffer size */
+
+	int curframe;
+	struct ibmcam_frame frame[IBMCAM_NUMFRAMES];	/* Double buffering */
+
+	int cursbuf;		/* Current receiving sbuf */
+	struct ibmcam_sbuf sbuf[IBMCAM_NUMSBUF];	/* Double buffering */
+	volatile int remove_pending;	/* If set then about to exit */
+
+        /*
+	 * Scratch space from the Isochronous pipe.
+	 * Scratch buffer should contain at least one pair of lines
+	 * (CAMERA_IMAGE_LINE_SZ). We set it to two pairs here.
+	 * This will be approximately 2 KB. HOWEVER in reality this
+	 * buffer must be as large as hundred of KB because otherwise
+	 * you'll get lots of overflows because V4L client may request
+	 * frames not as uniformly as USB sources them.
+	 */
+	unsigned char *scratch;
+	int scratchlen;
+
+	struct video_picture vpic, vpic_old;	/* Picture settings */
+	struct video_capability vcap;		/* Video capabilities */
+	struct video_channel vchan;	/* May be used for tuner support */
+	unsigned char video_endp;	/* 0x82 for IBM camera */
+        int has_hdr;
+        int frame_num;
+	int iso_packet_len;		/* Videomode-dependent, saves bus bandwidth */
+
+	/* Statistics that can be overlayed on screen */
+        unsigned long urb_count;        /* How many URBs we received so far */
+        unsigned long urb_length;       /* Length of last URB */
+        unsigned long data_count;       /* How many bytes we received */
+        unsigned long header_count;     /* How many frame headers we found */
+	unsigned long scratch_ovf_count;/* How many times we overflowed scratch */
+	unsigned long iso_skip_count;	/* How many empty ISO packets received */
+	unsigned long iso_err_count;	/* How many bad ISO packets received */
+};
+
+#endif /* __LINUX_IBMCAM_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/inits.h linux.18p8/drivers/usb/inits.h
--- linux.vanilla/drivers/usb/inits.h	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/inits.h	Thu Jan  1 01:00:00 1970
@@ -1,6 +0,0 @@
-int bp_mouse_init(void);
-int usb_kbd_init(void);
-int usb_audio_init(void);
-int hub_init(void);
-void hub_cleanup(void);
-void usb_mouse_cleanup(void);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/inode.c linux.18p8/drivers/usb/inode.c
--- linux.vanilla/drivers/usb/inode.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/inode.c	Thu Sep 14 15:35:56 2000
@@ -0,0 +1,730 @@
+/*****************************************************************************/
+
+/*
+ *	inode.c  --  Inode/Dentry functions for the USB device file system.
+ *
+ *	Copyright (C) 2000
+ *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  $Id: inode.c,v 1.3 2000/01/11 13:58:25 tom Exp $
+ *
+ *  History:
+ *   0.1  04.01.2000  Created
+ */
+
+/*****************************************************************************/
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/locks.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+#include <asm/uaccess.h>
+
+/* --------------------------------------------------------------------- */
+
+static LIST_HEAD(superlist);
+
+struct special {
+	const char *name;
+	struct inode_operations *iops;
+	struct inode *inode;
+	struct list_head inodes;
+};
+
+static struct inode_operations usbdevfs_devices_inode_operations = {
+	default_file_ops: &usbdevfs_devices_fops,
+};
+
+static struct inode_operations usbdevfs_drivers_inode_operations = {
+	default_file_ops: &usbdevfs_drivers_fops,
+};
+
+static struct inode_operations usbdevfs_device_inode_operations = {
+	default_file_ops: &usbdevfs_device_file_operations,
+};
+
+static struct special special[] = { 
+	{ "devices", &usbdevfs_devices_inode_operations,  },
+	{ "drivers", &usbdevfs_drivers_inode_operations,  }
+};
+
+#define NRSPECIAL (sizeof(special)/sizeof(special[0]))
+
+/* --------------------------------------------------------------------- */
+
+static int dnumber(struct dentry *dentry)
+{
+	const char *name;
+	unsigned int s;
+
+	if (dentry->d_name.len != 3)
+		return -1;
+	name = dentry->d_name.name;
+	if (name[0] < '0' || name[0] > '9' ||
+	    name[1] < '0' || name[1] > '9' ||
+	    name[2] < '0' || name[2] > '9')
+		return -1;
+	s = name[0] - '0';
+	s = s * 10 + name[1] - '0';
+	s = s * 10 + name[2] - '0';
+	return s;
+}
+
+/*
+ * utility functions; should be called with the kernel lock held
+ * to protect against busses/devices appearing/disappearing
+ */
+
+static void new_dev_inode(struct usb_device *dev, struct super_block *sb)
+{
+	struct inode *inode;
+	unsigned int devnum = dev->devnum;
+	unsigned int busnum = dev->bus->busnum;
+
+	if (devnum < 1 || devnum > 127 || busnum > 255)
+		return;
+	inode = iget(sb, IDEVICE | (busnum << 8) | devnum);
+	if (!inode) {
+		printk(KERN_ERR "usbdevfs: cannot create inode for bus %u device %u\n", busnum, devnum);
+		return;
+	}
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_uid = sb->u.usbdevfs_sb.devuid;
+	inode->i_gid = sb->u.usbdevfs_sb.devgid;
+	inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG;
+	inode->i_op = &usbdevfs_device_inode_operations;
+	inode->i_size = sizeof(struct usb_device_descriptor);
+	inode->u.usbdev_i.p.dev = dev;
+	list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
+	list_add_tail(&inode->u.usbdev_i.dlist, &dev->inodes);
+}
+
+static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb)
+{
+	unsigned int i;
+
+	if (!dev)
+		return;
+	new_dev_inode(dev, sb);
+	for (i = 0; i < dev->maxchild; i++) {
+                if (!dev->children[i])
+                        continue;
+		recurse_new_dev_inode(dev->children[i], sb);
+	}
+}
+
+static void new_bus_inode(struct usb_bus *bus, struct super_block *sb)
+{
+	struct inode *inode;
+	unsigned int busnum = bus->busnum;
+
+	if (busnum > 255)
+		return;
+	inode = iget(sb, IBUS | (busnum << 8));
+	if (!inode) {
+		printk(KERN_ERR "usbdevfs: cannot create inode for bus %u\n", busnum);
+		return;
+	}
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_uid = sb->u.usbdevfs_sb.busuid;
+	inode->i_gid = sb->u.usbdevfs_sb.busgid;
+	inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR;
+	inode->i_op = &usbdevfs_bus_inode_operations;
+	inode->u.usbdev_i.p.bus = bus;
+	list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
+	list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes);
+}
+
+static void free_inode(struct inode *inode)
+{
+	inode->u.usbdev_i.p.bus = NULL;
+	inode->u.usbdev_i.p.dev = NULL;
+	inode->i_mode &= ~S_IRWXUGO;
+	inode->i_uid = inode->i_gid = 0;
+	inode->i_size = 0;
+	list_del(&inode->u.usbdev_i.slist);
+	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
+	list_del(&inode->u.usbdev_i.dlist);
+	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
+	iput(inode);
+}
+
+static struct usb_bus *usbdevfs_findbus(int busnr)
+{
+        struct list_head *list;
+        struct usb_bus *bus;
+
+        for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
+                bus = list_entry(list, struct usb_bus, bus_list);
+                if (bus->busnum == busnr)
+                        return bus;
+        }
+        return NULL;
+}
+
+#if 0
+static struct usb_device *finddev(struct usb_device *dev, int devnr)
+{
+        unsigned int i;
+        struct usb_device *d2;
+
+        if (!dev)
+                return NULL;
+        if (dev->devnum == devnr)
+                return dev;
+        for (i = 0; i < dev->maxchild; i++) {
+                if (!dev->children[i])
+                        continue;
+                if ((d2 = finddev(dev->children[i], devnr)))
+                        return d2;
+        }
+        return NULL;
+}
+
+static struct usb_device *usbdevfs_finddevice(struct usb_bus *bus, int devnr)
+{
+        return finddev(bus->root_hub, devnr);
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+static int usbdevfs_revalidate(struct dentry *dentry, int flags)
+{
+	struct inode *inode = dentry->d_inode;
+
+        if (!inode)
+                return 0;
+	if (ITYPE(inode->i_ino) == IBUS && !inode->u.usbdev_i.p.bus)
+		return 0;
+	if (ITYPE(inode->i_ino) == IDEVICE && !inode->u.usbdev_i.p.dev)
+		return 0;
+	return 1;
+}
+
+static struct dentry_operations usbdevfs_dentry_operations = {
+	d_revalidate:	usbdevfs_revalidate,
+};
+
+static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry)
+{
+	int busnr;
+	unsigned long ino = 0;
+	unsigned int i;
+	struct inode *inode;
+
+	/* sanity check */
+	if (dir->i_ino != IROOT)
+		return ERR_PTR(-EINVAL);
+	dentry->d_op = &usbdevfs_dentry_operations;
+	busnr = dnumber(dentry);
+	if (busnr >= 0 && busnr <= 255)
+		ino = IBUS | (busnr << 8);
+	if (!ino) {
+		for (i = 0; i < NRSPECIAL; i++) {
+			if (strlen(special[i].name) == dentry->d_name.len && 
+			    !strncmp(special[i].name, dentry->d_name.name, dentry->d_name.len)) {
+				ino = ISPECIAL | (i + IROOT + 1);
+				break;
+			}
+		}
+	}
+	if (!ino)
+		return ERR_PTR(-ENOENT);
+	inode = iget(dir->i_sb, ino);
+	if (!inode)
+		return ERR_PTR(-EINVAL);
+	if (inode && ITYPE(ino) == IBUS && inode->u.usbdev_i.p.bus == NULL) {
+		iput(inode);
+		inode = NULL;
+	}
+	d_add(dentry, inode);
+	return NULL;
+}
+
+static struct dentry *usbdevfs_bus_lookup(struct inode *dir, struct dentry *dentry)
+{
+	struct inode *inode;
+	int devnr;
+
+	/* sanity check */
+	if (ITYPE(dir->i_ino) != IBUS)
+		return ERR_PTR(-EINVAL);
+	dentry->d_op = &usbdevfs_dentry_operations;
+	devnr = dnumber(dentry);
+	if (devnr < 1 || devnr > 127)
+		return ERR_PTR(-ENOENT);
+	inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr);
+	if (!inode)
+		return ERR_PTR(-EINVAL);
+	if (inode && inode->u.usbdev_i.p.dev == NULL) {
+		iput(inode);
+		inode = NULL;
+	}
+	d_add(dentry, inode);
+	return NULL;
+}
+
+static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	unsigned long ino = inode->i_ino;
+	struct special *spec;
+	struct list_head *list;
+	struct usb_bus *bus;
+	char numbuf[8];
+	unsigned int i;
+
+	/* sanity check */
+	if (ino != IROOT)
+		return -EINVAL;
+	i = filp->f_pos;
+	switch (i) {
+	case 0:
+		if (filldir(dirent, ".", 1, i, IROOT) < 0)
+			return 0;
+		filp->f_pos++;
+		i++;
+		/* fall through */
+
+	case 1:
+		if (filldir(dirent, "..", 2, i, IROOT) < 0)
+			return 0;
+		filp->f_pos++;
+		i++;
+		/* fall through */
+
+	default:
+		
+		while (i >= 2 && i < 2+NRSPECIAL) {
+			spec = &special[filp->f_pos-2];
+			if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT)) < 0)
+				return 0;
+			filp->f_pos++;
+			i++;
+		}
+		if (i < 2+NRSPECIAL)
+			return 0;
+		i -= 2+NRSPECIAL;
+		lock_kernel();
+		for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
+			if (i > 0) {
+				i--;
+				continue;
+			}
+			bus = list_entry(list, struct usb_bus, bus_list);
+			sprintf(numbuf, "%03d", bus->busnum);
+			if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8)) < 0)
+				break;
+			filp->f_pos++;
+		}
+		unlock_kernel();
+		return 0;
+	}
+}
+
+static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct file *filp, void *dirent, filldir_t filldir)
+{
+	char numbuf[8];
+	unsigned int i;
+
+	if (!dev)
+		return pos;
+	sprintf(numbuf, "%03d", dev->devnum);
+	if (pos > 0)
+		pos--;
+	else {
+		if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff)) < 0)
+			return -1;
+		filp->f_pos++;
+	}
+	for (i = 0; i < dev->maxchild; i++) {
+		if (!dev->children[i])
+			continue;
+		pos = bus_readdir(dev->children[i], ino, pos, filp, dirent, filldir);
+		if (pos < 0)
+			return -1;
+	}
+	return pos;
+}
+
+static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	unsigned long ino = inode->i_ino;
+	struct usb_bus *bus;
+
+	/* sanity check */
+	if (ITYPE(ino) != IBUS)
+		return -EINVAL;
+	switch ((unsigned int)filp->f_pos) {
+	case 0:
+		if (filldir(dirent, ".", 1, filp->f_pos, ino) < 0)
+			return 0;
+		filp->f_pos++;
+		/* fall through */
+
+	case 1:
+		if (filldir(dirent, "..", 2, filp->f_pos, IROOT) < 0)
+			return 0;
+		filp->f_pos++;
+		/* fall through */
+
+	default:
+		lock_kernel();
+		bus = usbdevfs_findbus(IBUSNR(ino));
+		bus_readdir(bus->root_hub, IDEVICE | ((bus->busnum & 0xff) << 8), filp->f_pos-2, filp, dirent, filldir);
+		unlock_kernel();
+		return 0;
+	}
+}
+
+static struct file_operations usbdevfs_root_file_operations = {
+	readdir: usbdevfs_root_readdir,
+};
+
+static struct inode_operations usbdevfs_root_inode_operations = {
+	default_file_ops: &usbdevfs_root_file_operations,
+	lookup: usbdevfs_root_lookup,
+};
+
+static struct file_operations usbdevfs_bus_file_operations = {
+	readdir: usbdevfs_bus_readdir,
+};
+
+static struct inode_operations usbdevfs_bus_inode_operations = {
+	default_file_ops: &usbdevfs_bus_file_operations,
+	lookup: usbdevfs_bus_lookup,
+};
+
+static void usbdevfs_read_inode(struct inode *inode)
+{
+	struct special *spec;
+
+	inode->i_ctime = inode->i_mtime = inode->i_atime = CURRENT_TIME;
+	inode->i_mode = S_IFREG;
+	inode->i_gid = inode->i_uid = 0;
+	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
+	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
+	inode->u.usbdev_i.p.dev = NULL;
+	inode->u.usbdev_i.p.bus = NULL;
+	switch (ITYPE(inode->i_ino)) {
+	case ISPECIAL:
+		if (inode->i_ino == IROOT) {
+			inode->i_op = &usbdevfs_root_inode_operations;
+			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+			return;
+		}
+		if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL)
+			return;
+		spec = &special[inode->i_ino-(IROOT+1)];
+		inode->i_op = spec->iops;
+		return;
+
+	case IDEVICE:
+		return;
+
+	case IBUS:
+		return;
+
+	default:
+		return;
+        }
+}
+
+static void usbdevfs_put_super(struct super_block *sb)
+{
+	list_del(&sb->u.usbdevfs_sb.slist);
+	INIT_LIST_HEAD(&sb->u.usbdevfs_sb.slist);
+	while (!list_empty(&sb->u.usbdevfs_sb.ilist))
+		free_inode(list_entry(sb->u.usbdevfs_sb.ilist.next, struct inode, u.usbdev_i.slist));
+	MOD_DEC_USE_COUNT;
+}
+
+static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf, int x)
+{
+        buf->f_type = USBDEVICE_SUPER_MAGIC;
+        buf->f_bsize = PAGE_SIZE/sizeof(long);   /* ??? */
+        buf->f_bfree = 0;
+        buf->f_bavail = 0;
+        buf->f_ffree = 0;
+        buf->f_namelen = NAME_MAX;
+        return 0;
+}
+
+static struct super_operations usbdevfs_sops = { 
+	read_inode:	usbdevfs_read_inode,
+	put_super:	usbdevfs_put_super,
+	statfs:		usbdevfs_statfs,
+};
+
+struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent)
+{
+        struct inode *root_inode, *inode;
+	struct list_head *blist;
+	struct usb_bus *bus;
+	unsigned int i;
+	uid_t devuid = 0, busuid = 0, listuid = 0;
+	gid_t devgid = 0, busgid = 0, listgid = 0;
+	umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO;
+	char *curopt = NULL, *value;
+
+	MOD_INC_USE_COUNT;
+	/* parse options */
+	if (data)
+		curopt = strtok(data, ",");
+	for (; curopt; curopt = strtok(NULL, ",")) {
+		if ((value = strchr(curopt, '=')) != NULL)
+			*value++ = 0;
+		if (!strcmp(curopt, "devuid")) {
+			if (!value || !value[0])
+				goto opterr;
+			devuid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "devgid")) {
+			if (!value || !value[0])
+				goto opterr;
+			devgid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "devmode")) {
+			if (!value || !value[0])
+				goto opterr;
+			devmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "busuid")) {
+			if (!value || !value[0])
+				goto opterr;
+			busuid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "busgid")) {
+			if (!value || !value[0])
+				goto opterr;
+			busgid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "busmode")) {
+			if (!value || !value[0])
+				goto opterr;
+			busmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "listuid")) {
+			if (!value || !value[0])
+				goto opterr;
+			listuid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "listgid")) {
+			if (!value || !value[0])
+				goto opterr;
+			listgid = simple_strtoul(value, &value, 0);
+			if (*value)
+				goto opterr;
+		}
+		if (!strcmp(curopt, "listmode")) {
+			if (!value || !value[0])
+				goto opterr;
+			listmode = simple_strtoul(value, &value, 0) & S_IRWXUGO;
+			if (*value)
+				goto opterr;
+		}
+	}
+	/* fill superblock */
+        s->s_blocksize = 1024;
+        s->s_blocksize_bits = 10;
+        s->s_magic = USBDEVICE_SUPER_MAGIC;
+        s->s_op = &usbdevfs_sops;
+	INIT_LIST_HEAD(&s->u.usbdevfs_sb.slist);
+	INIT_LIST_HEAD(&s->u.usbdevfs_sb.ilist);
+	s->u.usbdevfs_sb.devuid = devuid;
+	s->u.usbdevfs_sb.devgid = devgid;
+	s->u.usbdevfs_sb.devmode = devmode;
+	s->u.usbdevfs_sb.busuid = busuid;
+	s->u.usbdevfs_sb.busgid = busgid;
+	s->u.usbdevfs_sb.busmode = busmode;
+	root_inode = iget(s, IROOT);
+        if (!root_inode)
+                goto out_no_root;
+        s->s_root = d_alloc_root(root_inode, NULL);
+        if (!s->s_root)
+                goto out_no_root;
+	list_add_tail(&s->u.usbdevfs_sb.slist, &superlist);
+	for (i = 0; i < NRSPECIAL; i++) {
+		if (!(inode = iget(s, IROOT+1+i)))
+			continue;
+		inode->i_uid = listuid;
+		inode->i_gid = listgid;
+		inode->i_mode = listmode | S_IFREG;
+		special[i].inode = inode;
+		list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
+		list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
+	}
+	lock_kernel();
+	for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) {
+		bus = list_entry(blist, struct usb_bus, bus_list);
+		new_bus_inode(bus, s);
+		recurse_new_dev_inode(bus->root_hub, s);
+	}
+	unlock_kernel();
+        return s;
+
+ out_no_root:
+        printk("usbdevfs_read_super: get root inode failed\n");
+        iput(root_inode);
+	MOD_DEC_USE_COUNT;
+        return NULL;
+
+ opterr:
+        printk(KERN_WARNING "usbdevfs: mount parameter error\n");
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, 0);
+
+/* --------------------------------------------------------------------- */
+
+static void update_special_inodes (void)
+{
+	int i;
+	for (i = 0; i < NRSPECIAL; i++) {
+		struct inode *inode = special[i].inode;
+		if (inode)
+			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	}
+}
+
+
+void usbdevfs_add_bus(struct usb_bus *bus)
+{
+	struct list_head *slist;
+
+	lock_kernel();
+	for (slist = superlist.next; slist != &superlist; slist = slist->next)
+		new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+	update_special_inodes();
+	unlock_kernel();
+	usbdevfs_conn_disc_event();
+}
+
+void usbdevfs_remove_bus(struct usb_bus *bus)
+{
+	lock_kernel();
+	while (!list_empty(&bus->inodes))
+		free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist));
+	update_special_inodes();
+	unlock_kernel();
+	usbdevfs_conn_disc_event();
+}
+
+void usbdevfs_add_device(struct usb_device *dev)
+{
+	struct list_head *slist;
+
+	lock_kernel();
+	for (slist = superlist.next; slist != &superlist; slist = slist->next)
+		new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+	update_special_inodes();
+	unlock_kernel();
+	usbdevfs_conn_disc_event();
+}
+
+void usbdevfs_remove_device(struct usb_device *dev)
+{
+	struct dev_state *ds;
+	struct siginfo sinfo;
+
+	lock_kernel();
+	while (!list_empty(&dev->inodes))
+		free_inode(list_entry(dev->inodes.next, struct inode, u.usbdev_i.dlist));
+	while (!list_empty(&dev->filelist)) {
+		ds = list_entry(dev->filelist.next, struct dev_state, list);
+		list_del(&ds->list);
+		INIT_LIST_HEAD(&ds->list);
+		down_write(&ds->devsem);
+		ds->dev = NULL;
+		up_write(&ds->devsem);
+		if (ds->discsignr) {
+			sinfo.si_signo = SIGPIPE;
+			sinfo.si_errno = EPIPE;
+			sinfo.si_code = SI_ASYNCIO;
+			sinfo.si_addr = ds->disccontext;
+			send_sig_info(ds->discsignr, &sinfo, ds->disctask);
+		}
+	}
+	
+	update_special_inodes();
+	unlock_kernel();
+	usbdevfs_conn_disc_event();
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef CONFIG_PROC_FS		
+static struct proc_dir_entry *usbdir = NULL;
+#endif	
+
+int __init usbdevfs_init(void)
+{
+	int ret;
+
+	for (ret = 0; ret < NRSPECIAL; ret++) {
+		INIT_LIST_HEAD(&special[ret].inodes);
+	}
+	if ((ret = usb_register(&usbdevfs_driver)))
+		return ret;
+	if ((ret = register_filesystem(&usbdevice_fs_type)))
+		usb_deregister(&usbdevfs_driver);
+#ifdef CONFIG_PROC_FS		
+	/* create mount point for usbdevfs */
+	usbdir = proc_mkdir("usb", proc_bus);
+#endif	
+	return ret;
+}
+
+void __exit usbdevfs_cleanup(void)
+{
+#ifdef CONFIG_PROC_FS	
+        if (usbdir)
+                remove_proc_entry("usb", proc_bus);
+#endif
+	usb_deregister(&usbdevfs_driver);
+	unregister_filesystem(&usbdevice_fs_type);
+}
+
+#if 0
+module_init(usbdevfs_init);
+module_exit(usbdevfs_cleanup);
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/input.c linux.18p8/drivers/usb/input.c
--- linux.vanilla/drivers/usb/input.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/input.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,408 @@
+/*
+ * $Id: input.c,v 1.7 2000/05/28 17:31:36 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  The input layer module itself
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/kcomp.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+EXPORT_SYMBOL(input_register_device);
+EXPORT_SYMBOL(input_unregister_device);
+EXPORT_SYMBOL(input_register_handler);
+EXPORT_SYMBOL(input_unregister_handler);
+EXPORT_SYMBOL(input_register_minor);
+EXPORT_SYMBOL(input_unregister_minor);
+EXPORT_SYMBOL(input_open_device);
+EXPORT_SYMBOL(input_close_device);
+EXPORT_SYMBOL(input_event);
+
+#define INPUT_MAJOR	13
+#define INPUT_DEVICES	256
+
+static struct input_dev *input_dev = NULL;
+static struct input_handler *input_handler = NULL;
+static struct input_handler *input_table[8] = { NULL, /* ... */ };
+static devfs_handle_t input_devfs_handle = NULL;
+static int input_number = 0;
+static long input_devices[NBITS(INPUT_DEVICES)] = { 0, /* ... */ };
+
+void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct input_handle *handle = dev->handle;
+
+/*
+ * Filter non-events, and bad input values out.
+ */
+
+	if (type > EV_MAX || !test_bit(type, dev->evbit))
+		return;
+
+	switch (type) {
+
+		case EV_KEY:
+
+			if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
+				return;
+
+			if (value == 2) break;
+
+			change_bit(code, dev->key);
+
+			if (test_bit(EV_REP, dev->evbit) && dev->timer.function) {
+				if (value) {
+					mod_timer(&dev->timer, jiffies + dev->rep[REP_DELAY]);
+					dev->repeat_key = code;
+					break;
+				}
+				if (dev->repeat_key == code)
+					del_timer(&dev->timer);
+			}
+
+			break;
+		
+		case EV_ABS:
+
+			if (code > ABS_MAX || !test_bit(code, dev->absbit))
+				return;
+
+			if (dev->absfuzz[code]) {
+				if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
+				    (value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
+					return;
+
+				if ((value > dev->abs[code] - dev->absfuzz[code]) &&
+				    (value < dev->abs[code] + dev->absfuzz[code]))
+					value = (dev->abs[code] * 3 + value) >> 2;
+
+				if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
+				    (value < dev->abs[code] + (dev->absfuzz[code] << 1)))
+					value = (dev->abs[code] + value) >> 1;
+			}
+
+			if (dev->abs[code] == value)
+				return;
+
+			dev->abs[code] = value;
+			break;
+
+		case EV_REL:
+
+			if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
+				return;
+
+			break;
+
+		case EV_LED:
+	
+			if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
+				return;
+
+			change_bit(code, dev->led);
+			if (dev->event) dev->event(dev, type, code, value);	
+	
+			break;
+
+		case EV_SND:
+	
+			if (code > SND_MAX || !test_bit(code, dev->sndbit) || !!test_bit(code, dev->snd) == value)
+				return;
+
+			change_bit(code, dev->snd);
+			if (dev->event) dev->event(dev, type, code, value);	
+	
+			break;
+
+		case EV_REP:
+
+			if (code > REP_MAX || dev->rep[code] == value) return;
+
+			dev->rep[code] = value;
+			if (dev->event) dev->event(dev, type, code, value);
+
+			break;
+	}
+/*
+ * Add randomness.
+ */
+
+#if 0 /* BUG */
+	add_input_randomness(((unsigned long) dev) ^ (type << 24) ^ (code << 16) ^ value);
+#endif
+
+/*
+ * Distribute the event to handler modules.
+ */
+
+	while (handle) {
+		if (handle->open)
+			handle->handler->event(handle, type, code, value);
+		handle = handle->dnext;
+	}
+}
+
+static void input_repeat_key(unsigned long data)
+{
+	struct input_dev *dev = (void *) data;
+	input_event(dev, EV_KEY, dev->repeat_key, 2);
+	mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]);
+}
+
+int input_open_device(struct input_handle *handle)
+{
+	handle->open++;
+	if (handle->dev->open)
+		return handle->dev->open(handle->dev);
+	return 0;
+}
+
+void input_close_device(struct input_handle *handle)
+{
+	if (handle->dev->close)
+		handle->dev->close(handle->dev);
+	handle->open--;
+}
+
+static void input_link_handle(struct input_handle *handle)
+{
+	handle->dnext = handle->dev->handle;
+	handle->hnext = handle->handler->handle;
+	handle->dev->handle = handle;
+	handle->handler->handle = handle;
+}
+
+static void input_unlink_handle(struct input_handle *handle)
+{
+	struct input_handle **handleptr;
+
+	handleptr = &handle->dev->handle;
+	while (*handleptr && (*handleptr != handle))
+		handleptr = &((*handleptr)->dnext);
+	*handleptr = (*handleptr)->dnext;
+
+	handleptr = &handle->handler->handle;
+	while (*handleptr && (*handleptr != handle))
+		handleptr = &((*handleptr)->hnext);
+	*handleptr = (*handleptr)->hnext;
+}
+
+void input_register_device(struct input_dev *dev)
+{
+	struct input_handler *handler = input_handler;
+	struct input_handle *handle;
+
+/*
+ * Initialize repeat timer to default values.
+ */
+
+	init_timer(&dev->timer);
+	dev->timer.data = (long) dev;
+	dev->timer.function = input_repeat_key;
+	dev->rep[REP_DELAY] = HZ/4;
+	dev->rep[REP_PERIOD] = HZ/33;
+
+/*
+ * Add the device.
+ */
+
+	if (input_number >= INPUT_DEVICES) {
+		printk(KERN_WARNING "input: ran out of input device numbers!\n");
+		dev->number = input_number;
+	} else {
+		dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
+		set_bit(dev->number, input_devices);
+	}
+		
+	dev->next = input_dev;	
+	input_dev = dev;
+	input_number++;
+
+/*
+ * Notify handlers.
+ */
+
+	while (handler) {
+		if ((handle = handler->connect(handler, dev)))
+			input_link_handle(handle);
+		handler = handler->next;
+	}
+}
+
+void input_unregister_device(struct input_dev *dev)
+{
+	struct input_handle *handle = dev->handle;
+	struct input_dev **devptr = &input_dev;
+	struct input_handle *dnext;
+
+/*
+ * Kill any pending repeat timers.
+ */
+
+	del_timer(&dev->timer);
+
+/*
+ * Notify handlers.
+ */
+
+	while (handle) {
+		dnext = handle->dnext;
+		input_unlink_handle(handle);
+		handle->handler->disconnect(handle);
+		handle = dnext;
+	}
+
+/*
+ * Remove the device.
+ */
+
+	while (*devptr && (*devptr != dev))
+		devptr = &((*devptr)->next);
+	*devptr = (*devptr)->next;
+
+	input_number--;
+
+	if (dev->number < INPUT_DEVICES)
+		clear_bit(dev->number, input_devices);
+}
+
+void input_register_handler(struct input_handler *handler)
+{
+	struct input_dev *dev = input_dev;
+	struct input_handle *handle;
+
+/*
+ * Add minors if needed.
+ */
+
+	if (handler->fops != NULL)
+		input_table[handler->minor >> 5] = handler;
+
+/*
+ * Add the handler.
+ */
+
+	handler->next = input_handler;	
+	input_handler = handler;
+	
+/*
+ * Notify it about all existing devices.
+ */
+
+	while (dev) {
+		if ((handle = handler->connect(handler, dev)))
+			input_link_handle(handle);
+		dev = dev->next;
+	}
+}
+
+void input_unregister_handler(struct input_handler *handler)
+{
+	struct input_handler **handlerptr = &input_handler;
+	struct input_handle *handle = handler->handle;
+	struct input_handle *hnext;
+
+/*
+ * Tell the handler to disconnect from all devices it keeps open.
+ */
+
+	while (handle) {
+		hnext = handle->hnext;
+		input_unlink_handle(handle);
+		handler->disconnect(handle);
+		handle = hnext;
+	}
+
+/*
+ * Remove it.
+ */
+
+	while (*handlerptr && (*handlerptr != handler))
+		handlerptr = &((*handlerptr)->next);
+
+	*handlerptr = (*handlerptr)->next;
+
+/*
+ * Remove minors.
+ */
+
+	if (handler->fops != NULL)
+		input_table[handler->minor >> 5] = NULL;
+}
+
+static int input_open_file(struct inode *inode, struct file *file)
+{
+	struct input_handler *handler = input_table[MINOR(inode->i_rdev) >> 5];
+
+	if (!handler || !handler->fops || !handler->fops->open)
+		return -ENODEV;
+
+	file->f_op = handler->fops;
+
+	return handler->fops->open(inode, file);
+}
+
+static struct file_operations input_fops = {
+	open: input_open_file,
+};
+
+devfs_handle_t input_register_minor(char *name, int minor, int minor_base)
+{
+	char devfs_name[16];
+	sprintf(devfs_name, name, minor);
+	return devfs_register(input_devfs_handle, devfs_name, 0, DEVFS_FL_DEFAULT, INPUT_MAJOR, minor + minor_base,
+		S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, &input_fops, NULL);
+}
+
+void input_unregister_minor(devfs_handle_t handle)
+{
+	devfs_unregister(handle);
+}
+
+static int __init input_init(void)
+{
+	if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) {
+		printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
+		return -EBUSY;
+	}
+	input_devfs_handle = devfs_mk_dir(NULL, "input", 5, NULL);
+	return 0;
+}
+
+static void __exit input_exit(void)
+{
+	devfs_unregister(input_devfs_handle);
+        if (devfs_unregister_chrdev(INPUT_MAJOR, "input"))
+                printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR);
+}
+
+module_init(input_init);
+module_exit(input_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/joydev.c linux.18p8/drivers/usb/joydev.c
--- linux.vanilla/drivers/usb/joydev.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/joydev.c	Fri Sep  1 14:41:15 2000
@@ -0,0 +1,487 @@
+/*
+ * $Id: joydev.c,v 1.7 2000/05/29 09:01:52 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999 Colin Van Dyke 
+ *
+ *  Joystick device driver for the input driver suite.
+ *
+ *  Sponsored by SuSE and Intel
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/joystick.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+
+#define JOYDEV_MINOR_BASE	0
+#define JOYDEV_MINORS		32
+#define JOYDEV_BUFFER_SIZE	64
+
+struct joydev {
+	int used;
+	int open;
+	int minor;
+	struct input_handle handle;
+	wait_queue_head_t wait;
+	devfs_handle_t devfs;
+	struct joydev *next;
+	struct joydev_list *list;
+	struct js_corr corr[ABS_MAX];
+	struct JS_DATA_SAVE_TYPE glue;
+	int nabs;
+	int nkey;
+	__u16 keymap[KEY_MAX - BTN_MISC];
+	__u16 keypam[KEY_MAX - BTN_MISC];
+	__u8 absmap[ABS_MAX];
+	__u8 abspam[ABS_MAX];
+};
+
+struct joydev_list {
+	struct js_event buffer[JOYDEV_BUFFER_SIZE];
+	int head;
+	int tail;
+	int startup;
+	struct fasync_struct *fasync;
+	struct joydev *joydev;
+	struct joydev_list *next;
+};
+
+static struct joydev *joydev_table[JOYDEV_MINORS];
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_SUPPORTED_DEVICE("input/js");
+
+static int joydev_correct(int value, struct js_corr *corr)
+{
+	switch (corr->type) {
+		case JS_CORR_NONE:
+			break;
+		case JS_CORR_BROKEN:
+			value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
+				((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
+				((corr->coef[2] * (value - corr->coef[0])) >> 14);
+			break;
+		default:
+			return 0;
+	}
+
+	if (value < -32767) return -32767;
+	if (value >  32767) return  32767;
+
+	return value;
+}
+
+static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+{
+	struct joydev *joydev = handle->private;
+	struct joydev_list *list = joydev->list;
+	struct js_event event;
+
+	switch (type) {
+
+		case EV_KEY:
+			if (code < BTN_MISC || value == 2) return;
+			event.type = JS_EVENT_BUTTON;
+			event.number = joydev->keymap[code - BTN_MISC];
+			event.value = value;
+			break;
+
+		case EV_ABS:
+			event.type = JS_EVENT_AXIS;
+			event.number = joydev->absmap[code];
+			event.value = joydev_correct(value, &joydev->corr[event.number]);
+			break;
+
+		default:
+			return;
+	}  
+
+	event.time = jiffies * (1000 / HZ);
+
+	while (list) {
+
+		memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
+
+		if (list->startup == joydev->nabs + joydev->nkey)
+			if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
+				list->startup = 0;
+
+		kill_fasync(list->fasync, SIGIO);
+
+		list = list->next;
+	}
+
+	wake_up_interruptible(&joydev->wait);
+}
+
+static int joydev_fasync(int fd, struct file *file, int on)
+{
+	int retval;
+	struct joydev_list *list = file->private_data;
+	retval = fasync_helper(fd, file, on, &list->fasync);
+	return retval < 0 ? retval : 0;
+}
+
+static int joydev_release(struct inode * inode, struct file * file)
+{
+	struct joydev_list *list = file->private_data;
+	struct joydev_list **listptr = &list->joydev->list;
+
+	joydev_fasync(-1, file, 0);
+
+	while (*listptr && (*listptr != list))
+		listptr = &((*listptr)->next);
+	*listptr = (*listptr)->next;
+
+	if (!--list->joydev->open)
+		input_close_device(&list->joydev->handle);
+	
+	if (!--list->joydev->used) {
+		input_unregister_minor(list->joydev->devfs);
+		joydev_table[list->joydev->minor] = NULL;
+		kfree(list->joydev);
+	}
+
+	kfree(list);
+
+	return 0;
+}
+
+static int joydev_open(struct inode *inode, struct file *file)
+{
+	struct joydev_list *list;
+	int i = MINOR(inode->i_rdev) - JOYDEV_MINOR_BASE;
+
+	if (i > JOYDEV_MINORS || !joydev_table[i])
+		return -ENODEV;
+
+	if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+	memset(list, 0, sizeof(struct joydev_list));
+
+	list->joydev = joydev_table[i];
+	list->next = joydev_table[i]->list;
+	joydev_table[i]->list = list;	
+
+	file->private_data = list;
+
+	list->joydev->used++;
+
+	if (!list->joydev->open++)
+		input_open_device(&list->joydev->handle);
+
+	return 0;
+}
+
+static ssize_t joydev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct joydev_list *list = file->private_data;
+	struct joydev *joydev = list->joydev;
+	struct input_dev *input = joydev->handle.dev;
+	int retval = 0;
+
+	if (count < sizeof(struct js_event))
+		return -EINVAL;
+
+	if (count == sizeof(struct JS_DATA_TYPE)) {
+
+		struct JS_DATA_TYPE data;
+
+		data.buttons =  ((joydev->nkey > 0 && test_bit(joydev->keypam[0], input->key)) ? 1 : 0) |
+				((joydev->nkey > 1 && test_bit(joydev->keypam[1], input->key)) ? 2 : 0);
+		data.x = ((joydev_correct(input->abs[ABS_X], &joydev->corr[0]) / 256) + 128) >> joydev->glue.JS_CORR.x;
+		data.y = ((joydev_correct(input->abs[ABS_Y], &joydev->corr[1]) / 256) + 128) >> joydev->glue.JS_CORR.y;
+
+		if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
+			return -EFAULT;
+
+		list->startup = 0;
+		list->tail = list->head;
+
+		return sizeof(struct JS_DATA_TYPE);
+	}
+
+	if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) {
+
+		add_wait_queue(&list->joydev->wait, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+
+		while (list->head == list->tail) {
+
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+
+			schedule();
+		}
+
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&list->joydev->wait, &wait);
+	}
+
+	if (retval)
+		return retval;
+
+	while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
+
+		struct js_event event;
+
+		event.time = jiffies * (1000/HZ);
+
+		if (list->startup < joydev->nkey) {
+			event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
+			event.value = !!test_bit(joydev->keypam[list->startup], input->key);
+			event.number = list->startup;
+		} else {
+			event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
+			event.value = joydev_correct(input->abs[joydev->abspam[list->startup - joydev->nkey]],
+							&joydev->corr[list->startup - joydev->nkey]);
+			event.number = list->startup - joydev->nkey;
+		}
+
+		if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
+			return -EFAULT;
+
+		list->startup++;
+		retval += sizeof(struct js_event);
+	}
+
+	while (list->head != list->tail && retval + sizeof(struct js_event) <= count) {
+
+		if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event)))
+			return -EFAULT;
+
+		list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
+		retval += sizeof(struct js_event);
+	}
+
+	return retval;
+}
+
+/* No kernel lock - fine */
+static unsigned int joydev_poll(struct file *file, poll_table *wait)
+{
+	struct joydev_list *list = file->private_data;
+	poll_wait(file, &list->joydev->wait, wait);
+	if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct joydev_list *list = file->private_data;
+	struct joydev *joydev = list->joydev;
+	struct input_dev *dev = joydev->handle.dev;
+
+
+	switch (cmd) {
+
+		case JS_SET_CAL:
+			return copy_from_user(&joydev->glue.JS_CORR, (struct JS_DATA_TYPE *) arg,
+				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+		case JS_GET_CAL:
+			return copy_to_user((struct JS_DATA_TYPE *) arg, &joydev->glue.JS_CORR,
+				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+		case JS_SET_TIMEOUT:
+			return get_user(joydev->glue.JS_TIMEOUT, (int *) arg);
+		case JS_GET_TIMEOUT:
+			return put_user(joydev->glue.JS_TIMEOUT, (int *) arg);
+		case JS_SET_TIMELIMIT:
+			return get_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
+		case JS_GET_TIMELIMIT:
+			return put_user(joydev->glue.JS_TIMELIMIT, (long *) arg);
+		case JS_SET_ALL:
+			return copy_from_user(&joydev->glue, (struct JS_DATA_SAVE_TYPE *) arg,
+						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+		case JS_GET_ALL:
+			return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &joydev->glue,
+						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+
+		case JSIOCGVERSION:
+			return put_user(JS_VERSION, (__u32 *) arg);
+		case JSIOCGAXES:
+			return put_user(joydev->nabs, (__u8 *) arg);
+		case JSIOCGBUTTONS:
+			return put_user(joydev->nkey, (__u8 *) arg);
+		case JSIOCSCORR:
+			return copy_from_user(joydev->corr, (struct js_corr *) arg,
+						sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
+		case JSIOCGCORR:
+			return copy_to_user((struct js_corr *) arg, joydev->corr,
+						sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
+		default:
+			if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
+				int len;
+				if (!dev->name) return 0;
+				len = strlen(dev->name) + 1;
+				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+				if (copy_to_user((char *) arg, dev->name, len)) return -EFAULT;
+				return len;
+			}
+	}
+	return -EINVAL;
+}
+
+static struct file_operations joydev_fops = {
+	read:		joydev_read,
+	write:		joydev_write,
+	poll:		joydev_poll,
+	open:		joydev_open,
+	release:	joydev_release,
+	ioctl:		joydev_ioctl,
+	fasync:		joydev_fasync,
+};
+
+static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev)
+{
+	struct joydev *joydev;
+	int i, j, minor;
+
+	if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) &&
+	      test_bit(ABS_X, dev->absbit) && test_bit(ABS_Y, dev->absbit) &&
+	     (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit)
+		|| test_bit(BTN_1, dev->keybit)))) return NULL; 
+
+	for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
+	if (joydev_table[minor]) {
+		printk(KERN_ERR "joydev: no more free joydev devices\n");
+		return NULL;
+	}
+
+	if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
+		return NULL;
+	memset(joydev, 0, sizeof(struct joydev));
+
+	init_waitqueue_head(&joydev->wait);
+
+	joydev->minor = minor;
+	joydev_table[minor] = joydev;
+
+	joydev->handle.dev = dev;
+	joydev->handle.handler = handler;
+	joydev->handle.private = joydev;
+
+	joydev->used = 1;
+
+	for (i = 0; i < ABS_MAX; i++)
+		if (test_bit(i, dev->absbit)) {
+			joydev->absmap[i] = joydev->nabs;
+			joydev->abspam[joydev->nabs] = i;
+			joydev->nabs++;
+		}
+
+	for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++)
+		if (test_bit(i + BTN_MISC, dev->keybit)) {
+			joydev->keymap[i] = joydev->nkey;
+			joydev->keypam[joydev->nkey] = i + BTN_MISC;
+			joydev->nkey++;
+		}
+
+	for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
+		if (test_bit(i + BTN_MISC, dev->keybit)) {
+			joydev->keymap[i] = joydev->nkey;
+			joydev->keypam[joydev->nkey] = i + BTN_MISC;
+			joydev->nkey++;
+		}
+
+	for (i = 0; i < joydev->nabs; i++) {
+		j = joydev->abspam[i];
+		if (dev->absmax[j] == dev->absmin[j]) {
+			joydev->corr[i].type = JS_CORR_NONE;
+			continue;
+		}
+		joydev->corr[i].type = JS_CORR_BROKEN;
+		joydev->corr[i].prec = dev->absfuzz[j];
+		joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
+		joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
+		joydev->corr[i].coef[2] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
+		joydev->corr[i].coef[3] = (1 << 29) / ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]);
+	}
+
+	joydev->devfs = input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
+
+	printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number);
+
+	return &joydev->handle;
+}
+
+static void joydev_disconnect(struct input_handle *handle)
+{
+	struct joydev *joydev = handle->private;
+
+	if (joydev->open)
+		input_close_device(handle);	
+
+	if (!--joydev->used) {
+		input_unregister_minor(joydev->devfs);
+		joydev_table[joydev->minor] = NULL;
+		kfree(joydev);
+	}
+}
+
+static struct input_handler joydev_handler = {
+	event:		joydev_event,
+	connect:	joydev_connect,
+	disconnect:	joydev_disconnect,
+	fops:		&joydev_fops,
+	minor:		JOYDEV_MINOR_BASE,
+};
+
+static int __init joydev_init(void)
+{
+	input_register_handler(&joydev_handler);
+	return 0;
+}
+
+static void __exit joydev_exit(void)
+{
+	input_unregister_handler(&joydev_handler);
+}
+
+module_init(joydev_init);
+module_exit(joydev_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/kaweth.c linux.18p8/drivers/usb/kaweth.c
--- linux.vanilla/drivers/usb/kaweth.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/kaweth.c	Fri Sep  1 14:07:21 2000
@@ -0,0 +1,1030 @@
+/****************************************************************
+ *
+ *     kawasaki.c - driver for KL5KUSB101 based USB->Ethernet
+ *
+ *     (c) 2000 Interlan Communications
+ *
+ *     Original author: The Zapman <zapman@interlan.net>
+ *     	Inspired by, and much credit goes to Michael Rothwell <rothwell@interlan.net>
+ *     		for the test equipment, help, and patience
+ *			Based off of (and with thanks to) Petko Manolov's pegaus.c driver.
+ *			Also many thanks to Joel Silverman at Kawasaki for providing the firmware
+ *				and driver resources.
+ *
+ *		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. 
+ *
+ ****************************************************************/
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/types.h>
+#include <asm/semaphore.h>
+
+#include "kawethfw.h"
+
+#define KAWETH_MTU								1514
+#define KAWETH_BUF_SIZE						1664
+#define KAWETH_TX_TIMEOUT					(1 * HZ)
+#define KAWETH_FIRMWARE_BUF_SIZE	4096
+#define KAWETH_CONTROL_TIMEOUT		(1 * HZ)
+
+#define KAWETH_STATUS_BROKEN			0x0000001
+#define KAWETH_STATUS_CLOSING			0x0000002
+
+#define KAWETH_PACKET_FILTER_PROMISCUOUS		0x01
+#define KAWETH_PACKET_FILTER_ALL_MULTICAST	0x02
+#define KAWETH_PACKET_FILTER_DIRECTED				0x04
+#define KAWETH_PACKET_FILTER_BROADCAST			0x08
+#define KAWETH_PACKET_FILTER_MULTICAST			0x10
+
+#define KAWETH_COMMAND_GET_ETHERNET_DESC		0x00
+#define KAWETH_COMMAND_SET_PACKET_FILTER		0x02
+#define KAWETH_COMMAND_GET_MAC							0x06
+#define KAWETH_COMMAND_SET_URB_SIZE					0x08
+#define KAWETH_COMMAND_SET_SOFS_WAIT				0x09
+#define KAWETH_COMMAND_SCAN									0xFF
+
+#define KAWETH_SOFS_TO_WAIT									0x05
+
+
+MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>");
+MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
+
+static void *kaweth_probe(struct usb_device *dev, unsigned int ifnum);
+static void kaweth_disconnect(struct usb_device *dev, void *ptr);
+
+/****************************************************************
+ *     kaweth_driver
+ ****************************************************************/
+static struct usb_driver kaweth_driver = {
+	name:		"kaweth",
+	probe:		kaweth_probe,
+	disconnect:	kaweth_disconnect,
+};
+//  __attribute__ ((packed))
+typedef __u8 eth_addr_t[6];
+
+/****************************************************************
+ *     usb_eth_dev
+ ****************************************************************/
+struct usb_eth_dev {
+	char *name;
+	__u16 vendor;
+	__u16 device;
+	void *pdata;
+};
+
+/****************************************************************
+ *     kaweth_ethernet_configuration
+ ****************************************************************/
+struct kaweth_ethernet_configuration
+{
+	__u8 size;
+	__u8 reserved1;
+	__u8 reserved2;
+	eth_addr_t hw_addr;
+	__u32 statistics_mask;
+	__u16 segment_size;
+	__u16 max_multicast_filters;
+	__u8 reserved3;
+} __attribute__ ((packed));
+
+/****************************************************************
+ *     kaweth_device
+ ****************************************************************/
+struct kaweth_device
+{
+	spinlock_t device_lock;
+
+	__u32 status;
+
+	struct usb_device *dev;
+	struct net_device *net;
+	wait_queue_head_t control_wait;
+
+	struct urb *rx_urb;
+	struct urb *tx_urb;
+	
+	__u8 firmware_buf[KAWETH_FIRMWARE_BUF_SIZE];
+	__u8 tx_buf[KAWETH_BUF_SIZE];
+	__u8 rx_buf[KAWETH_BUF_SIZE];
+
+	struct kaweth_ethernet_configuration configuration;
+
+	struct net_device_stats stats;
+} __attribute__ ((packed));
+
+/****************************************************************
+ *     usb_dev_id
+ ****************************************************************/
+static struct usb_eth_dev usb_dev_id[] = {
+	{ "KLSI KL5KUSB101B", 0x05e9, 0x0008, NULL },
+	{ "NetGear EA-101", 0x0846, 0x1001, NULL },
+	{ "Peracom Enet", 0x0565, 0x0002, NULL },
+	{ "Peracom Enet2", 0x0565, 0x0005, NULL },
+	{ "3Com 3C19250", 0x0506, 0x03e8, NULL },
+	{ "Linksys USB10T", 0x066b, 0x2202, NULL },
+	{ "D-Link DSB-650C", 0x2001, 0x4000, NULL },
+	{ "D-Link DSB-650", 0x0557, 0x2002, NULL },
+	{ "AOX USB Ethernet", 0x03e8, 0x0008, NULL },
+	{ "ADS USB-10BT", 0x06e1, 0x0008, NULL },
+	{ "Entrega E45", 0x1645, 0x0005, NULL},
+	{ "SMC 2202USB", 0x0707, 0x0100, NULL},
+	{ "Correga K.K.", 0x07aa, 0x0001, NULL},
+	{ NULL, 0, 0, NULL },
+};
+
+/****************************************************************
+ *     kaweth_check_device_ids
+ ****************************************************************/
+static int kaweth_check_device_ids(__u16 vendor, __u16 product)
+{
+	int i=0;
+	
+	while (usb_dev_id[i].name)
+	{
+		if((usb_dev_id[i].vendor == vendor) && 
+			 (usb_dev_id[i].device == product))
+			{
+				printk("%s connected...\n", usb_dev_id[i].name);
+				
+				return 0;
+			}
+		i++;
+	}
+	return	1;
+}
+
+/****************************************************************
+ *     kaweth_control_complete
+ ****************************************************************/
+static void kaweth_control_complete(struct urb *urb)
+{
+	struct kaweth_device *kaweth = (struct kaweth_device *)urb->context;
+
+	if(waitqueue_active(&kaweth->control_wait))
+	{
+		wake_up(&kaweth->control_wait);
+	}
+}
+
+/****************************************************************
+ *     kaweth_control
+ ****************************************************************/
+static int kaweth_control(struct kaweth_device *kaweth,
+													unsigned int pipe, 
+													__u8 request, 
+													__u8 requesttype, 
+													__u16 value, 
+													__u16 index,
+													void *data, 
+													__u16 size, 
+													int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	purb_t urb;
+	devrequest *dr;
+	int status;
+
+	if(in_interrupt())
+	{
+		return -EBUSY;
+	}
+
+	urb = usb_alloc_urb(0);
+	dr = kmalloc(sizeof(devrequest), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+
+	if(!urb || !dr)
+	{
+		if(urb) kfree(urb);
+
+		return -ENOMEM;
+	}
+
+	spin_lock(&kaweth->device_lock);
+
+	urb->dev = kaweth->dev;
+	urb->pipe = pipe;
+	urb->setup_packet = (void *)dr;
+	urb->transfer_flags = USB_DISABLE_SPD;
+	urb->transfer_buffer = (void *)data;
+	urb->transfer_buffer_length = size;
+	urb->actual_length = size;
+	urb->complete = kaweth_control_complete;
+	urb->context = kaweth;
+
+	dr->requesttype = requesttype;
+	dr->request = request;
+	dr->value = value;
+	dr->index = index;
+	dr->length = size;
+
+	printk("Request type: %x  Request: %x  Value: %x Index: %x Length: %x\n",
+				 (int)dr->requesttype,
+				 (int)dr->request,
+				 (int)dr->value,
+				 (int)dr->index,
+				 (int)dr->length); 
+
+	init_waitqueue_head(&kaweth->control_wait);
+
+	current->state = TASK_INTERRUPTIBLE;
+	
+	add_wait_queue(&kaweth->control_wait, &wait);
+
+	status = usb_submit_urb(urb);
+
+//	printk("pipe: %x\n", pipe);
+//	printk("maxpacket: %x\n", usb_maxpacket(kaweth->dev, pipe, usb_pipeout(pipe)));
+
+	if(status)
+	{		
+		usb_free_urb(urb);
+		remove_wait_queue(&kaweth->control_wait, &wait);
+		spin_unlock(&kaweth->device_lock);
+		return status;
+	}
+
+	if(urb->status == -EINPROGRESS)
+	{
+		while(timeout && urb->status == -EINPROGRESS)
+		{
+			status = timeout = schedule_timeout(timeout);
+		}
+	}
+	else
+	{
+		status = 1;
+	}
+
+	remove_wait_queue(&kaweth->control_wait, &wait);
+
+	if(!status)
+	{
+		usb_unlink_urb(urb);
+	
+		printk("kaweth timeout\n");
+
+		status = -ETIMEDOUT;
+	}
+	else
+	{
+		status = urb->status;
+
+		if(urb->status)
+		{
+			printk("kaweth control message failed (urb addr: %x)\n", (int)urb);
+			
+			usb_clear_halt(kaweth->dev, usb_rcvctrlpipe(kaweth->dev, 0));
+			usb_clear_halt(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0));
+
+			usb_unlink_urb(urb);
+		}
+	}
+
+	spin_unlock(&kaweth->device_lock);
+
+	printk("Actual length: %d, length %d\n", urb->actual_length, urb->transfer_buffer_length);
+
+//	printk("pipe: %x\n", pipe);
+//	printk("maxpacket: %x\n", usb_maxpacket(kaweth->dev, pipe, usb_pipeout(pipe)));
+
+	usb_free_urb(urb);
+	kfree(dr);
+	
+	return status;	
+}
+
+/****************************************************************
+ *     kaweth_read_configuration
+ ****************************************************************/
+static int kaweth_read_configuration(struct kaweth_device *kaweth)
+{
+	int retval;
+
+	printk("Reading kaweth configuration\n");
+
+	retval = kaweth_control(kaweth,
+									usb_rcvctrlpipe(kaweth->dev, 0),
+									KAWETH_COMMAND_GET_ETHERNET_DESC,
+									USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+									0,
+									0,
+									(void *)&kaweth->configuration,
+									sizeof(kaweth->configuration),
+									KAWETH_CONTROL_TIMEOUT);
+
+	return retval;
+}
+
+/****************************************************************
+ *     kaweth_set_urb_size
+ ****************************************************************/
+static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size)
+{
+	int retval;
+
+	printk("Setting URB size to %d\n", (unsigned)urb_size);
+
+	retval = kaweth_control(kaweth,
+									usb_sndctrlpipe(kaweth->dev, 0),
+									KAWETH_COMMAND_SET_URB_SIZE,
+									USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+									urb_size,
+									0,
+									(void *)&kaweth->firmware_buf,
+									0,
+									KAWETH_CONTROL_TIMEOUT);
+
+	return retval;
+}
+
+/****************************************************************
+ *     kaweth_set_sofs_wait
+ ****************************************************************/
+static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait)
+{
+	int retval;
+
+	printk("Set SOFS wait to %d\n", (unsigned)sofs_wait);
+
+	retval = kaweth_control(kaweth,
+									usb_sndctrlpipe(kaweth->dev, 0),
+									KAWETH_COMMAND_SET_SOFS_WAIT,
+									USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+									sofs_wait,
+									0,
+									(void *)&kaweth->firmware_buf,
+									0,
+									KAWETH_CONTROL_TIMEOUT);
+
+	return retval;
+}
+
+/****************************************************************
+ *     kaweth_set_recieve_filter
+ ****************************************************************/
+static int kaweth_set_recieve_filter(struct kaweth_device *kaweth, __u16 recieve_filter)
+{
+	int retval;
+
+	printk("Set recieve filter to %d\n", (unsigned)recieve_filter);
+
+	retval = kaweth_control(kaweth,
+									usb_sndctrlpipe(kaweth->dev, 0),
+									KAWETH_COMMAND_SET_PACKET_FILTER,
+									USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+									recieve_filter,
+									0,
+									(void *)&kaweth->firmware_buf,
+									0,
+									KAWETH_CONTROL_TIMEOUT);
+
+	return retval;
+}
+
+/****************************************************************
+ *     kaweth_download_firmware
+ ****************************************************************/
+static int kaweth_download_firmware(struct kaweth_device *kaweth, 
+																		__u8 *data, 
+																		__u16 data_len,
+																		__u8 interrupt,
+																		__u8 type)
+{	
+	if(data_len > KAWETH_FIRMWARE_BUF_SIZE)
+	{
+		printk("Firmware too big: %d\n", data_len);
+		
+		return -ENOSPC;
+	}
+	
+	memcpy(kaweth->firmware_buf, data, data_len);
+	
+	kaweth->firmware_buf[2] = (data_len & 0xFF) - 7;
+	kaweth->firmware_buf[3] = data_len >> 8;
+	kaweth->firmware_buf[4] = type;
+	kaweth->firmware_buf[5] = interrupt;
+
+	printk("Downloading firmware at %x to kaweth device at %x...\n", (int)data, (int)kaweth);
+	printk("Firmware length: %d\n", data_len);
+
+	return kaweth_control(kaweth,
+									usb_sndctrlpipe(kaweth->dev, 0),
+									KAWETH_COMMAND_SCAN,
+									USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+									0,
+									0,
+									(void *)&kaweth->firmware_buf,
+									data_len,
+									KAWETH_CONTROL_TIMEOUT);
+}
+
+/****************************************************************
+ *     kaweth_trigger_firmware
+ ****************************************************************/
+static int kaweth_trigger_firmware(struct kaweth_device *kaweth,
+																	 __u8 interrupt)
+{
+	kaweth->firmware_buf[0] = 0xB6;
+	kaweth->firmware_buf[1] = 0xC3;
+	kaweth->firmware_buf[2] = 1;
+	kaweth->firmware_buf[3] = 0;
+	kaweth->firmware_buf[4] = 6;
+	kaweth->firmware_buf[5] = 100;
+	kaweth->firmware_buf[6] = 0;
+	kaweth->firmware_buf[7] = 0;
+	
+	printk("Triggering firmware\n");
+
+	return kaweth_control(kaweth,
+									usb_sndctrlpipe(kaweth->dev, 0),
+									KAWETH_COMMAND_SCAN,
+									USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+									0,
+									0,
+									(void *)&kaweth->firmware_buf,
+									8,
+									KAWETH_CONTROL_TIMEOUT);
+}
+
+/****************************************************************
+ *     kaweth_reset
+ ****************************************************************/
+static int kaweth_reset(struct kaweth_device *kaweth)
+{
+	int result;
+
+	result = usb_set_configuration(kaweth->dev, 1);
+	
+	udelay(10000);
+
+	return result;
+}
+
+static void kaweth_usb_recieve(struct urb *);
+
+/****************************************************************
+ *     kaweth_resubmit_rx_urb
+ ****************************************************************/
+static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth)
+{
+	int result;
+	
+	memset(kaweth->rx_urb, 0, sizeof(*kaweth->rx_urb));
+
+	spin_lock_init(&kaweth->rx_urb->lock);
+
+	FILL_BULK_URB(kaweth->rx_urb,
+								kaweth->dev,
+								usb_rcvbulkpipe(kaweth->dev, 1),
+								kaweth->rx_buf,
+								KAWETH_BUF_SIZE,
+								kaweth_usb_recieve,
+								kaweth);
+
+//	kaweth->rx_urb->transfer_flags = USB_DISABLE_SPD | USB_URB_EARLY_COMPLETE;
+
+	if((result = usb_submit_urb(kaweth->rx_urb)))
+	{
+		printk("kaweth: resubmitting rx_urb %d failed\n", result);
+	}
+}
+
+/****************************************************************
+ *     kaweth_usb_recieve
+ ****************************************************************/
+static void kaweth_usb_recieve(struct urb *urb)
+{
+	struct kaweth_device *kaweth = urb->context;
+	struct net_device *net = kaweth->net;
+	
+	int count = urb->actual_length,
+			count2 = urb->transfer_buffer_length;
+			
+	__u16 pkt_len = *(__u16 *)kaweth->rx_buf;
+
+	struct sk_buff *skb;
+
+	if(kaweth->status & KAWETH_STATUS_CLOSING)
+	{
+		return;
+	}
+	
+#define RX_FAILED		kaweth_resubmit_rx_urb(kaweth);			\
+										return
+
+	if(urb->status && urb->status != -EREMOTEIO && count != 1) 
+	{
+		printk("%s: RX status: %d count: %d packet_len: %d\n", 
+					 net->name, urb->status, count, (int)pkt_len);
+
+		RX_FAILED;
+	}
+
+	if(kaweth->net && (count > 2))
+	{
+		if(pkt_len > (count - 2))
+		{
+			printk("kaweth error: packet length too long for USB frame (pkt_len: %x, count: %x)\n",
+						 pkt_len, count);
+
+			printk("Packet len & 2047: %x\n", pkt_len & 2047);
+			printk("Count 2: %x\n", count2);
+
+			RX_FAILED;
+		}
+		
+		if(!(skb = dev_alloc_skb(pkt_len+2)))
+		{
+			RX_FAILED;
+		}
+
+		skb->dev = net;
+
+		eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0);
+		
+		skb_put(skb, pkt_len);
+
+		skb->protocol = eth_type_trans(skb, net);
+		
+		netif_rx(skb);
+		
+		kaweth->stats.rx_packets++;
+		kaweth->stats.rx_bytes += pkt_len;
+	}
+
+	kaweth_resubmit_rx_urb(kaweth);
+}
+
+/****************************************************************
+ *     kaweth_open
+ ****************************************************************/
+static int kaweth_open(struct net_device *net)
+{
+	struct kaweth_device *kaweth = (struct kaweth_device *)net->priv;
+
+	printk("Dev usage: %d\n", kaweth->dev->refcnt.counter);
+
+	printk("Opening network device...\n");
+
+	kaweth_resubmit_rx_urb(kaweth);
+
+	netif_start_queue(net);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/****************************************************************
+ *     kaweth_close
+ ****************************************************************/
+static int kaweth_close(struct net_device *net)
+{
+	struct kaweth_device *kaweth = net->priv;
+
+	netif_stop_queue(net);
+
+	kaweth->status |= KAWETH_STATUS_CLOSING;
+
+	usb_unlink_urb(kaweth->rx_urb);
+
+	kaweth->status &= ~KAWETH_STATUS_CLOSING;
+
+	MOD_DEC_USE_COUNT;
+
+	printk("Dev usage: %d\n", kaweth->dev->refcnt.counter);
+
+	return 0;
+}
+
+/****************************************************************
+ *     kaweth_ioctl
+ ****************************************************************/
+static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+//	__u16 *data = (__u16 *)&rq->ifr_data;
+//	struct kaweth_device *kaweth = net->priv;
+/*
+	switch(cmd) {
+		default:
+			return -EOPNOTSUPP;
+	}
+*/
+	return -EOPNOTSUPP;
+}
+
+/****************************************************************
+ *     kaweth_usb_transmit_complete
+ ****************************************************************/
+static void kaweth_usb_transmit_complete(struct urb *urb)
+{
+	struct kaweth_device *kaweth = urb->context;
+
+	spin_lock(&kaweth->device_lock);
+
+	if (urb->status)
+		printk("%s: TX status %d", kaweth->net->name, urb->status);
+
+	netif_wake_queue(kaweth->net);
+
+	spin_unlock(&kaweth->device_lock);
+}
+
+/****************************************************************
+ *     kaweth_start_xmit
+ ****************************************************************/
+static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
+{
+	struct kaweth_device *kaweth = net->priv;
+//	int count = ((skb->len) & 0x3f) ? skb->len+2 : skb->len+3;
+	int count = skb->len;
+	
+	int res;
+
+	spin_lock(&kaweth->device_lock);
+
+	netif_stop_queue(net);
+
+	*((__u16 *)kaweth->tx_buf) = skb->len;
+
+	memcpy(kaweth->tx_buf + 2, skb->data, skb->len);
+
+	memset(kaweth->tx_urb, 0, sizeof(*kaweth->tx_urb));
+	spin_lock_init(&kaweth->tx_urb->lock);
+
+	FILL_BULK_URB(kaweth->tx_urb,
+							kaweth->dev,
+							usb_sndbulkpipe(kaweth->dev, 2),
+							kaweth->tx_buf,
+							count + 2,
+							kaweth_usb_transmit_complete,
+							kaweth);
+
+	if((res = usb_submit_urb(kaweth->tx_urb)))
+	{
+		warn("kaweth failed tx_urb %d", res);
+		kaweth->stats.tx_errors++;
+		
+		netif_start_queue(net);
+	} 
+	else 
+	{
+		kaweth->stats.tx_packets++;
+		kaweth->stats.tx_bytes += skb->len;
+		net->trans_start = jiffies;
+	}
+
+	dev_kfree_skb(skb);
+
+	spin_unlock(&kaweth->device_lock);
+
+	return 0;
+}
+
+/****************************************************************
+ *     kaweth_set_rx_mode
+ ****************************************************************/
+static void kaweth_set_rx_mode(struct net_device *net)
+{
+	struct kaweth_device *kaweth = net->priv;
+	int result;
+	
+	__u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED |
+															 KAWETH_PACKET_FILTER_BROADCAST |
+															 KAWETH_PACKET_FILTER_MULTICAST;
+
+	printk("Setting Rx mode\n");
+	
+	netif_stop_queue(net);
+
+	if (net->flags & IFF_PROMISC) 
+	{
+		packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
+	} 
+	else if ((net->mc_count) || //  > multicast_filter_limit) ||
+					 (net->flags & IFF_ALLMULTI)) 
+	{
+		packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST;
+	}
+
+	result = kaweth_control(kaweth,
+								 usb_sndctrlpipe(kaweth->dev, 0),
+								 KAWETH_COMMAND_SET_PACKET_FILTER,
+								 USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+								 packet_filter_bitmap,
+								 0,
+								 (void *)&kaweth->firmware_buf,
+								 0,
+								 KAWETH_CONTROL_TIMEOUT);
+
+	if(result < 0)
+	{
+		printk("Failed to set Rx mode: %d\n", result);
+	}
+	else
+	{
+		printk("%s: set Rx mode to %d\n", net->name, packet_filter_bitmap);
+	}
+		
+	netif_wake_queue(net);
+}
+
+/****************************************************************
+ *     kaweth_netdev_stats
+ ****************************************************************/
+static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev)
+{
+	return &((struct kaweth_device *)dev->priv)->stats;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 0)
+/****************************************************************
+ *     kaweth_tx_timeout
+ ****************************************************************/
+static void kaweth_tx_timeout(struct net_device *net)
+{
+	struct kaweth_device *kaweth = net->priv;
+
+	printk("%s: Tx timed out. Reseting...\n", net->name);
+	kaweth->stats.tx_errors++;
+	net->trans_start = jiffies;
+
+	usb_unlink_urb(kaweth->tx_urb);
+
+	netif_wake_queue(net);
+}
+#endif
+
+/****************************************************************
+ *     kaweth_probe
+ ****************************************************************/
+static void *kaweth_probe(struct usb_device *dev, unsigned int ifnum)
+{
+//	struct net_device *net;
+//	eth_addr_t mac_addr;
+	struct kaweth_device *kaweth;
+	const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+	int result = 0;
+	int i;
+	
+	printk("Kawasaki Device Probe (Device number:%x): 0x%4.4x:0x%4.4x\n",
+				 dev->devnum, 
+				 (int)dev->descriptor.idVendor, 
+				 (int)dev->descriptor.idProduct);
+
+	printk("Device at %p\n", dev);
+
+	printk("Descriptor length: %x type: %x\n", 
+				 (int)dev->descriptor.bLength,
+				 (int)dev->descriptor.bDescriptorType);
+
+	if (kaweth_check_device_ids(dev->descriptor.idVendor, 
+															dev->descriptor.idProduct)) 
+	{
+		return NULL;
+	}
+
+	if(!(kaweth = kmalloc(sizeof(struct kaweth_device), GFP_KERNEL)))
+	{
+		printk("out of memory allocating device structure\n");
+		return NULL;
+	}
+
+	memset(kaweth, 0, sizeof(*kaweth));
+
+	kaweth->dev = dev;
+	kaweth->status = 0;
+	kaweth->net = NULL;
+	kaweth->device_lock = SPIN_LOCK_UNLOCKED;
+
+	if((result = kaweth_read_configuration(kaweth)) < 0)
+	{
+//		printk("Resetting (jiffies: %x)...\n", jiffies);
+		printk("Resetting...\n");
+
+		kaweth_reset(kaweth);
+
+//		printk("Dowloading firmware (jiffies: %x)...\n", jiffies);
+												 
+		if((result = kaweth_download_firmware(kaweth, kaweth_new_code, len_kaweth_new_code, 100, 2)) < 0)
+		{
+			printk("Error downloading firmware (%d), no net device created\n", result);
+
+			kfree(kaweth);
+			
+			return NULL;
+		}
+
+//		printk("Dowloading firmware fix (jiffies: %x)...\n", jiffies);
+
+		if((result = kaweth_download_firmware(kaweth, kaweth_new_code_fix, len_kaweth_new_code_fix, 100, 3)) < 0)
+		{
+			printk("Error downloading firmware fix (%d), no net device created\n", result);
+
+			kfree(kaweth);
+
+			return NULL;
+		}
+
+//		printk("Dowloading firmware trigger (jiffies: %x)...\n", jiffies);
+
+		if((result = kaweth_trigger_firmware(kaweth, 100)) < 0)
+		{
+			printk("Error triggering firmware (%d), no net device created\n", result);
+
+			kfree(kaweth);
+
+			return NULL;
+		}
+
+		udelay(1000);
+
+		printk("Resetting device (jiffies: %lx)...\n", jiffies);
+
+		if(kaweth_reset(kaweth))
+		{
+			printk("Error resetting device\n");
+
+			kfree(kaweth);
+
+			return NULL;
+		}
+
+		printk("Reset device (jiffies: %lx)...\n", jiffies);
+	}
+
+	result = kaweth_read_configuration(kaweth);
+
+	printk("Statitstics collection: %x\n", kaweth->configuration.statistics_mask);
+	printk("Multicast filter limit: %x\n", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
+	printk("MTU: %x\n", kaweth->configuration.segment_size);
+	printk("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
+				 (int)kaweth->configuration.hw_addr[0],
+				 (int)kaweth->configuration.hw_addr[1],
+				 (int)kaweth->configuration.hw_addr[2],
+				 (int)kaweth->configuration.hw_addr[3],
+				 (int)kaweth->configuration.hw_addr[4],
+				 (int)kaweth->configuration.hw_addr[5]);
+
+	if(!memcmp(&kaweth->configuration.hw_addr, &bcast_addr, sizeof(bcast_addr)))
+	{
+		printk("Firmware not functioning properly, no net device created\n");
+
+		kfree(kaweth);
+
+		return NULL;
+	}
+
+	for(i = 0; i < sizeof(kaweth->configuration); i++)
+	{
+		printk(":%2.2x:", (unsigned int)((unsigned char *)&kaweth->configuration)[i]);
+	}
+
+	printk("\n");
+
+	if(result < 0)
+	{
+		printk("Error reading configuration (%d), no net device created\n", result);
+
+		return kaweth;
+	}
+
+	result = kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE);
+
+	if(result < 0)
+	{
+		printk("Error setting URB size\n");
+
+		return kaweth;
+	}
+	
+	result = kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT);
+
+	if(result < 0)
+	{
+		printk("Error setting SOFS wait\n");
+
+		return kaweth;
+	}
+
+	result = kaweth_set_recieve_filter(kaweth, KAWETH_PACKET_FILTER_DIRECTED |
+															 KAWETH_PACKET_FILTER_BROADCAST |
+															 KAWETH_PACKET_FILTER_MULTICAST);
+
+	if(result < 0)
+	{
+		printk("Error setting recieve filter\n");
+
+		return kaweth;
+	}
+	
+	printk("Initializing net device...\n");
+
+	kaweth->tx_urb = usb_alloc_urb(0);
+	kaweth->rx_urb = usb_alloc_urb(0);
+
+	kaweth->net = init_etherdev(0, 0);
+
+	memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr));
+	memcpy(kaweth->net->dev_addr, &kaweth->configuration.hw_addr, sizeof(kaweth->configuration.hw_addr));
+	 
+	kaweth->net->priv = kaweth;
+	kaweth->net->open = kaweth_open;
+	kaweth->net->stop = kaweth_close;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 0)
+	kaweth->net->watchdog_timeo = KAWETH_TX_TIMEOUT;
+	kaweth->net->tx_timeout = kaweth_tx_timeout;
+#endif
+	
+	kaweth->net->do_ioctl = kaweth_ioctl;
+	kaweth->net->hard_start_xmit = kaweth_start_xmit;
+	kaweth->net->set_multicast_list = kaweth_set_rx_mode;
+	kaweth->net->get_stats = kaweth_netdev_stats;
+	kaweth->net->mtu = kaweth->configuration.segment_size;
+
+	memset(&kaweth->stats, 0, sizeof(kaweth->stats));
+
+	printk("kaweth interface created at %s\n", kaweth->net->name);
+								
+	printk("Kaweth probe returning...\n");
+
+	return kaweth;
+}
+
+/****************************************************************
+ *     kaweth_disconnect
+ ****************************************************************/
+static void kaweth_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct kaweth_device *kaweth = ptr;
+
+	printk("Unregistering kaweth\n");
+
+	if (!kaweth) {
+		warn("unregistering non-existant device");
+		return;
+	}
+
+	if(kaweth->net)
+	{
+		if(kaweth->net->flags & IFF_UP)
+		{
+			printk("Closing net device\n");
+			
+			dev_close(kaweth->net);
+		}
+
+		printk("Unregistering net device\n");
+		
+		unregister_netdev(kaweth->net);
+	}
+
+	usb_free_urb(kaweth->rx_urb);
+	usb_free_urb(kaweth->tx_urb);
+
+	kfree(kaweth);
+}
+
+
+/****************************************************************
+ *     kaweth_init
+ ****************************************************************/
+int __init kaweth_init(void)
+{
+	printk("Kawasaki USB->Ethernet Driver loading...\n");
+
+	return usb_register(&kaweth_driver);
+}
+
+/****************************************************************
+ *     kaweth_exit
+ ****************************************************************/
+void __exit kaweth_exit(void)
+{
+	usb_deregister(&kaweth_driver);
+}
+
+module_init(kaweth_init);
+module_exit(kaweth_exit);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/kawethfw.h linux.18p8/drivers/usb/kawethfw.h
--- linux.vanilla/drivers/usb/kawethfw.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/kawethfw.h	Fri Sep  1 14:07:21 2000
@@ -0,0 +1,639 @@
+/******************************************/
+/* NOTE: B6/C3 is data header signature   */
+/*       0xAA/0xBB is data length = total */
+/*       bytes - 7, 0xCC is type, 0xDD is */
+/*       interrupt to use.                */
+/******************************************/
+
+/****************************************************************
+ *     kaweth_trigger_code
+ ****************************************************************/
+static __u8 kaweth_trigger_code[] = 
+{
+    0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+    0xc8, 0x07, 0xa0, 0x00, 0xf0, 0x07, 0x5e, 0x00,
+    0x06, 0x00, 0xf0, 0x07, 0x0a, 0x00, 0x08, 0x00,
+    0xf0, 0x09, 0x00, 0x00, 0x02, 0x00, 0xe7, 0x07,
+    0x36, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00,
+    0x04, 0x00, 0xe7, 0x07, 0x50, 0xc3, 0x10, 0xc0,
+    0xf0, 0x09, 0x0e, 0xc0, 0x00, 0x00, 0xe7, 0x87,
+    0x01, 0x00, 0x0e, 0xc0, 0x97, 0xcf, 0xd7, 0x09,
+    0x00, 0xc0, 0x17, 0x02, 0xc8, 0x07, 0xa0, 0x00,
+    0xe7, 0x17, 0x50, 0xc3, 0x10, 0xc0, 0x30, 0xd8,
+    0x04, 0x00, 0x30, 0x5c, 0x08, 0x00, 0x04, 0x00,
+    0xb0, 0xc0, 0x06, 0x00, 0xc8, 0x05, 0xe7, 0x05,
+    0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0x49, 0xaf,
+    0xc0, 0x07, 0x00, 0x00, 0x60, 0xaf, 0x4a, 0xaf,
+    0x00, 0x0c, 0x0c, 0x00, 0x40, 0xd2, 0x00, 0x1c,
+    0x0c, 0x00, 0x40, 0xd2, 0x30, 0x00, 0x08, 0x00,
+    0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0xf0, 0x07,
+    0x86, 0x00, 0x06, 0x00, 0x67, 0xcf, 0x27, 0x0c,
+    0x02, 0x00, 0x00, 0x00, 0x27, 0x0c, 0x00, 0x00,
+    0x0e, 0xc0, 0x49, 0xaf, 0x64, 0xaf, 0xc0, 0x07,
+    0x00, 0x00, 0x4b, 0xaf, 0x4a, 0xaf, 0x5a, 0xcf,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x94, 0x00, 0x05, 0x00,
+    0,    0
+};
+
+/****************************************************************
+ *     kaweth_trigger_code_fix
+ ****************************************************************/
+static __u8 kaweth_trigger_code_fix[] = 
+{
+    0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+    0x02, 0x00, 0x06, 0x00, 0x18, 0x00, 0x3e, 0x00,
+    0x80, 0x00, 0x98, 0x00, 0xaa, 0x00,
+    0,    0
+};
+
+/****************************************************************
+ *     kaweth_new_code
+ ****************************************************************/
+static __u8 kaweth_new_code[] = 
+{
+    0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+    0x9f, 0xcf, 0xbc, 0x08, 0xe7, 0x57, 0x00, 0x00,
+    0x9a, 0x08, 0x97, 0xc1, 0xe7, 0x67, 0xff, 0x1f,
+    0x28, 0xc0, 0xe7, 0x87, 0x00, 0x04, 0x24, 0xc0,
+    0xe7, 0x67, 0xff, 0xf9, 0x22, 0xc0, 0x97, 0xcf,
+    0xe7, 0x09, 0xa2, 0xc0, 0x94, 0x08, 0xd7, 0x09,
+    0x00, 0xc0, 0xe7, 0x59, 0xba, 0x08, 0x94, 0x08,
+    0x03, 0xc1, 0xe7, 0x67, 0xff, 0xf7, 0x24, 0xc0,
+    0xe7, 0x05, 0x00, 0xc0, 0xa7, 0xcf, 0x92, 0x08,
+    0xe7, 0x57, 0x00, 0x00, 0x8e, 0x08, 0xa7, 0xa1,
+    0x8e, 0x08, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+    0xf2, 0x09, 0x0a, 0xc0, 0xe7, 0x57, 0x00, 0x00,
+    0xa4, 0xc0, 0xa7, 0xc0, 0x56, 0x08, 0x9f, 0xaf,
+    0x70, 0x09, 0xe7, 0x07, 0x00, 0x00, 0xf2, 0x09,
+    0xe7, 0x57, 0xff, 0xff, 0x90, 0x08, 0x9f, 0xa0,
+    0x40, 0x00, 0xe7, 0x59, 0x90, 0x08, 0x94, 0x08,
+    0x9f, 0xa0, 0x40, 0x00, 0xc8, 0x09, 0xa2, 0x08,
+    0x08, 0x62, 0x9f, 0xa1, 0x14, 0x0a, 0xe7, 0x57,
+    0x00, 0x00, 0x52, 0x08, 0xa7, 0xc0, 0x56, 0x08,
+    0x9f, 0xaf, 0x04, 0x00, 0xe7, 0x57, 0x00, 0x00,
+    0x8e, 0x08, 0xa7, 0xc1, 0x56, 0x08, 0xc0, 0x09,
+    0xa8, 0x08, 0x00, 0x60, 0x05, 0xc4, 0xc0, 0x59,
+    0x94, 0x08, 0x02, 0xc0, 0x9f, 0xaf, 0xee, 0x00,
+    0xe7, 0x59, 0xae, 0x08, 0x94, 0x08, 0x02, 0xc1,
+    0x9f, 0xaf, 0xf6, 0x00, 0x9f, 0xaf, 0x9e, 0x03,
+    0xef, 0x57, 0x00, 0x00, 0xf0, 0x09, 0x9f, 0xa1,
+    0xde, 0x01, 0xe7, 0x57, 0x00, 0x00, 0x78, 0x08,
+    0x9f, 0xa0, 0xe4, 0x03, 0x9f, 0xaf, 0x2c, 0x04,
+    0xa7, 0xcf, 0x56, 0x08, 0x48, 0x02, 0xe7, 0x09,
+    0x94, 0x08, 0xa8, 0x08, 0xc8, 0x37, 0x04, 0x00,
+    0x9f, 0xaf, 0x68, 0x04, 0x97, 0xcf, 0xe7, 0x57,
+    0x00, 0x00, 0xa6, 0x08, 0x97, 0xc0, 0xd7, 0x09,
+    0x00, 0xc0, 0xc1, 0xdf, 0xc8, 0x09, 0x9c, 0x08,
+    0x08, 0x62, 0x1d, 0xc0, 0x27, 0x04, 0x9c, 0x08,
+    0x10, 0x94, 0xf0, 0x07, 0xee, 0x09, 0x02, 0x00,
+    0xc1, 0x07, 0x01, 0x00, 0x70, 0x00, 0x04, 0x00,
+    0xf0, 0x07, 0x44, 0x01, 0x06, 0x00, 0x50, 0xaf,
+    0xe7, 0x09, 0x94, 0x08, 0xae, 0x08, 0xe7, 0x17,
+    0x14, 0x00, 0xae, 0x08, 0xe7, 0x67, 0xff, 0x07,
+    0xae, 0x08, 0xe7, 0x07, 0xff, 0xff, 0xa8, 0x08,
+    0xe7, 0x07, 0x00, 0x00, 0xa6, 0x08, 0xe7, 0x05,
+    0x00, 0xc0, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0,
+    0xc1, 0xdf, 0x48, 0x02, 0xd0, 0x09, 0x9c, 0x08,
+    0x27, 0x02, 0x9c, 0x08, 0xe7, 0x09, 0x20, 0xc0,
+    0xee, 0x09, 0xe7, 0xd0, 0xee, 0x09, 0xe7, 0x05,
+    0x00, 0xc0, 0x97, 0xcf, 0x48, 0x02, 0xc8, 0x37,
+    0x04, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x60,
+    0x21, 0xc0, 0xc0, 0x37, 0x3e, 0x00, 0x23, 0xc9,
+    0xc0, 0x57, 0xb4, 0x05, 0x1b, 0xc8, 0xc0, 0x17,
+    0x3f, 0x00, 0xc0, 0x67, 0xc0, 0xff, 0x30, 0x00,
+    0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00,
+    0x00, 0x02, 0xc0, 0x17, 0x4c, 0x00, 0x30, 0x00,
+    0x06, 0x00, 0xf0, 0x07, 0xbe, 0x01, 0x0a, 0x00,
+    0x48, 0x02, 0xc1, 0x07, 0x02, 0x00, 0xd7, 0x09,
+    0x00, 0xc0, 0xc1, 0xdf, 0x51, 0xaf, 0xe7, 0x05,
+    0x00, 0xc0, 0x97, 0xcf, 0x9f, 0xaf, 0x68, 0x04,
+    0x9f, 0xaf, 0xe4, 0x03, 0x97, 0xcf, 0x9f, 0xaf,
+    0xe4, 0x03, 0xc9, 0x37, 0x04, 0x00, 0xc1, 0xdf,
+    0xc8, 0x09, 0x70, 0x08, 0x50, 0x02, 0x67, 0x02,
+    0x70, 0x08, 0xd1, 0x07, 0x00, 0x00, 0xc0, 0xdf,
+    0x9f, 0xaf, 0xde, 0x01, 0x97, 0xcf, 0xe7, 0x57,
+    0x00, 0x00, 0xaa, 0x08, 0x97, 0xc1, 0xe7, 0x57,
+    0x01, 0x00, 0x7a, 0x08, 0x97, 0xc0, 0xc8, 0x09,
+    0x6e, 0x08, 0x08, 0x62, 0x97, 0xc0, 0x00, 0x02,
+    0xc0, 0x17, 0x0e, 0x00, 0x27, 0x00, 0x34, 0x01,
+    0x27, 0x0c, 0x0c, 0x00, 0x36, 0x01, 0xef, 0x57,
+    0x00, 0x00, 0xf0, 0x09, 0x9f, 0xc0, 0xbe, 0x02,
+    0xe7, 0x57, 0x00, 0x00, 0xb0, 0x08, 0x97, 0xc1,
+    0xe7, 0x07, 0x09, 0x00, 0x12, 0xc0, 0xe7, 0x77,
+    0x00, 0x08, 0x20, 0xc0, 0x9f, 0xc1, 0xb6, 0x02,
+    0xe7, 0x57, 0x09, 0x00, 0x12, 0xc0, 0x77, 0xc9,
+    0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0xe7, 0x77,
+    0x00, 0x08, 0x20, 0xc0, 0x2f, 0xc1, 0xe7, 0x07,
+    0x00, 0x00, 0x42, 0xc0, 0xe7, 0x07, 0x05, 0x00,
+    0x90, 0xc0, 0xc8, 0x07, 0x0a, 0x00, 0xe7, 0x77,
+    0x04, 0x00, 0x20, 0xc0, 0x09, 0xc1, 0x08, 0xda,
+    0x7a, 0xc1, 0xe7, 0x07, 0x00, 0x01, 0x42, 0xc0,
+    0xe7, 0x07, 0x04, 0x00, 0x90, 0xc0, 0x1a, 0xcf,
+    0xe7, 0x07, 0x01, 0x00, 0x7a, 0x08, 0x00, 0xd8,
+    0x27, 0x50, 0x34, 0x01, 0x17, 0xc1, 0xe7, 0x77,
+    0x02, 0x00, 0x20, 0xc0, 0x79, 0xc1, 0x27, 0x50,
+    0x34, 0x01, 0x10, 0xc1, 0xe7, 0x77, 0x02, 0x00,
+    0x20, 0xc0, 0x79, 0xc0, 0x9f, 0xaf, 0xd8, 0x02,
+    0xe7, 0x05, 0x00, 0xc0, 0x00, 0x60, 0x9f, 0xc0,
+    0xde, 0x01, 0x97, 0xcf, 0xe7, 0x07, 0x01, 0x00,
+    0xb8, 0x08, 0x06, 0xcf, 0xe7, 0x07, 0x30, 0x0e,
+    0x02, 0x00, 0xe7, 0x07, 0x50, 0xc3, 0x12, 0xc0,
+    0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0xe7, 0x07,
+    0x01, 0x00, 0xb8, 0x08, 0x97, 0xcf, 0xe7, 0x07,
+    0x50, 0xc3, 0x12, 0xc0, 0xe7, 0x07, 0x30, 0x0e,
+    0x02, 0x00, 0xe7, 0x07, 0x01, 0x00, 0x7a, 0x08,
+    0xe7, 0x07, 0x05, 0x00, 0x90, 0xc0, 0x97, 0xcf,
+    0xe7, 0x07, 0x00, 0x01, 0x42, 0xc0, 0xe7, 0x07,
+    0x04, 0x00, 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x00,
+    0x7a, 0x08, 0xe7, 0x57, 0x0f, 0x00, 0xb2, 0x08,
+    0x13, 0xc1, 0x9f, 0xaf, 0x2e, 0x08, 0xca, 0x09,
+    0xac, 0x08, 0xf2, 0x17, 0x01, 0x00, 0x5c, 0x00,
+    0xf2, 0x27, 0x00, 0x00, 0x5e, 0x00, 0xe7, 0x07,
+    0x00, 0x00, 0xb2, 0x08, 0xe7, 0x07, 0x01, 0x00,
+    0xb4, 0x08, 0xc0, 0x07, 0xff, 0xff, 0x97, 0xcf,
+    0x9f, 0xaf, 0x4c, 0x03, 0xc0, 0x69, 0xb4, 0x08,
+    0x57, 0x00, 0x9f, 0xde, 0x33, 0x00, 0xc1, 0x05,
+    0x27, 0xd8, 0xb2, 0x08, 0x27, 0xd2, 0xb4, 0x08,
+    0xe7, 0x87, 0x01, 0x00, 0xb4, 0x08, 0xe7, 0x67,
+    0xff, 0x03, 0xb4, 0x08, 0x00, 0x60, 0x97, 0xc0,
+    0xe7, 0x07, 0x01, 0x00, 0xb0, 0x08, 0x27, 0x00,
+    0x12, 0xc0, 0x97, 0xcf, 0xc0, 0x09, 0xb6, 0x08,
+    0x00, 0xd2, 0x02, 0xc3, 0xc0, 0x97, 0x05, 0x80,
+    0x27, 0x00, 0xb6, 0x08, 0xc0, 0x99, 0x82, 0x08,
+    0xc0, 0x99, 0xa2, 0xc0, 0x97, 0xcf, 0xe7, 0x07,
+    0x00, 0x00, 0xb0, 0x08, 0xc0, 0xdf, 0x97, 0xcf,
+    0xc8, 0x09, 0x72, 0x08, 0x08, 0x62, 0x02, 0xc0,
+    0x10, 0x64, 0x07, 0xc1, 0xe7, 0x07, 0x00, 0x00,
+    0x64, 0x08, 0xe7, 0x07, 0xc8, 0x05, 0x24, 0x00,
+    0x97, 0xcf, 0x27, 0x04, 0x72, 0x08, 0xc8, 0x17,
+    0x0e, 0x00, 0x27, 0x02, 0x64, 0x08, 0xe7, 0x07,
+    0xd6, 0x05, 0x24, 0x00, 0x97, 0xcf, 0xd7, 0x09,
+    0x00, 0xc0, 0xc1, 0xdf, 0xe7, 0x57, 0x00, 0x00,
+    0x62, 0x08, 0x13, 0xc1, 0x9f, 0xaf, 0x70, 0x03,
+    0xe7, 0x57, 0x00, 0x00, 0x64, 0x08, 0x13, 0xc0,
+    0xe7, 0x09, 0x64, 0x08, 0x30, 0x01, 0xe7, 0x07,
+    0xf2, 0x05, 0x32, 0x01, 0xe7, 0x07, 0x10, 0x00,
+    0x96, 0xc0, 0xe7, 0x09, 0x64, 0x08, 0x62, 0x08,
+    0x04, 0xcf, 0xe7, 0x57, 0x00, 0x00, 0x64, 0x08,
+    0x02, 0xc1, 0x9f, 0xaf, 0x70, 0x03, 0xe7, 0x05,
+    0x00, 0xc0, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0,
+    0xc1, 0xdf, 0xc8, 0x09, 0x72, 0x08, 0x27, 0x02,
+    0x78, 0x08, 0x08, 0x62, 0x03, 0xc1, 0xe7, 0x05,
+    0x00, 0xc0, 0x97, 0xcf, 0x27, 0x04, 0x72, 0x08,
+    0xe7, 0x05, 0x00, 0xc0, 0xf0, 0x07, 0x40, 0x00,
+    0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00,
+    0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00,
+    0x06, 0x00, 0xf0, 0x07, 0x64, 0x01, 0x0a, 0x00,
+    0xc8, 0x17, 0x04, 0x00, 0xc1, 0x07, 0x02, 0x00,
+    0x51, 0xaf, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+    0x6a, 0x08, 0x97, 0xc0, 0xc1, 0xdf, 0xc8, 0x09,
+    0x6a, 0x08, 0x27, 0x04, 0x6a, 0x08, 0x27, 0x52,
+    0x6c, 0x08, 0x03, 0xc1, 0xe7, 0x07, 0x6a, 0x08,
+    0x6c, 0x08, 0xc0, 0xdf, 0x17, 0x02, 0xc8, 0x17,
+    0x0e, 0x00, 0x9f, 0xaf, 0x16, 0x05, 0xc8, 0x05,
+    0x00, 0x60, 0x03, 0xc0, 0x9f, 0xaf, 0x80, 0x04,
+    0x97, 0xcf, 0x9f, 0xaf, 0x68, 0x04, 0x97, 0xcf,
+    0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x08, 0x62,
+    0x1c, 0xc0, 0xd0, 0x09, 0x72, 0x08, 0x27, 0x02,
+    0x72, 0x08, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf,
+    0x97, 0x02, 0xca, 0x09, 0xac, 0x08, 0xf2, 0x17,
+    0x01, 0x00, 0x04, 0x00, 0xf2, 0x27, 0x00, 0x00,
+    0x06, 0x00, 0xca, 0x17, 0x2c, 0x00, 0xf8, 0x77,
+    0x01, 0x00, 0x0e, 0x00, 0x06, 0xc0, 0xca, 0xd9,
+    0xf8, 0x57, 0xff, 0x00, 0x0e, 0x00, 0x01, 0xc1,
+    0xca, 0xd9, 0x22, 0x1c, 0x0c, 0x00, 0xe2, 0x27,
+    0x00, 0x00, 0xe2, 0x17, 0x01, 0x00, 0xe2, 0x27,
+    0x00, 0x00, 0xca, 0x05, 0x00, 0x0c, 0x0c, 0x00,
+    0xc0, 0x17, 0x41, 0x00, 0xc0, 0x67, 0xc0, 0xff,
+    0x30, 0x00, 0x08, 0x00, 0x00, 0x02, 0xc0, 0x17,
+    0x0c, 0x00, 0x30, 0x00, 0x06, 0x00, 0xf0, 0x07,
+    0xdc, 0x00, 0x0a, 0x00, 0xf0, 0x07, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x0c, 0x08, 0x00, 0x40, 0xd1,
+    0x01, 0x00, 0xc0, 0x19, 0xa6, 0x08, 0xc0, 0x59,
+    0x98, 0x08, 0x04, 0xc9, 0x49, 0xaf, 0x9f, 0xaf,
+    0xee, 0x00, 0x4a, 0xaf, 0x67, 0x10, 0xa6, 0x08,
+    0xc8, 0x17, 0x04, 0x00, 0xc1, 0x07, 0x01, 0x00,
+    0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x50, 0xaf,
+    0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0xc0, 0x07,
+    0x01, 0x00, 0xc1, 0x09, 0x7c, 0x08, 0xc1, 0x77,
+    0x01, 0x00, 0x97, 0xc1, 0xd8, 0x77, 0x01, 0x00,
+    0x12, 0xc0, 0xc9, 0x07, 0x4c, 0x08, 0x9f, 0xaf,
+    0x64, 0x05, 0x04, 0xc1, 0xc1, 0x77, 0x08, 0x00,
+    0x13, 0xc0, 0x97, 0xcf, 0xc1, 0x77, 0x02, 0x00,
+    0x97, 0xc1, 0xc1, 0x77, 0x10, 0x00, 0x0c, 0xc0,
+    0x9f, 0xaf, 0x86, 0x05, 0x97, 0xcf, 0xc1, 0x77,
+    0x04, 0x00, 0x06, 0xc0, 0xc9, 0x07, 0x7e, 0x08,
+    0x9f, 0xaf, 0x64, 0x05, 0x97, 0xc0, 0x00, 0xcf,
+    0x00, 0x90, 0x97, 0xcf, 0x50, 0x54, 0x97, 0xc1,
+    0x70, 0x5c, 0x02, 0x00, 0x02, 0x00, 0x97, 0xc1,
+    0x70, 0x5c, 0x04, 0x00, 0x04, 0x00, 0x97, 0xcf,
+    0xc0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00,
+    0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, 0xcb, 0x09,
+    0x88, 0x08, 0xcc, 0x09, 0x8a, 0x08, 0x0b, 0x53,
+    0x11, 0xc0, 0xc9, 0x02, 0xca, 0x07, 0x78, 0x05,
+    0x9f, 0xaf, 0x64, 0x05, 0x97, 0xc0, 0x0a, 0xc8,
+    0x82, 0x08, 0x0a, 0xcf, 0x82, 0x08, 0x9f, 0xaf,
+    0x64, 0x05, 0x97, 0xc0, 0x05, 0xc2, 0x89, 0x30,
+    0x82, 0x60, 0x78, 0xc1, 0x00, 0x90, 0x97, 0xcf,
+    0x89, 0x10, 0x09, 0x53, 0x79, 0xc2, 0x89, 0x30,
+    0x82, 0x08, 0x7a, 0xcf, 0xc0, 0xdf, 0x97, 0xcf,
+    0xe7, 0x09, 0x96, 0xc0, 0x66, 0x08, 0xe7, 0x09,
+    0x98, 0xc0, 0x68, 0x08, 0x0f, 0xcf, 0xe7, 0x09,
+    0x96, 0xc0, 0x66, 0x08, 0xe7, 0x09, 0x98, 0xc0,
+    0x68, 0x08, 0xe7, 0x09, 0x64, 0x08, 0x30, 0x01,
+    0xe7, 0x07, 0xf2, 0x05, 0x32, 0x01, 0xe7, 0x07,
+    0x10, 0x00, 0x96, 0xc0, 0xd7, 0x09, 0x00, 0xc0,
+    0x17, 0x02, 0xc8, 0x09, 0x62, 0x08, 0xc8, 0x37,
+    0x0e, 0x00, 0xe7, 0x57, 0x04, 0x00, 0x68, 0x08,
+    0x3d, 0xc0, 0xe7, 0x87, 0x00, 0x08, 0x24, 0xc0,
+    0xe7, 0x09, 0x94, 0x08, 0xba, 0x08, 0xe7, 0x17,
+    0x64, 0x00, 0xba, 0x08, 0xe7, 0x67, 0xff, 0x07,
+    0xba, 0x08, 0xe7, 0x77, 0x2a, 0x00, 0x66, 0x08,
+    0x30, 0xc0, 0x97, 0x02, 0xca, 0x09, 0xac, 0x08,
+    0xe7, 0x77, 0x20, 0x00, 0x66, 0x08, 0x0e, 0xc0,
+    0xf2, 0x17, 0x01, 0x00, 0x10, 0x00, 0xf2, 0x27,
+    0x00, 0x00, 0x12, 0x00, 0xe7, 0x77, 0x0a, 0x00,
+    0x66, 0x08, 0xca, 0x05, 0x1e, 0xc0, 0x97, 0x02,
+    0xca, 0x09, 0xac, 0x08, 0xf2, 0x17, 0x01, 0x00,
+    0x0c, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x0e, 0x00,
+    0xe7, 0x77, 0x02, 0x00, 0x66, 0x08, 0x07, 0xc0,
+    0xf2, 0x17, 0x01, 0x00, 0x44, 0x00, 0xf2, 0x27,
+    0x00, 0x00, 0x46, 0x00, 0x06, 0xcf, 0xf2, 0x17,
+    0x01, 0x00, 0x60, 0x00, 0xf2, 0x27, 0x00, 0x00,
+    0x62, 0x00, 0xca, 0x05, 0x9f, 0xaf, 0x68, 0x04,
+    0x0f, 0xcf, 0x57, 0x02, 0x09, 0x02, 0xf1, 0x09,
+    0x68, 0x08, 0x0c, 0x00, 0xf1, 0xda, 0x0c, 0x00,
+    0xc8, 0x09, 0x6c, 0x08, 0x50, 0x02, 0x67, 0x02,
+    0x6c, 0x08, 0xd1, 0x07, 0x00, 0x00, 0xc9, 0x05,
+    0xe7, 0x09, 0x64, 0x08, 0x62, 0x08, 0xe7, 0x57,
+    0x00, 0x00, 0x62, 0x08, 0x02, 0xc0, 0x9f, 0xaf,
+    0x70, 0x03, 0xc8, 0x05, 0xe7, 0x05, 0x00, 0xc0,
+    0xc0, 0xdf, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0,
+    0x17, 0x00, 0x17, 0x02, 0x97, 0x02, 0xc0, 0x09,
+    0x92, 0xc0, 0xe7, 0x87, 0x00, 0x08, 0x24, 0xc0,
+    0xe7, 0x09, 0x94, 0x08, 0xba, 0x08, 0xe7, 0x17,
+    0x64, 0x00, 0xba, 0x08, 0xe7, 0x67, 0xff, 0x07,
+    0xba, 0x08, 0xe7, 0x07, 0x04, 0x00, 0x90, 0xc0,
+    0xca, 0x09, 0xac, 0x08, 0xe7, 0x07, 0x00, 0x00,
+    0x7a, 0x08, 0xe7, 0x07, 0x66, 0x03, 0x02, 0x00,
+    0xc0, 0x77, 0x02, 0x00, 0x10, 0xc0, 0xef, 0x57,
+    0x00, 0x00, 0xf0, 0x09, 0x04, 0xc0, 0x9f, 0xaf,
+    0xd8, 0x02, 0x9f, 0xcf, 0x12, 0x08, 0xf2, 0x17,
+    0x01, 0x00, 0x50, 0x00, 0xf2, 0x27, 0x00, 0x00,
+    0x52, 0x00, 0x9f, 0xcf, 0x12, 0x08, 0xef, 0x57,
+    0x00, 0x00, 0xf0, 0x09, 0x08, 0xc0, 0xe7, 0x57,
+    0x00, 0x00, 0xb8, 0x08, 0xe7, 0x07, 0x00, 0x00,
+    0xb8, 0x08, 0x0a, 0xc0, 0x03, 0xcf, 0xc0, 0x77,
+    0x10, 0x00, 0x06, 0xc0, 0xf2, 0x17, 0x01, 0x00,
+    0x58, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x5a, 0x00,
+    0xc0, 0x77, 0x80, 0x00, 0x06, 0xc0, 0xf2, 0x17,
+    0x01, 0x00, 0x70, 0x00, 0xf2, 0x27, 0x00, 0x00,
+    0x72, 0x00, 0xc0, 0x77, 0x08, 0x00, 0x1d, 0xc1,
+    0xf2, 0x17, 0x01, 0x00, 0x08, 0x00, 0xf2, 0x27,
+    0x00, 0x00, 0x0a, 0x00, 0xc0, 0x77, 0x00, 0x02,
+    0x06, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x64, 0x00,
+    0xf2, 0x27, 0x00, 0x00, 0x66, 0x00, 0xc0, 0x77,
+    0x40, 0x00, 0x06, 0xc0, 0xf2, 0x17, 0x01, 0x00,
+    0x5c, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x5e, 0x00,
+    0xc0, 0x77, 0x01, 0x00, 0x01, 0xc0, 0x37, 0xcf,
+    0x36, 0xcf, 0xf2, 0x17, 0x01, 0x00, 0x00, 0x00,
+    0xf2, 0x27, 0x00, 0x00, 0x02, 0x00, 0xef, 0x57,
+    0x00, 0x00, 0xf0, 0x09, 0x18, 0xc0, 0xe7, 0x57,
+    0x01, 0x00, 0xb2, 0x08, 0x0e, 0xc2, 0x07, 0xc8,
+    0xf2, 0x17, 0x01, 0x00, 0x50, 0x00, 0xf2, 0x27,
+    0x00, 0x00, 0x52, 0x00, 0x06, 0xcf, 0xf2, 0x17,
+    0x01, 0x00, 0x54, 0x00, 0xf2, 0x27, 0x00, 0x00,
+    0x56, 0x00, 0xe7, 0x07, 0x00, 0x00, 0xb2, 0x08,
+    0xe7, 0x07, 0x01, 0x00, 0xb4, 0x08, 0xc8, 0x09,
+    0x34, 0x01, 0xca, 0x17, 0x14, 0x00, 0xd8, 0x77,
+    0x01, 0x00, 0x05, 0xc0, 0xca, 0xd9, 0xd8, 0x57,
+    0xff, 0x00, 0x01, 0xc0, 0xca, 0xd9, 0xe2, 0x19,
+    0x94, 0xc0, 0xe2, 0x27, 0x00, 0x00, 0xe2, 0x17,
+    0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, 0x9f, 0xaf,
+    0x2e, 0x08, 0x9f, 0xaf, 0xde, 0x01, 0xe7, 0x57,
+    0x00, 0x00, 0xaa, 0x08, 0x9f, 0xa1, 0xf0, 0x0b,
+    0xca, 0x05, 0xc8, 0x05, 0xc0, 0x05, 0xe7, 0x05,
+    0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0xc8, 0x09,
+    0x6e, 0x08, 0x08, 0x62, 0x97, 0xc0, 0x27, 0x04,
+    0x6e, 0x08, 0x27, 0x52, 0x70, 0x08, 0x03, 0xc1,
+    0xe7, 0x07, 0x6e, 0x08, 0x70, 0x08, 0x9f, 0xaf,
+    0x68, 0x04, 0x97, 0xcf, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x33, 0xcc,
+    0x00, 0x00, 0x00, 0x00, 0xe7, 0x57, 0x00, 0x80,
+    0xb2, 0x00, 0x06, 0xc2, 0xe7, 0x07, 0x52, 0x0e,
+    0x12, 0x00, 0xe7, 0x07, 0x98, 0x0e, 0xb2, 0x00,
+    0xe7, 0x07, 0xa4, 0x09, 0xf2, 0x02, 0xc8, 0x09,
+    0xb4, 0x00, 0xf8, 0x07, 0x02, 0x00, 0x0d, 0x00,
+    0xd7, 0x09, 0x0e, 0xc0, 0xe7, 0x07, 0x00, 0x00,
+    0x0e, 0xc0, 0xc8, 0x09, 0xdc, 0x00, 0xf0, 0x07,
+    0xff, 0xff, 0x09, 0x00, 0xf0, 0x07, 0xfb, 0x13,
+    0x0b, 0x00, 0xe7, 0x09, 0xc0, 0x00, 0x58, 0x08,
+    0xe7, 0x09, 0xbe, 0x00, 0x54, 0x08, 0xe7, 0x09,
+    0x10, 0x00, 0x92, 0x08, 0xc8, 0x07, 0xb4, 0x09,
+    0x9f, 0xaf, 0x8c, 0x09, 0x9f, 0xaf, 0xe2, 0x0b,
+    0xc0, 0x07, 0x80, 0x01, 0x44, 0xaf, 0x27, 0x00,
+    0x88, 0x08, 0x27, 0x00, 0x8a, 0x08, 0x27, 0x00,
+    0x8c, 0x08, 0xc0, 0x07, 0x74, 0x00, 0x44, 0xaf,
+    0x27, 0x00, 0xac, 0x08, 0x08, 0x00, 0x00, 0x90,
+    0xc1, 0x07, 0x1d, 0x00, 0x20, 0x00, 0x20, 0x00,
+    0x01, 0xda, 0x7c, 0xc1, 0x9f, 0xaf, 0x8a, 0x0b,
+    0xc0, 0x07, 0x4c, 0x00, 0x48, 0xaf, 0x27, 0x00,
+    0x56, 0x08, 0x9f, 0xaf, 0x72, 0x0c, 0xe7, 0x07,
+    0x00, 0x80, 0x96, 0x08, 0xef, 0x57, 0x00, 0x00,
+    0xf0, 0x09, 0x03, 0xc0, 0xe7, 0x07, 0x01, 0x00,
+    0x1c, 0xc0, 0xe7, 0x05, 0x0e, 0xc0, 0x97, 0xcf,
+    0x49, 0xaf, 0xe7, 0x87, 0x43, 0x00, 0x0e, 0xc0,
+    0xe7, 0x07, 0xff, 0xff, 0x94, 0x08, 0x9f, 0xaf,
+    0x8a, 0x0c, 0xc0, 0x07, 0x01, 0x00, 0x60, 0xaf,
+    0x4a, 0xaf, 0x97, 0xcf, 0x00, 0x08, 0x09, 0x08,
+    0x11, 0x08, 0x00, 0xda, 0x7c, 0xc1, 0x97, 0xcf,
+    0x67, 0x04, 0xcc, 0x02, 0xc0, 0xdf, 0x51, 0x94,
+    0xb1, 0xaf, 0x06, 0x00, 0xc1, 0xdf, 0xc9, 0x09,
+    0xcc, 0x02, 0x49, 0x62, 0x75, 0xc1, 0xc0, 0xdf,
+    0xa7, 0xcf, 0xd6, 0x02, 0x0e, 0x00, 0x24, 0x00,
+    0xd6, 0x05, 0x22, 0x00, 0xc4, 0x06, 0xd0, 0x00,
+    0xf0, 0x0b, 0xaa, 0x00, 0x0e, 0x0a, 0xbe, 0x00,
+    0x2c, 0x0c, 0x10, 0x00, 0x20, 0x00, 0x04, 0x00,
+    0xc4, 0x05, 0x02, 0x00, 0x66, 0x03, 0x06, 0x00,
+    0x00, 0x00, 0x24, 0xc0, 0x04, 0x04, 0x28, 0xc0,
+    0xfe, 0xfb, 0x1e, 0xc0, 0x00, 0x04, 0x22, 0xc0,
+    0xff, 0xf0, 0xc0, 0x00, 0x60, 0x0b, 0x00, 0x00,
+    0x00, 0x00, 0xff, 0xff, 0x34, 0x0a, 0x3e, 0x0a,
+    0x9e, 0x0a, 0xa8, 0x0a, 0xce, 0x0a, 0xd2, 0x0a,
+    0xd6, 0x0a, 0x00, 0x0b, 0x10, 0x0b, 0x1e, 0x0b,
+    0x20, 0x0b, 0x28, 0x0b, 0x28, 0x0b, 0x27, 0x02,
+    0xa2, 0x08, 0x97, 0xcf, 0xe7, 0x07, 0x00, 0x00,
+    0xa2, 0x08, 0x0a, 0x0e, 0x01, 0x00, 0xca, 0x57,
+    0x0e, 0x00, 0x9f, 0xc3, 0x2a, 0x0b, 0xca, 0x37,
+    0x00, 0x00, 0x9f, 0xc2, 0x2a, 0x0b, 0x0a, 0xd2,
+    0xb2, 0xcf, 0xf4, 0x09, 0xc8, 0x09, 0xde, 0x00,
+    0x07, 0x06, 0x9f, 0xcf, 0x3c, 0x0b, 0xf0, 0x57,
+    0x80, 0x01, 0x06, 0x00, 0x9f, 0xc8, 0x2a, 0x0b,
+    0x27, 0x0c, 0x02, 0x00, 0x86, 0x08, 0xc0, 0x09,
+    0x88, 0x08, 0x27, 0x00, 0x8a, 0x08, 0xe7, 0x07,
+    0x00, 0x00, 0x84, 0x08, 0x27, 0x00, 0x5c, 0x08,
+    0x00, 0x1c, 0x06, 0x00, 0x27, 0x00, 0x8c, 0x08,
+    0x41, 0x90, 0x67, 0x50, 0x86, 0x08, 0x0d, 0xc0,
+    0x67, 0x00, 0x5a, 0x08, 0x27, 0x0c, 0x06, 0x00,
+    0x5e, 0x08, 0xe7, 0x07, 0x8a, 0x0a, 0x60, 0x08,
+    0xc8, 0x07, 0x5a, 0x08, 0x41, 0x90, 0x51, 0xaf,
+    0x97, 0xcf, 0x9f, 0xaf, 0xac, 0x0e, 0xe7, 0x09,
+    0x8c, 0x08, 0x8a, 0x08, 0xe7, 0x09, 0x86, 0x08,
+    0x84, 0x08, 0x59, 0xaf, 0x97, 0xcf, 0x27, 0x0c,
+    0x02, 0x00, 0x7c, 0x08, 0x59, 0xaf, 0x97, 0xcf,
+    0x09, 0x0c, 0x02, 0x00, 0x09, 0xda, 0x49, 0xd2,
+    0xc9, 0x19, 0xac, 0x08, 0xc8, 0x07, 0x5a, 0x08,
+    0xe0, 0x07, 0x00, 0x00, 0x60, 0x02, 0xe0, 0x07,
+    0x04, 0x00, 0xd0, 0x07, 0x9a, 0x0a, 0x48, 0xdb,
+    0x41, 0x90, 0x50, 0xaf, 0x97, 0xcf, 0x59, 0xaf,
+    0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf, 0xf0, 0x57,
+    0x06, 0x00, 0x06, 0x00, 0x26, 0xc1, 0xe7, 0x07,
+    0x7e, 0x08, 0x5c, 0x08, 0x41, 0x90, 0x67, 0x00,
+    0x5a, 0x08, 0x27, 0x0c, 0x06, 0x00, 0x5e, 0x08,
+    0xe7, 0x07, 0x5c, 0x0b, 0x60, 0x08, 0xc8, 0x07,
+    0x5a, 0x08, 0x41, 0x90, 0x51, 0xaf, 0x97, 0xcf,
+    0x07, 0x0c, 0x06, 0x00, 0xc7, 0x57, 0x06, 0x00,
+    0x10, 0xc1, 0xc8, 0x07, 0x7e, 0x08, 0x16, 0xcf,
+    0x00, 0x0c, 0x02, 0x00, 0x00, 0xda, 0x40, 0xd1,
+    0x27, 0x00, 0x98, 0x08, 0x1f, 0xcf, 0x1e, 0xcf,
+    0x27, 0x0c, 0x02, 0x00, 0xa4, 0x08, 0x1a, 0xcf,
+    0x00, 0xcf, 0x27, 0x02, 0x20, 0x01, 0xe7, 0x07,
+    0x08, 0x00, 0x22, 0x01, 0xe7, 0x07, 0x13, 0x00,
+    0xb0, 0xc0, 0x97, 0xcf, 0x41, 0x90, 0x67, 0x00,
+    0x5a, 0x08, 0xe7, 0x01, 0x5e, 0x08, 0x27, 0x02,
+    0x5c, 0x08, 0xe7, 0x07, 0x5c, 0x0b, 0x60, 0x08,
+    0xc8, 0x07, 0x5a, 0x08, 0xc1, 0x07, 0x00, 0x80,
+    0x50, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf,
+    0x00, 0x60, 0x05, 0xc0, 0xe7, 0x07, 0x00, 0x00,
+    0x9a, 0x08, 0xa7, 0xcf, 0x58, 0x08, 0x9f, 0xaf,
+    0xe2, 0x0b, 0xe7, 0x07, 0x01, 0x00, 0x9a, 0x08,
+    0x49, 0xaf, 0xd7, 0x09, 0x00, 0xc0, 0x07, 0xaf,
+    0xe7, 0x05, 0x00, 0xc0, 0x4a, 0xaf, 0xa7, 0xcf,
+    0x58, 0x08, 0xc0, 0x07, 0x40, 0x00, 0x44, 0xaf,
+    0x27, 0x00, 0xa0, 0x08, 0x08, 0x00, 0xc0, 0x07,
+    0x20, 0x00, 0x20, 0x94, 0x00, 0xda, 0x7d, 0xc1,
+    0xc0, 0x07, 0xfe, 0x7f, 0x44, 0xaf, 0x40, 0x00,
+    0x41, 0x90, 0xc0, 0x37, 0x08, 0x00, 0xdf, 0xde,
+    0x50, 0x06, 0xc0, 0x57, 0x10, 0x00, 0x02, 0xc2,
+    0xc0, 0x07, 0x10, 0x00, 0x27, 0x00, 0x76, 0x08,
+    0x41, 0x90, 0x9f, 0xde, 0x40, 0x06, 0x44, 0xaf,
+    0x27, 0x00, 0x74, 0x08, 0xc0, 0x09, 0x76, 0x08,
+    0x41, 0x90, 0x00, 0xd2, 0x00, 0xd8, 0x9f, 0xde,
+    0x08, 0x00, 0x44, 0xaf, 0x27, 0x00, 0x9e, 0x08,
+    0x97, 0xcf, 0xe7, 0x87, 0x00, 0x84, 0x28, 0xc0,
+    0xe7, 0x67, 0xff, 0xf3, 0x24, 0xc0, 0x97, 0xcf,
+    0xe7, 0x87, 0x01, 0x00, 0xaa, 0x08, 0xe7, 0x57,
+    0x00, 0x00, 0x7a, 0x08, 0x97, 0xc1, 0x9f, 0xaf,
+    0xe2, 0x0b, 0xe7, 0x87, 0x00, 0x06, 0x22, 0xc0,
+    0xe7, 0x07, 0x00, 0x00, 0x90, 0xc0, 0xe7, 0x67,
+    0xfe, 0xff, 0x3e, 0xc0, 0xe7, 0x07, 0x2e, 0x00,
+    0x0a, 0xc0, 0xe7, 0x87, 0x01, 0x00, 0x3e, 0xc0,
+    0xe7, 0x07, 0xff, 0xff, 0x94, 0x08, 0x9f, 0xaf,
+    0xf0, 0x0c, 0x97, 0xcf, 0x17, 0x00, 0xa7, 0xaf,
+    0x54, 0x08, 0xc0, 0x05, 0x27, 0x00, 0x52, 0x08,
+    0xe7, 0x87, 0x01, 0x00, 0xaa, 0x08, 0x9f, 0xaf,
+    0xe2, 0x0b, 0xe7, 0x07, 0x0c, 0x00, 0x40, 0xc0,
+    0x9f, 0xaf, 0xf0, 0x0c, 0xe7, 0x07, 0x00, 0x00,
+    0x78, 0x08, 0x00, 0x90, 0xe7, 0x09, 0x88, 0x08,
+    0x8a, 0x08, 0x27, 0x00, 0x84, 0x08, 0x27, 0x00,
+    0x7c, 0x08, 0x9f, 0xaf, 0x8a, 0x0c, 0xe7, 0x07,
+    0x00, 0x00, 0xb2, 0x02, 0xe7, 0x07, 0x00, 0x00,
+    0xb4, 0x02, 0xc0, 0x07, 0x06, 0x00, 0xc8, 0x09,
+    0xde, 0x00, 0xc8, 0x17, 0x03, 0x00, 0xc9, 0x07,
+    0x7e, 0x08, 0x29, 0x0a, 0x00, 0xda, 0x7d, 0xc1,
+    0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf,
+    0x00, 0x90, 0x27, 0x00, 0x6a, 0x08, 0xe7, 0x07,
+    0x6a, 0x08, 0x6c, 0x08, 0x27, 0x00, 0x6e, 0x08,
+    0xe7, 0x07, 0x6e, 0x08, 0x70, 0x08, 0x27, 0x00,
+    0x78, 0x08, 0x27, 0x00, 0x62, 0x08, 0x27, 0x00,
+    0x64, 0x08, 0xc8, 0x09, 0x74, 0x08, 0xc1, 0x09,
+    0x76, 0x08, 0xc9, 0x07, 0x72, 0x08, 0x11, 0x02,
+    0x09, 0x02, 0xc8, 0x17, 0x40, 0x06, 0x01, 0xda,
+    0x7a, 0xc1, 0x51, 0x94, 0xc8, 0x09, 0x9e, 0x08,
+    0xc9, 0x07, 0x9c, 0x08, 0xc1, 0x09, 0x76, 0x08,
+    0x01, 0xd2, 0x01, 0xd8, 0x11, 0x02, 0x09, 0x02,
+    0xc8, 0x17, 0x08, 0x00, 0x01, 0xda, 0x7a, 0xc1,
+    0x51, 0x94, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf,
+    0xe7, 0x57, 0x00, 0x00, 0x52, 0x08, 0x97, 0xc0,
+    0x9f, 0xaf, 0x04, 0x00, 0xe7, 0x09, 0x94, 0x08,
+    0x90, 0x08, 0xe7, 0x57, 0xff, 0xff, 0x90, 0x08,
+    0x04, 0xc1, 0xe7, 0x07, 0xf0, 0x0c, 0x8e, 0x08,
+    0x97, 0xcf, 0xe7, 0x17, 0x32, 0x00, 0x90, 0x08,
+    0xe7, 0x67, 0xff, 0x07, 0x90, 0x08, 0xe7, 0x07,
+    0x26, 0x0d, 0x8e, 0x08, 0x97, 0xcf, 0xd7, 0x09,
+    0x00, 0xc0, 0xc1, 0xdf, 0xe7, 0x57, 0x00, 0x00,
+    0x96, 0x08, 0x23, 0xc0, 0xe7, 0x07, 0x00, 0x80,
+    0x80, 0xc0, 0xe7, 0x07, 0x04, 0x00, 0x90, 0xc0,
+    0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0, 0xe7, 0x07,
+    0x00, 0x80, 0x80, 0xc0, 0xc0, 0x07, 0x00, 0x00,
+    0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00,
+    0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0, 0xe7, 0x07,
+    0x00, 0x80, 0x80, 0xc0, 0xe7, 0x07, 0x00, 0x80,
+    0x40, 0xc0, 0xc0, 0x07, 0x00, 0x00, 0xe7, 0x07,
+    0x00, 0x00, 0x40, 0xc0, 0xe7, 0x07, 0x00, 0x00,
+    0x80, 0xc0, 0xef, 0x57, 0x00, 0x00, 0xf1, 0x09,
+    0x9f, 0xa0, 0xc0, 0x0d, 0xe7, 0x07, 0x04, 0x00,
+    0x90, 0xc0, 0xe7, 0x07, 0x00, 0x02, 0x40, 0xc0,
+    0xe7, 0x07, 0x0c, 0x02, 0x40, 0xc0, 0xe7, 0x07,
+    0x00, 0x00, 0x96, 0x08, 0xe7, 0x07, 0x00, 0x00,
+    0x8e, 0x08, 0xe7, 0x07, 0x00, 0x00, 0xaa, 0x08,
+    0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x9f, 0xaf,
+    0x9e, 0x03, 0xe7, 0x05, 0x00, 0xc0, 0x9f, 0xaf,
+    0xde, 0x01, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf,
+    0x9f, 0xaf, 0xde, 0x0d, 0xef, 0x77, 0x00, 0x00,
+    0xf1, 0x09, 0x97, 0xc1, 0x9f, 0xaf, 0xde, 0x0d,
+    0xef, 0x77, 0x00, 0x00, 0xf1, 0x09, 0x97, 0xc1,
+    0xef, 0x07, 0x01, 0x00, 0xf1, 0x09, 0xe7, 0x87,
+    0x00, 0x08, 0x1e, 0xc0, 0xe7, 0x87, 0x00, 0x08,
+    0x22, 0xc0, 0xe7, 0x67, 0xff, 0xf7, 0x22, 0xc0,
+    0xe7, 0x77, 0x00, 0x08, 0x20, 0xc0, 0x11, 0xc0,
+    0xe7, 0x67, 0xff, 0xf7, 0x1e, 0xc0, 0xe7, 0x87,
+    0x00, 0x08, 0x22, 0xc0, 0xe7, 0x67, 0xff, 0xf7,
+    0x22, 0xc0, 0xe7, 0x77, 0x00, 0x08, 0x20, 0xc0,
+    0x04, 0xc1, 0xe7, 0x87, 0x00, 0x08, 0x22, 0xc0,
+    0x97, 0xcf, 0xe7, 0x07, 0x01, 0x01, 0xf0, 0x09,
+    0xef, 0x57, 0x18, 0x00, 0xfe, 0xff, 0x97, 0xc2,
+    0xef, 0x07, 0x00, 0x00, 0xf0, 0x09, 0x97, 0xcf,
+    0xd7, 0x09, 0x00, 0xc0, 0x17, 0x00, 0x17, 0x02,
+    0x97, 0x02, 0xe7, 0x57, 0x00, 0x00, 0x7a, 0x08,
+    0x06, 0xc0, 0xc0, 0x09, 0x92, 0xc0, 0xc0, 0x77,
+    0x09, 0x02, 0x9f, 0xc1, 0xea, 0x06, 0x9f, 0xcf,
+    0x20, 0x08, 0xd7, 0x09, 0x0e, 0xc0, 0xe7, 0x07,
+    0x00, 0x00, 0x0e, 0xc0, 0x9f, 0xaf, 0x66, 0x0e,
+    0xe7, 0x05, 0x0e, 0xc0, 0x97, 0xcf, 0xd7, 0x09,
+    0x00, 0xc0, 0x17, 0x02, 0xc8, 0x09, 0xb0, 0xc0,
+    0xe7, 0x67, 0xfe, 0x7f, 0xb0, 0xc0, 0xc8, 0x77,
+    0x00, 0x20, 0x9f, 0xc1, 0x64, 0xeb, 0xe7, 0x57,
+    0x00, 0x00, 0xc8, 0x02, 0x9f, 0xc1, 0x80, 0xeb,
+    0xc8, 0x99, 0xca, 0x02, 0xc8, 0x67, 0x04, 0x00,
+    0x9f, 0xc1, 0x96, 0xeb, 0x9f, 0xcf, 0x4c, 0xeb,
+    0xe7, 0x07, 0x00, 0x00, 0xa6, 0xc0, 0xe7, 0x09,
+    0xb0, 0xc0, 0xc8, 0x02, 0xe7, 0x07, 0x03, 0x00,
+    0xb0, 0xc0, 0x97, 0xcf, 0xc0, 0x09, 0x86, 0x08,
+    0xc0, 0x37, 0x01, 0x00, 0x97, 0xc9, 0xc9, 0x09,
+    0x88, 0x08, 0x02, 0x00, 0x41, 0x90, 0x48, 0x02,
+    0xc9, 0x17, 0x06, 0x00, 0x9f, 0xaf, 0x64, 0x05,
+    0x9f, 0xa2, 0xd6, 0x0e, 0x02, 0xda, 0x77, 0xc1,
+    0x41, 0x60, 0x71, 0xc1, 0x97, 0xcf, 0x17, 0x02,
+    0x57, 0x02, 0x43, 0x04, 0x21, 0x04, 0xe0, 0x00,
+    0x43, 0x04, 0x21, 0x04, 0xe0, 0x00, 0x43, 0x04,
+    0x21, 0x04, 0xe0, 0x00, 0xc1, 0x07, 0x01, 0x00,
+    0xc9, 0x05, 0xc8, 0x05, 0x97, 0xcf,
+    0,    0
+};
+
+/****************************************************************
+ *     kaweth_new_code_fix
+ ****************************************************************/
+static __u8 kaweth_new_code_fix[] = 
+{
+    0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+    0x02, 0x00, 0x08, 0x00, 0x24, 0x00, 0x2e, 0x00,
+    0x2c, 0x00, 0x3e, 0x00, 0x44, 0x00, 0x48, 0x00,
+    0x50, 0x00, 0x5c, 0x00, 0x60, 0x00, 0x66, 0x00,
+    0x6c, 0x00, 0x70, 0x00, 0x76, 0x00, 0x74, 0x00,
+    0x7a, 0x00, 0x7e, 0x00, 0x84, 0x00, 0x8a, 0x00,
+    0x8e, 0x00, 0x92, 0x00, 0x98, 0x00, 0x9c, 0x00,
+    0xa0, 0x00, 0xa8, 0x00, 0xae, 0x00, 0xb4, 0x00,
+    0xb2, 0x00, 0xba, 0x00, 0xbe, 0x00, 0xc4, 0x00,
+    0xc8, 0x00, 0xce, 0x00, 0xd2, 0x00, 0xd6, 0x00,
+    0xda, 0x00, 0xe2, 0x00, 0xe0, 0x00, 0xea, 0x00,
+    0xf2, 0x00, 0xfe, 0x00, 0x06, 0x01, 0x0c, 0x01,
+    0x1a, 0x01, 0x24, 0x01, 0x22, 0x01, 0x2a, 0x01,
+    0x30, 0x01, 0x36, 0x01, 0x3c, 0x01, 0x4e, 0x01,
+    0x52, 0x01, 0x58, 0x01, 0x5c, 0x01, 0x9c, 0x01,
+    0xb6, 0x01, 0xba, 0x01, 0xc0, 0x01, 0xca, 0x01,
+    0xd0, 0x01, 0xda, 0x01, 0xe2, 0x01, 0xea, 0x01,
+    0xf0, 0x01, 0x0a, 0x02, 0x0e, 0x02, 0x14, 0x02,
+    0x26, 0x02, 0x6c, 0x02, 0x8e, 0x02, 0x98, 0x02,
+    0xa0, 0x02, 0xa6, 0x02, 0xba, 0x02, 0xc6, 0x02,
+    0xce, 0x02, 0xe8, 0x02, 0xee, 0x02, 0xf4, 0x02,
+    0xf8, 0x02, 0x0a, 0x03, 0x10, 0x03, 0x1a, 0x03,
+    0x1e, 0x03, 0x2a, 0x03, 0x2e, 0x03, 0x34, 0x03,
+    0x3a, 0x03, 0x44, 0x03, 0x4e, 0x03, 0x5a, 0x03,
+    0x5e, 0x03, 0x6a, 0x03, 0x72, 0x03, 0x80, 0x03,
+    0x84, 0x03, 0x8c, 0x03, 0x94, 0x03, 0x98, 0x03,
+    0xa8, 0x03, 0xae, 0x03, 0xb4, 0x03, 0xba, 0x03,
+    0xce, 0x03, 0xcc, 0x03, 0xd6, 0x03, 0xdc, 0x03,
+    0xec, 0x03, 0xf0, 0x03, 0xfe, 0x03, 0x1c, 0x04,
+    0x30, 0x04, 0x38, 0x04, 0x3c, 0x04, 0x40, 0x04,
+    0x48, 0x04, 0x46, 0x04, 0x54, 0x04, 0x5e, 0x04,
+    0x64, 0x04, 0x74, 0x04, 0x78, 0x04, 0x84, 0x04,
+    0xd8, 0x04, 0xec, 0x04, 0xf0, 0x04, 0xf8, 0x04,
+    0xfe, 0x04, 0x1c, 0x05, 0x2c, 0x05, 0x30, 0x05,
+    0x4a, 0x05, 0x56, 0x05, 0x5a, 0x05, 0x88, 0x05,
+    0x8c, 0x05, 0x96, 0x05, 0x9a, 0x05, 0xa8, 0x05,
+    0xcc, 0x05, 0xd2, 0x05, 0xda, 0x05, 0xe0, 0x05,
+    0xe4, 0x05, 0xfc, 0x05, 0x06, 0x06, 0x14, 0x06,
+    0x12, 0x06, 0x1a, 0x06, 0x20, 0x06, 0x26, 0x06,
+    0x2e, 0x06, 0x34, 0x06, 0x48, 0x06, 0x52, 0x06,
+    0x64, 0x06, 0x86, 0x06, 0x90, 0x06, 0x9a, 0x06,
+    0xa0, 0x06, 0xac, 0x06, 0xaa, 0x06, 0xb2, 0x06,
+    0xb8, 0x06, 0xdc, 0x06, 0xda, 0x06, 0xe2, 0x06,
+    0xe8, 0x06, 0xf2, 0x06, 0xf8, 0x06, 0xfc, 0x06,
+    0x0a, 0x07, 0x10, 0x07, 0x14, 0x07, 0x24, 0x07,
+    0x2a, 0x07, 0x32, 0x07, 0x38, 0x07, 0xb2, 0x07,
+    0xba, 0x07, 0xde, 0x07, 0xe4, 0x07, 0x10, 0x08,
+    0x14, 0x08, 0x1a, 0x08, 0x1e, 0x08, 0x30, 0x08,
+    0x38, 0x08, 0x3c, 0x08, 0x44, 0x08, 0x42, 0x08,
+    0x48, 0x08, 0xc6, 0x08, 0xcc, 0x08, 0xd2, 0x08,
+    0xfe, 0x08, 0x04, 0x09, 0x0a, 0x09, 0x0e, 0x09,
+    0x12, 0x09, 0x16, 0x09, 0x20, 0x09, 0x24, 0x09,
+    0x28, 0x09, 0x32, 0x09, 0x46, 0x09, 0x4a, 0x09,
+    0x50, 0x09, 0x54, 0x09, 0x5a, 0x09, 0x60, 0x09,
+    0x7c, 0x09, 0x80, 0x09, 0xb8, 0x09, 0xbc, 0x09,
+    0xc0, 0x09, 0xc4, 0x09, 0xc8, 0x09, 0xcc, 0x09,
+    0xd0, 0x09, 0xd4, 0x09, 0xec, 0x09, 0xf4, 0x09,
+    0xf6, 0x09, 0xf8, 0x09, 0xfa, 0x09, 0xfc, 0x09,
+    0xfe, 0x09, 0x00, 0x0a, 0x02, 0x0a, 0x04, 0x0a,
+    0x06, 0x0a, 0x08, 0x0a, 0x0a, 0x0a, 0x0c, 0x0a,
+    0x10, 0x0a, 0x18, 0x0a, 0x24, 0x0a, 0x2c, 0x0a,
+    0x32, 0x0a, 0x3c, 0x0a, 0x46, 0x0a, 0x4c, 0x0a,
+    0x50, 0x0a, 0x54, 0x0a, 0x5a, 0x0a, 0x5e, 0x0a,
+    0x66, 0x0a, 0x6c, 0x0a, 0x72, 0x0a, 0x78, 0x0a,
+    0x7e, 0x0a, 0x7c, 0x0a, 0x82, 0x0a, 0x8c, 0x0a,
+    0x92, 0x0a, 0x90, 0x0a, 0x98, 0x0a, 0x96, 0x0a,
+    0xa2, 0x0a, 0xb2, 0x0a, 0xb6, 0x0a, 0xc4, 0x0a,
+    0xe2, 0x0a, 0xe0, 0x0a, 0xe8, 0x0a, 0xee, 0x0a,
+    0xf4, 0x0a, 0xf2, 0x0a, 0xf8, 0x0a, 0x0c, 0x0b,
+    0x1a, 0x0b, 0x24, 0x0b, 0x40, 0x0b, 0x44, 0x0b,
+    0x48, 0x0b, 0x4e, 0x0b, 0x4c, 0x0b, 0x52, 0x0b,
+    0x68, 0x0b, 0x6c, 0x0b, 0x70, 0x0b, 0x76, 0x0b,
+    0x88, 0x0b, 0x92, 0x0b, 0xbe, 0x0b, 0xca, 0x0b,
+    0xce, 0x0b, 0xde, 0x0b, 0xf4, 0x0b, 0xfa, 0x0b,
+    0x00, 0x0c, 0x24, 0x0c, 0x28, 0x0c, 0x30, 0x0c,
+    0x36, 0x0c, 0x3c, 0x0c, 0x40, 0x0c, 0x4a, 0x0c,
+    0x50, 0x0c, 0x58, 0x0c, 0x56, 0x0c, 0x5c, 0x0c,
+    0x60, 0x0c, 0x64, 0x0c, 0x80, 0x0c, 0x94, 0x0c,
+    0x9a, 0x0c, 0x98, 0x0c, 0x9e, 0x0c, 0xa4, 0x0c,
+    0xa2, 0x0c, 0xa8, 0x0c, 0xac, 0x0c, 0xb0, 0x0c,
+    0xb4, 0x0c, 0xb8, 0x0c, 0xbc, 0x0c, 0xce, 0x0c,
+    0xd2, 0x0c, 0xd6, 0x0c, 0xf4, 0x0c, 0xfa, 0x0c,
+    0x00, 0x0d, 0xfe, 0x0c, 0x06, 0x0d, 0x0e, 0x0d,
+    0x0c, 0x0d, 0x16, 0x0d, 0x1c, 0x0d, 0x22, 0x0d,
+    0x20, 0x0d, 0x30, 0x0d, 0x7e, 0x0d, 0x82, 0x0d,
+    0x9a, 0x0d, 0xa0, 0x0d, 0xa6, 0x0d, 0xb0, 0x0d,
+    0xb8, 0x0d, 0xc2, 0x0d, 0xc8, 0x0d, 0xce, 0x0d,
+    0xd4, 0x0d, 0xdc, 0x0d, 0x1e, 0x0e, 0x2c, 0x0e,
+    0x3e, 0x0e, 0x4c, 0x0e, 0x50, 0x0e, 0x5e, 0x0e,
+    0xae, 0x0e, 0xb8, 0x0e, 0xc6, 0x0e, 0xca, 0x0e,
+    0,    0
+};
+
+const int len_kaweth_trigger_code = sizeof(kaweth_trigger_code);
+const int len_kaweth_trigger_code_fix = sizeof(kaweth_trigger_code_fix);
+const int len_kaweth_new_code = sizeof(kaweth_new_code);
+const int len_kaweth_new_code_fix = sizeof(kaweth_new_code_fix);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/keybdev.c linux.18p8/drivers/usb/keybdev.c
--- linux.vanilla/drivers/usb/keybdev.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/keybdev.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,198 @@
+/*
+ * $Id: keybdev.c,v 1.3 2000/05/28 17:31:36 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Input driver to keyboard driver binding.
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/config.h>
+#include <linux/kbd_ll.h>
+#include <linux/input.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kbd_kern.h>
+#include <linux/kcomp.h>
+
+#if defined(__i386__) || defined(__alpha__) || defined(__mips__)
+
+static int x86_sysrq_alt = 0;
+
+static unsigned short x86_keycodes[256] =
+	{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+	 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+	 80, 81, 82, 83, 43, 85, 86, 87, 88,115,119,120,121,375,123, 90,
+	284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
+	367,294,293,286,350, 92,334,512,116,377,109,111,373,347,348,349,
+	360, 93, 94, 95, 98,376,100,101,357,316,354,304,289,102,351,355,
+	103,104,105,275,281,272,306,106,274,107,288,364,358,363,362,361,
+	291,108,381,290,287,292,279,305,280, 99,112,257,258,113,270,114,
+	118,117,125,374,379,259,260,261,262,263,264,265,266,267,268,269,
+	271,273,276,277,278,282,283,295,296,297,299,300,301,302,303,307,
+	308,310,313,314,315,317,318,319,320,321,322,323,324,325,326,330,
+	332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 };
+
+static int emulate_raw(unsigned int keycode, int down)
+{
+	if (keycode > 255 || !x86_keycodes[keycode])
+		return -1; 
+
+	if (keycode == KEY_PAUSE) {
+		handle_scancode(0xe1, 1);
+		handle_scancode(0x1d, down);
+		handle_scancode(0x45, down);
+		return 0;
+	} 
+
+	if (keycode == KEY_SYSRQ && x86_sysrq_alt) {
+		handle_scancode(0x54, down);
+		return 0;
+	}
+
+	if (x86_keycodes[keycode] & 0x100)
+		handle_scancode(0xe0, 1);
+
+	handle_scancode(x86_keycodes[keycode] & 0x7f, down);
+
+	if (keycode == KEY_SYSRQ) {
+		handle_scancode(0xe0, 1);
+		handle_scancode(0x37, down);
+	}
+
+	if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
+		x86_sysrq_alt = down;
+
+	return 0;
+}
+
+#elif defined(CONFIG_MAC_KEYBOARD)
+
+static unsigned char mac_keycodes[128] =
+	{ 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
+	 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128,  1,
+	  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
+	 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
+	 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
+	 84, 85, 82, 65, 42,  0, 10,103,111,  0,  0,  0,  0,  0,  0,  0,
+	 76,125, 75,105,124,  0,115, 62,116, 59, 60,119, 61,121,114,117,
+	  0,  0,  0,  0,127, 81,  0,113,  0,  0,  0,  0,  0, 55, 55 };
+
+static int emulate_raw(unsigned int keycode, int down)
+{
+	if (keycode > 127 || !mac_keycodes[keycode])
+		return -1;
+
+	handle_scancode(mac_keycodes[keycode] & 0x7f, down);
+
+	return 0;
+}
+
+#endif
+
+static struct input_handler keybdev_handler;
+
+void keybdev_ledfunc(unsigned int led)
+{
+	struct input_handle *handle;	
+
+	for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
+
+		input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01));
+		input_event(handle->dev, EV_LED, LED_NUML,    !!(led & 0x02));
+		input_event(handle->dev, EV_LED, LED_CAPSL,   !!(led & 0x04));
+
+	}
+}
+
+void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
+{
+	if (type != EV_KEY) return;
+
+	if (emulate_raw(code, down))
+		printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code);
+
+	mark_bh(KEYBOARD_BH);
+}
+
+static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev)
+{
+	struct input_handle *handle;
+	int i;
+
+	if (!test_bit(EV_KEY, dev->evbit))
+		return NULL;
+
+	for (i = KEY_RESERVED; i < BTN_MISC; i++)
+		if (test_bit(i, dev->keybit)) break;
+
+	if (i == BTN_MISC)
+ 		return NULL;
+
+	if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+		return NULL;
+	memset(handle, 0, sizeof(struct input_handle));
+
+	handle->dev = dev;
+	handle->handler = handler;
+
+	input_open_device(handle);
+
+	printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
+
+	return handle;
+}
+
+static void keybdev_disconnect(struct input_handle *handle)
+{
+	printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number);
+	input_close_device(handle);
+	kfree(handle);
+}
+	
+static struct input_handler keybdev_handler = {
+	event:		keybdev_event,
+	connect:	keybdev_connect,
+	disconnect:	keybdev_disconnect,
+};
+
+static int __init keybdev_init(void)
+{
+	input_register_handler(&keybdev_handler);
+	kbd_ledfunc = keybdev_ledfunc;
+	return 0;
+}
+
+static void __exit keybdev_exit(void)
+{
+	kbd_ledfunc = NULL;
+	input_unregister_handler(&keybdev_handler);
+}
+
+module_init(keybdev_init);
+module_exit(keybdev_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/keyboard.c linux.18p8/drivers/usb/keyboard.c
--- linux.vanilla/drivers/usb/keyboard.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/keyboard.c	Thu Jan  1 01:00:00 1970
@@ -1,226 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/kbd_ll.h>
-#include "usb.h"
-
-#define PCKBD_PRESSED  0x00
-#define PCKBD_RELEASED 0x80
-#define PCKBD_NEEDS_E0 0x80
-
-#define USBKBD_MODIFIER_BASE  120
-#define USBKBD_KEYCODE_OFFSET 2
-#define USBKBD_KEYCODE_COUNT  6
-
-#define USBKBD_VALID_KEYCODE(key) ((unsigned char)(key) > 3)
-#define USBKBD_FIND_KEYCODE(down, key, count) \
-    ((unsigned char*) memscan((down), (key), (count)) < ((down) + (count)))
-
-#define USBKBD_REPEAT_DELAY (HZ / 4)
-#define USBKBD_REPEAT_RATE (HZ / 20)
-
-struct usb_keyboard
-{
-    struct usb_device *dev;
-    unsigned long down[2];
-    unsigned char repeat_key;
-    struct timer_list repeat_timer;
-    struct list_head list;
-};
-
-extern unsigned char usb_kbd_map[];
-
-static int usb_kbd_probe(struct usb_device *dev);
-static void usb_kbd_disconnect(struct usb_device *dev);
-static void usb_kbd_repeat(unsigned long dummy);
-
-static LIST_HEAD(usb_kbd_list);
-
-static struct usb_driver usb_kbd_driver =
-{
-    "keyboard",
-    usb_kbd_probe,
-    usb_kbd_disconnect,
-    {NULL, NULL}
-};
-
-
-static void
-usb_kbd_handle_key(unsigned char key, int down)
-{
-    int scancode = (int) usb_kbd_map[key];
-    if(scancode)
-    {
-        if(scancode & PCKBD_NEEDS_E0)
-        {
-            handle_scancode(0xe0, 1);
-        }
-        handle_scancode((scancode & ~PCKBD_NEEDS_E0), down);
-    }
-}
-
-static void
-usb_kbd_repeat(unsigned long dev_id)
-{
-    struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
-
-    unsigned long flags;
-    save_flags(flags);
-    cli();
-
-    if(kbd->repeat_key)
-    {
-        usb_kbd_handle_key(kbd->repeat_key, 1);
-
-        /* reset repeat timer */
-        kbd->repeat_timer.function = usb_kbd_repeat;
-        kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_RATE;
-        kbd->repeat_timer.data = (unsigned long) kbd;
-        kbd->repeat_timer.prev = NULL;
-        kbd->repeat_timer.next = NULL;
-        add_timer(&kbd->repeat_timer);
-    }
-
-    restore_flags(flags);
-}
-
-static int
-usb_kbd_irq(int state, void *buffer, void *dev_id)
-{
-    struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
-    unsigned long *down = (unsigned long*) buffer;
-
-    if(kbd->down[0] != down[0] || kbd->down[1] != down[1])
-    {
-        unsigned char *olddown, *newdown;
-        unsigned char modsdelta, key;
-        int i;
-
-        /* handle modifier change */
-        modsdelta = (*(unsigned char*) down ^ *(unsigned char*) kbd->down);
-        if(modsdelta)
-        {
-            for(i = 0; i < 8; i++)
-            {
-                if(modsdelta & 0x01)
-                {
-                    int pressed = (*(unsigned char*) down >> i) & 0x01;
-                    usb_kbd_handle_key(
-                        i + USBKBD_MODIFIER_BASE,
-                        pressed);
-                }
-                modsdelta >>= 1;
-            }
-        }
-
-        olddown = (unsigned char*) kbd->down + USBKBD_KEYCODE_OFFSET;
-        newdown = (unsigned char*) down + USBKBD_KEYCODE_OFFSET;
-
-        /* handle released keys */
-        for(i = 0; i < USBKBD_KEYCODE_COUNT; i++)
-        {
-            key = olddown[i];
-            if(USBKBD_VALID_KEYCODE(key)
-               && !USBKBD_FIND_KEYCODE(newdown, key, USBKBD_KEYCODE_COUNT))
-            {
-                usb_kbd_handle_key(key, 0);
-            }
-        }
-
-        /* handle pressed keys */
-        kbd->repeat_key = 0;
-        for(i = 0; i < USBKBD_KEYCODE_COUNT; i++)
-        {
-            key = newdown[i];
-            if(USBKBD_VALID_KEYCODE(key)
-               && !USBKBD_FIND_KEYCODE(olddown, key, USBKBD_KEYCODE_COUNT))
-            {
-                usb_kbd_handle_key(key, 1);
-                kbd->repeat_key = key;
-            }
-        }
-
-        /* set repeat timer if any keys were pressed */
-        if(kbd->repeat_key)
-        {
-            del_timer(&kbd->repeat_timer);
-            kbd->repeat_timer.function = usb_kbd_repeat;
-            kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_DELAY;
-            kbd->repeat_timer.data = (unsigned long) kbd;
-            kbd->repeat_timer.prev = NULL;
-            kbd->repeat_timer.next = NULL;
-            add_timer(&kbd->repeat_timer);
-        }
-
-        kbd->down[0] = down[0];
-        kbd->down[1] = down[1];
-    }
-
-    return 1;
-}
-
-static int
-usb_kbd_probe(struct usb_device *dev)
-{
-    struct usb_interface_descriptor *interface;
-    struct usb_endpoint_descriptor *endpoint;
-    struct usb_keyboard *kbd;
-
-    interface = &dev->config[0].interface[0];
-    endpoint = &interface->endpoint[0];
-
-    if(interface->bInterfaceClass != 3
-       || interface->bInterfaceSubClass != 1
-       || interface->bInterfaceProtocol != 1)
-    {
-        return -1;
-    }
-
-    printk(KERN_INFO "USB HID boot protocol keyboard detected.\n");
-
-    kbd = kmalloc(sizeof(struct usb_keyboard), GFP_KERNEL);
-    if(kbd)
-    {
-        memset(kbd, 0, sizeof(*kbd));
-        kbd->dev = dev;
-        dev->private = kbd;
-
-        usb_set_configuration(dev, dev->config[0].bConfigurationValue);
-        usb_set_protocol(dev, 0);
-        usb_set_idle(dev, 0, 0);
-        
-        usb_request_irq(dev,
-                        usb_rcvctrlpipe(dev, endpoint->bEndpointAddress),
-                        usb_kbd_irq,
-                        endpoint->bInterval,
-                        kbd);
-
-        list_add(&kbd->list, &usb_kbd_list);
-    }
-
-    return 0;
-}
-
-static void
-usb_kbd_disconnect(struct usb_device *dev)
-{
-    struct usb_keyboard *kbd = (struct usb_keyboard*) dev->private;
-    if(kbd)
-    {
-        dev->private = NULL;
-        list_del(&kbd->list);
-        del_timer(&kbd->repeat_timer);
-        kfree(kbd);
-    }
-
-    printk(KERN_INFO "USB HID boot protocol keyboard removed.\n");
-}
-
-int
-usb_kbd_init(void)
-{
-    usb_register(&usb_kbd_driver);
-    return 0;
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/keymap.c linux.18p8/drivers/usb/keymap.c
--- linux.vanilla/drivers/usb/keymap.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/keymap.c	Thu Jan  1 01:00:00 1970
@@ -1,50 +0,0 @@
-unsigned char usb_kbd_map[256] = 
-{
-    0x00,  0x00,  0x00,  0x00,  0x1e,  0x30,  0x2e,  0x20,
-    0x12,  0x21,  0x22,  0x23,  0x17,  0x24,  0x25,  0x26,
-
-    0x32,  0x31,  0x18,  0x19,  0x10,  0x13,  0x1f,  0x14,
-    0x16,  0x2f,  0x11,  0x2d,  0x15,  0x2c,  0x02,  0x03,
-
-    0x04,  0x05,  0x06,  0x07,  0x08,  0x09,  0x0a,  0x0b,
-    0x1c,  0x01,  0xd3,  0x0f,  0x39,  0x0c,  0x0d,  0x1a,
-
-    0x1b,  0x2b,  0x00,  0x27,  0x28,  0x29,  0x33,  0x34,
-    0x35,  0x3a,  0x3b,  0x3c,  0x3d,  0x3e,  0x3f,  0x40,
-
-    0x41,  0x42,  0x43,  0x44,  0x57,  0x58,  0xb7,  0x46,
-    0x00,  0xd2,  0xc7,  0xc9,  0x63,  0xcf,  0xd1,  0xcd,
-
-    0xcb,  0xd0,  0xc8,  0x45,  0xb5,  0x37,  0x4a,  0x4e,
-    0x9c,  0x4f,  0x50,  0x51,  0x4b,  0x4c,  0x4d,  0x47,
-
-    0x48,  0x49,  0x52,  0x53,  0x00,  0x6d,  0x00,  0x00,
-    0xbd,  0xbe,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x1d,  0x2a,  0x38,  0xdb,  0x9d,  0x36,  0xb8,  0xdc,
-
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/maps/fixup.map linux.18p8/drivers/usb/maps/fixup.map
--- linux.vanilla/drivers/usb/maps/fixup.map	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/maps/fixup.map	Thu Jan  1 01:00:00 1970
@@ -1,31 +0,0 @@
-# misc fixes
-keycode   0 = Pause
-keycode  29 = Control
-keycode  99 = Remove
-keycode  42 = Shift
-keycode  54 = Shift_R
-keycode 109 = Application
-
-# E0 keys (or'ed with 0x80)
-keycode 156 = KP_Enter
-keycode 157 = Control_R
-keycode 181 = KP_Divide
-keycode 183 = Print_Screen
-keycode 184 = Alt_R
-keycode 189 = F13
-keycode 190 = F14
-keycode 193 = F17
-keycode 198 = Break
-keycode 199 = Home
-keycode 200 = Up
-keycode 201 = Prior
-keycode 203 = Left
-keycode 205 = Right
-keycode 207 = End
-keycode 208 = Down
-keycode 209 = Next
-keycode 210 = Insert
-keycode 211 = Delete
-keycode 219 = Window
-keycode 220 = Window_R
-keycode 221 = Menu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/maps/serial.map linux.18p8/drivers/usb/maps/serial.map
--- linux.vanilla/drivers/usb/maps/serial.map	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/maps/serial.map	Thu Jan  1 01:00:00 1970
@@ -1,370 +0,0 @@
-keymaps 0-2,4-6,8-9,12
-keycode   1 = Escape          
-	alt	keycode   1 = Meta_Escape     
-	shift	alt	keycode   1 = Meta_Escape     
-	control	alt	keycode   1 = Meta_Escape     
-keycode   2 = one              exclam          
-	alt	keycode   2 = Meta_one        
-	shift	alt	keycode   2 = Meta_exclam     
-keycode   3 = two              at               at               nul              nul             
-	alt	keycode   3 = Meta_two        
-	shift	alt	keycode   3 = Meta_at         
-	control	alt	keycode   3 = Meta_nul        
-keycode   4 = three            numbersign      
-	control	keycode   4 = Escape          
-	alt	keycode   4 = Meta_three      
-	shift	alt	keycode   4 = Meta_numbersign 
-keycode   5 = four             dollar           dollar           Control_backslash
-	alt	keycode   5 = Meta_four       
-	shift	alt	keycode   5 = Meta_dollar     
-	control	alt	keycode   5 = Meta_Control_backslash
-keycode   6 = five             percent         
-	control	keycode   6 = Control_bracketright
-	alt	keycode   6 = Meta_five       
-	shift	alt	keycode   6 = Meta_percent    
-keycode   7 = six              asciicircum     
-	control	keycode   7 = Control_asciicircum
-	alt	keycode   7 = Meta_six        
-	shift	alt	keycode   7 = Meta_asciicircum
-keycode   8 = seven            ampersand        braceleft        Control_underscore
-	alt	keycode   8 = Meta_seven      
-	shift	alt	keycode   8 = Meta_ampersand  
-	control	alt	keycode   8 = Meta_Control_underscore
-keycode   9 = eight            asterisk         bracketleft      Delete          
-	alt	keycode   9 = Meta_eight      
-	shift	alt	keycode   9 = Meta_asterisk   
-	control	alt	keycode   9 = Meta_Delete     
-keycode  10 = nine             parenleft        bracketright    
-	alt	keycode  10 = Meta_nine       
-	shift	alt	keycode  10 = Meta_parenleft  
-keycode  11 = zero             parenright       braceright      
-	alt	keycode  11 = Meta_zero       
-	shift	alt	keycode  11 = Meta_parenright 
-keycode  12 = minus            underscore       backslash        Control_underscore Control_underscore
-	alt	keycode  12 = Meta_minus      
-	shift	alt	keycode  12 = Meta_underscore 
-	control	alt	keycode  12 = Meta_Control_underscore
-keycode  13 = equal            plus            
-	alt	keycode  13 = Meta_equal      
-	shift	alt	keycode  13 = Meta_plus       
-keycode  14 = Delete          
-	alt	keycode  14 = Meta_Delete     
-	shift	alt	keycode  14 = Meta_Delete     
-	control	alt	keycode  14 = Meta_Delete     
-keycode  15 = Tab             
-	alt	keycode  15 = Meta_Tab        
-	shift	alt	keycode  15 = Meta_Tab        
-	control	alt	keycode  15 = Meta_Tab        
-keycode  16 = q               
-keycode  17 = w               
-keycode  18 = e               
-keycode  19 = r               
-keycode  20 = t               
-keycode  21 = y               
-keycode  22 = u               
-keycode  23 = i               
-keycode  24 = o               
-keycode  25 = p               
-keycode  26 = bracketleft      braceleft       
-	control	keycode  26 = Escape          
-	alt	keycode  26 = Meta_bracketleft
-	shift	alt	keycode  26 = Meta_braceleft  
-keycode  27 = bracketright     braceright       asciitilde       Control_bracketright
-	alt	keycode  27 = Meta_bracketright
-	shift	alt	keycode  27 = Meta_braceright 
-	control	alt	keycode  27 = Meta_Control_bracketright
-keycode  28 = Return          
-	alt	keycode  28 = Meta_Control_m  
-keycode  29 = Control         
-keycode  30 = a               
-keycode  31 = s               
-keycode  32 = d               
-keycode  33 = f               
-keycode  34 = g               
-keycode  35 = h               
-keycode  36 = j               
-keycode  37 = k               
-keycode  38 = l               
-keycode  39 = semicolon        colon           
-	alt	keycode  39 = Meta_semicolon  
-	shift	alt	keycode  39 = Meta_colon      
-keycode  40 = apostrophe       quotedbl        
-	control	keycode  40 = Control_g       
-	alt	keycode  40 = Meta_apostrophe 
-	shift	alt	keycode  40 = Meta_quotedbl   
-keycode  41 = grave            asciitilde      
-	control	keycode  41 = nul             
-	alt	keycode  41 = Meta_grave      
-	shift	alt	keycode  41 = Meta_asciitilde 
-keycode  42 = Shift           
-keycode  43 = backslash        bar             
-	control	keycode  43 = Control_backslash
-	alt	keycode  43 = Meta_backslash  
-	shift	alt	keycode  43 = Meta_bar        
-keycode  44 = z               
-keycode  45 = x               
-keycode  46 = c               
-keycode  47 = v               
-keycode  48 = b               
-keycode  49 = n               
-keycode  50 = m               
-keycode  51 = comma            less            
-	alt	keycode  51 = Meta_comma      
-	shift	alt	keycode  51 = Meta_less       
-keycode  52 = period           greater         
-	alt	keycode  52 = Meta_period     
-	shift	alt	keycode  52 = Meta_greater    
-keycode  53 = slash            question        
-	control	keycode  53 = Delete          
-	alt	keycode  53 = Meta_slash      
-	shift	alt	keycode  53 = Meta_question   
-keycode  54 = Shift           
-keycode  55 = KP_Multiply     
-	altgr	keycode  55 = Hex_C           
-keycode  56 = Alt             
-keycode  57 = space           
-	control	keycode  57 = nul             
-	alt	keycode  57 = Meta_space      
-	shift	alt	keycode  57 = Meta_space      
-	control	alt	keycode  57 = Meta_nul        
-keycode  58 = Caps_Lock       
-keycode  59 = F1               F13              Console_13       F25             
-	alt	keycode  59 = Console_1       
-	control	alt	keycode  59 = Console_1       
-keycode  60 = F2               F14              Console_14       F26             
-	alt	keycode  60 = Console_2       
-	control	alt	keycode  60 = Console_2       
-keycode  61 = F3               F15              Console_15       F27             
-	alt	keycode  61 = Console_3       
-	control	alt	keycode  61 = Console_3       
-keycode  62 = F4               F16              Console_16       F28             
-	alt	keycode  62 = Console_4       
-	control	alt	keycode  62 = Console_4       
-keycode  63 = F5               F17              Console_17       F29             
-	alt	keycode  63 = Console_5       
-	control	alt	keycode  63 = Console_5       
-keycode  64 = F6               F18              Console_18       F30             
-	alt	keycode  64 = Console_6       
-	control	alt	keycode  64 = Console_6       
-keycode  65 = F7               F19              Console_19       F31             
-	alt	keycode  65 = Console_7       
-	control	alt	keycode  65 = Console_7       
-keycode  66 = F8               F20              Console_20       F32             
-	alt	keycode  66 = Console_8       
-	control	alt	keycode  66 = Console_8       
-keycode  67 = F9               F21              Console_21       F33             
-	alt	keycode  67 = Console_9       
-	control	alt	keycode  67 = Console_9       
-keycode  68 = F10              F22              Console_22       F34             
-	alt	keycode  68 = Console_10      
-	control	alt	keycode  68 = Console_10      
-keycode  69 = Num_Lock        
-	altgr	keycode  69 = Hex_E           
-keycode  70 = Scroll_Lock      Show_Memory      Show_Registers   Show_State      
-	alt	keycode  70 = Scroll_Lock     
-keycode  71 = KP_7            
-	altgr	keycode  71 = Hex_7           
-	alt	keycode  71 = Ascii_7         
-keycode  72 = KP_8            
-	altgr	keycode  72 = Hex_8           
-	alt	keycode  72 = Ascii_8         
-keycode  73 = KP_9            
-	altgr	keycode  73 = Hex_9           
-	alt	keycode  73 = Ascii_9         
-keycode  74 = KP_Subtract     
-keycode  75 = KP_4            
-	altgr	keycode  75 = Hex_4           
-	alt	keycode  75 = Ascii_4         
-keycode  76 = KP_5            
-	altgr	keycode  76 = Hex_5           
-	alt	keycode  76 = Ascii_5         
-keycode  77 = KP_6            
-	altgr	keycode  77 = Hex_6           
-	alt	keycode  77 = Ascii_6         
-keycode  78 = KP_Add          
-keycode  79 = KP_1            
-	altgr	keycode  79 = Hex_1           
-	alt	keycode  79 = Ascii_1         
-keycode  80 = KP_2            
-	altgr	keycode  80 = Hex_2           
-	alt	keycode  80 = Ascii_2         
-keycode  81 = KP_3            
-	altgr	keycode  81 = Hex_3           
-	alt	keycode  81 = Ascii_3         
-keycode  82 = KP_0            
-	altgr	keycode  82 = Hex_0           
-	alt	keycode  82 = Ascii_0         
-keycode  83 = KP_Period       
-	altgr	control	keycode  83 = Boot            
-	control	alt	keycode  83 = Boot            
-keycode  84 = Last_Console    
-keycode  85 =
-keycode  86 = less             greater          bar             
-	alt	keycode  86 = Meta_less       
-	shift	alt	keycode  86 = Meta_greater    
-keycode  87 = F11              F23              Console_23       F35             
-	alt	keycode  87 = Console_11      
-	control	alt	keycode  87 = Console_11      
-keycode  88 = F12              F24              Console_24       F36             
-	alt	keycode  88 = Console_12      
-	control	alt	keycode  88 = Console_12      
-keycode  89 =
-keycode  90 =
-keycode  91 =
-keycode  92 =
-keycode  93 =
-keycode  94 =
-keycode  95 =
-keycode  96 = KP_Enter        
-keycode  97 = Control         
-keycode  98 = KP_Divide       
-	altgr	keycode  98 = Hex_B           
-keycode  99 = Control_backslash
-	alt	keycode  99 = Meta_Control_backslash
-	shift	alt	keycode  99 = Meta_Control_backslash
-	control	alt	keycode  99 = Meta_Control_backslash
-keycode 100 = AltGr           
-keycode 101 = Break           
-keycode 102 = Find            
-keycode 103 = Up              
-	alt	keycode 103 = KeyboardSignal  
-keycode 104 = Prior           
-	shift	keycode 104 = Scroll_Backward 
-keycode 105 = Left            
-	alt	keycode 105 = Decr_Console    
-keycode 106 = Right           
-	alt	keycode 106 = Incr_Console    
-keycode 107 = Select          
-keycode 108 = Down            
-keycode 109 = Next            
-	shift	keycode 109 = Scroll_Forward  
-keycode 110 = Insert          
-keycode 111 = Remove          
-	altgr	control	keycode 111 = Boot            
-	control	alt	keycode 111 = Boot            
-keycode 112 = Macro           
-	altgr	control	keycode 112 = VoidSymbol      
-	shift	alt	keycode 112 = VoidSymbol      
-keycode 113 = F13             
-	altgr	control	keycode 113 = VoidSymbol      
-	shift	alt	keycode 113 = VoidSymbol      
-keycode 114 = F14             
-	altgr	control	keycode 114 = VoidSymbol      
-	shift	alt	keycode 114 = VoidSymbol      
-keycode 115 = Help            
-	altgr	control	keycode 115 = VoidSymbol      
-	shift	alt	keycode 115 = VoidSymbol      
-keycode 116 = Do              
-	altgr	control	keycode 116 = VoidSymbol      
-	shift	alt	keycode 116 = VoidSymbol      
-keycode 117 = F17             
-	altgr	control	keycode 117 = VoidSymbol      
-	shift	alt	keycode 117 = VoidSymbol      
-keycode 118 = KP_MinPlus      
-	altgr	control	keycode 118 = VoidSymbol      
-	shift	alt	keycode 118 = VoidSymbol      
-keycode 119 = Pause           
-keycode 120 =
-keycode 121 =
-keycode 122 =
-keycode 123 =
-keycode 124 =
-keycode 125 =
-keycode 126 =
-keycode 127 =
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to 'À'
-compose '`' 'a' to 'à'
-compose '\'' 'A' to 'Á'
-compose '\'' 'a' to 'á'
-compose '^' 'A' to 'Â'
-compose '^' 'a' to 'â'
-compose '~' 'A' to '�'
-compose '~' 'a' to '�'
-compose '"' 'A' to 'Ä'
-compose '"' 'a' to 'ä'
-compose 'O' 'A' to 'Ċ'
-compose 'o' 'a' to 'ċ'
-compose '0' 'A' to 'Ċ'
-compose '0' 'a' to 'ċ'
-compose 'A' 'A' to 'Ċ'
-compose 'a' 'a' to 'ċ'
-compose 'A' 'E' to 'Ĉ'
-compose 'a' 'e' to 'ĉ'
-compose ',' 'C' to 'Ç'
-compose ',' 'c' to 'ç'
-compose '`' 'E' to 'È'
-compose '`' 'e' to 'è'
-compose '\'' 'E' to 'É'
-compose '\'' 'e' to 'é'
-compose '^' 'E' to 'Ê'
-compose '^' 'e' to 'ê'
-compose '"' 'E' to 'Ë'
-compose '"' 'e' to 'ë'
-compose '`' 'I' to 'Ì'
-compose '`' 'i' to 'ì'
-compose '\'' 'I' to 'Í'
-compose '\'' 'i' to 'í'
-compose '^' 'I' to 'Î'
-compose '^' 'i' to 'î'
-compose '"' 'I' to 'Ï'
-compose '"' 'i' to 'ï'
-compose '-' 'D' to '�'
-compose '-' 'd' to '�'
-compose '~' 'N' to 'Ñ'
-compose '~' 'n' to 'ñ'
-compose '`' 'O' to 'Ò'
-compose '`' 'o' to 'ò'
-compose '\'' 'O' to 'Ó'
-compose '\'' 'o' to 'ó'
-compose '^' 'O' to 'Ô'
-compose '^' 'o' to 'ô'
-compose '~' 'O' to 'Ġ'
-compose '~' 'o' to 'ġ'
-compose '"' 'O' to 'Ö'
-compose '"' 'o' to 'ö'
-compose '/' 'O' to 'Ĝ'
-compose '/' 'o' to 'ĝ'
-compose '`' 'U' to 'Ù'
-compose '`' 'u' to 'ù'
-compose '\'' 'U' to 'Ú'
-compose '\'' 'u' to 'ú'
-compose '^' 'U' to 'Û'
-compose '^' 'u' to 'û'
-compose '"' 'U' to 'Ü'
-compose '"' 'u' to 'ü'
-compose '\'' 'Y' to 'Ŭ'
-compose '\'' 'y' to 'ŭ'
-compose 'T' 'H' to 'Ŝ'
-compose 't' 'h' to 'ŝ'
-compose 's' 's' to 'ß'
-compose '"' 'y' to '˙'
-compose 's' 'z' to 'ß'
-compose 'i' 'j' to '˙'
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/maps/usb.map linux.18p8/drivers/usb/maps/usb.map
--- linux.vanilla/drivers/usb/maps/usb.map	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/maps/usb.map	Thu Jan  1 01:00:00 1970
@@ -1,233 +0,0 @@
-# USB kernel keymap.
-keymaps 0-2,4-5,8,12
-
-keycode   4 = a
-	altgr   keycode  30 = Hex_A
-keycode   5 = b
-	altgr   keycode  48 = Hex_B
-keycode   6 = c
-	altgr   keycode  46 = Hex_C   
-keycode   7 = d
-	altgr   keycode  32 = Hex_D   
-keycode   8 = e
-	altgr   keycode  18 = Hex_E   
-keycode   9 = f
-	altgr   keycode  33 = Hex_F               
-keycode  10 = g               
-keycode  11 = h               
-keycode  12 = i               
-keycode  13 = j               
-keycode  14 = k               
-keycode  15 = l               
-keycode  16 = m               
-keycode  17 = n               
-keycode  18 = o               
-keycode  19 = p               
-keycode  20 = q               
-keycode  21 = r               
-keycode  22 = s               
-keycode  23 = t               
-keycode  24 = u               
-keycode  25 = v               
-keycode  26 = w               
-keycode  27 = x               
-keycode  28 = y               
-keycode  29 = z               
-keycode  30 = one              exclam          
-	alt     keycode   2 = Meta_one        
-keycode  31 = two              at
-	control	keycode   3 = nul             
-	shift	control	keycode   3 = nul             
-	alt	keycode   3 = Meta_two        
-keycode  32 = three            numbersign      
-	control keycode   4 = Escape          
-	alt     keycode   4 = Meta_three      
-keycode  33 = four             dollar
-	control keycode   5 = Control_backslash
-	alt     keycode   5 = Meta_four       
-keycode  34 = five             percent         
-	control keycode   6 = Control_bracketright
-	alt     keycode   6 = Meta_five       
-keycode  35 = six              asciicircum     
-	control keycode   7 = Control_asciicircum
-	alt     keycode   7 = Meta_six        
-keycode  36 = seven            ampersand
-	control keycode   8 = Control_underscore
-	alt     keycode   8 = Meta_seven      
-keycode  37 = eight            asterisk
-	control keycode   9 = Delete          
-	alt     keycode   9 = Meta_eight      
-keycode  38 = nine             parenleft
-	alt     keycode  10 = Meta_nine       
-keycode  39 = zero             parenright
-	alt     keycode  11 = Meta_zero       
-keycode  40 = Return          
-	alt     keycode  28 = Meta_Control_m  
-keycode  41 = Escape           Escape          
-	alt     keycode   1 = Meta_Escape     
-keycode  42 = Delete           Delete          
-	control keycode  14 = BackSpace
-	alt     keycode  14 = Meta_Delete     
-keycode  43 = Tab              Tab             
-	alt     keycode  15 = Meta_Tab        
-keycode  44 = space            space           
-	control keycode  57 = nul             
-	alt     keycode  57 = Meta_space      
-keycode  45 = minus            underscore       backslash       
-	control	keycode  12 = Control_underscore
-	shift	control	keycode  12 = Control_underscore
-	alt	keycode  12 = Meta_minus      
-keycode  46 = equal            plus            
-	alt     keycode  13 = Meta_equal      
-keycode  47 = bracketleft      braceleft       
-	control keycode  26 = Escape          
-	alt     keycode  26 = Meta_bracketleft
-keycode  48 = bracketright     braceright       asciitilde      
-	control keycode  27 = Control_bracketright
-	alt     keycode  27 = Meta_bracketright
-keycode  49 = backslash        bar             
-	control keycode  43 = Control_backslash
-	alt     keycode  43 = Meta_backslash  
-keycode 50 =
-keycode  51 = semicolon        colon           
-	alt     keycode  39 = Meta_semicolon  
-keycode  52 = apostrophe       quotedbl        
-	control keycode  40 = Control_g       
-	alt     keycode  40 = Meta_apostrophe 
-keycode  53 = grave            asciitilde      
-	control keycode  41 = nul             
-	alt     keycode  41 = Meta_grave      
-keycode  54 = comma            less            
-	alt     keycode  51 = Meta_comma      
-keycode  55 = period           greater         
-	control keycode  52 = Compose         
-	alt     keycode  52 = Meta_period     
-keycode  56 = slash            question        
-	control keycode  53 = Delete          
-	alt     keycode  53 = Meta_slash      
-keycode  57 = Caps_Lock       
-keycode  58 = F1               F11              Console_13      
-	control keycode  59 = F1              
-	alt     keycode  59 = Console_1       
-	control alt     keycode  59 = Console_1       
-keycode  59 = F2               F12              Console_14      
-	control keycode  60 = F2              
-	alt     keycode  60 = Console_2       
-	control alt     keycode  60 = Console_2       
-keycode  60 = F3               F13              Console_15      
-	control keycode  61 = F3              
-	alt     keycode  61 = Console_3       
-	control alt     keycode  61 = Console_3       
-keycode  61 = F4               F14              Console_16      
-	control keycode  62 = F4              
-	alt     keycode  62 = Console_4       
-	control alt     keycode  62 = Console_4       
-keycode  62 = F5               F15              Console_17      
-	control keycode  63 = F5              
-	alt     keycode  63 = Console_5       
-	control alt     keycode  63 = Console_5       
-keycode  63 = F6               F16              Console_18      
-	control keycode  64 = F6              
-	alt     keycode  64 = Console_6       
-	control alt     keycode  64 = Console_6       
-keycode  64 = F7               F17              Console_19      
-	control keycode  65 = F7              
-	alt     keycode  65 = Console_7       
-	control alt     keycode  65 = Console_7       
-keycode  65 = F8               F18              Console_20      
-	control keycode  66 = F8              
-	alt     keycode  66 = Console_8       
-	control alt     keycode  66 = Console_8       
-keycode  66 = F9               F19              Console_21      
-	control keycode  67 = F9              
-	alt     keycode  67 = Console_9       
-	control alt     keycode  67 = Console_9       
-keycode  67 = F10              F20              Console_22      
-	control keycode  68 = F10             
-	alt     keycode  68 = Console_10      
-	control alt     keycode  68 = Console_10      
-keycode  68 = F11              F11              Console_23      
-	control keycode  87 = F11             
-	alt     keycode  87 = Console_11      
-	control alt     keycode  87 = Console_11      
-keycode  69 = F12              F12              Console_24      
-	control keycode  88 = F12             
-	alt     keycode  88 = Console_12      
-	control alt     keycode  88 = Console_12      
-keycode  70 = Print_Screen
-keycode  71 = Scroll_Lock      Show_Memory      Show_Registers  
-	control keycode  70 = Show_State      
-	alt     keycode  70 = Scroll_Lock     
-keycode  72 = Pause           
-keycode  73 = Insert          
-keycode  74 = Home
-keycode  75 = Prior           
-	shift   keycode 104 = Scroll_Backward 
-keycode  76 = Remove          
-#	altgr   control keycode 111 = Boot            
-	control alt     keycode 111 = Boot            
-keycode  77 = End
-keycode  78 = Next            
-	shift   keycode 109 = Scroll_Forward  
-keycode  79 = Right           
-	alt     keycode 106 = Incr_Console
-keycode  80 = Left            
-	alt     keycode 105 = Decr_Console
-keycode  81 = Down            
-keycode  82 = Up              
-keycode  83 = Num_Lock
-	shift   keycode  69 = Bare_Num_Lock
-keycode  84 = KP_Divide       
-keycode  85 = KP_Multiply     
-keycode  86 = KP_Subtract     
-keycode  87 = KP_Add          
-keycode  88 = KP_Enter        
-keycode  89 = KP_1            
-	alt     keycode  79 = Ascii_1         
-	altgr   keycode  79 = Hex_1         
-keycode  90 = KP_2            
-	alt     keycode  80 = Ascii_2         
-	altgr   keycode  80 = Hex_2         
-keycode  91 = KP_3            
-	alt     keycode  81 = Ascii_3         
-	altgr   keycode  81 = Hex_3         
-keycode  92 = KP_4            
-	alt     keycode  75 = Ascii_4         
-	altgr   keycode  75 = Hex_4         
-keycode  93 = KP_5            
-	alt     keycode  76 = Ascii_5         
-	altgr   keycode  76 = Hex_5         
-keycode  94 = KP_6            
-	alt     keycode  77 = Ascii_6         
-	altgr   keycode  77 = Hex_6         
-keycode  95 = KP_7            
-	alt     keycode  71 = Ascii_7         
-	altgr   keycode  71 = Hex_7         
-keycode  96 = KP_8            
-	alt     keycode  72 = Ascii_8         
-	altgr   keycode  72 = Hex_8         
-keycode  97 = KP_9            
-	alt     keycode  73 = Ascii_9         
-	altgr   keycode  73 = Hex_9         
-keycode  98 = KP_0            
-	alt     keycode  82 = Ascii_0         
-	altgr   keycode  82 = Hex_0         
-keycode  99 = KP_Period       
-#	altgr   control keycode  83 = Boot            
-	control alt     keycode  83 = Boot            
-keycode 100 =
-keycode 101 = Application
-keycode 102 =
-keycode 103 =
-keycode 104 = F13             
-keycode 105 = F14             
-
-# modifiers
-keycode 120 = Control
-keycode 121 = Shift
-keycode 122 = Alt
-keycode 123 = Window
-keycode 124 = Control_R
-keycode 125 = Shift_R
-keycode 126 = Alt_R
-keycode 127 = Window_R
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/mdc800.c linux.18p8/drivers/usb/mdc800.c
--- linux.vanilla/drivers/usb/mdc800.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/mdc800.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,935 @@
+/*
+ * copyright (C) 1999/2000 by Henning Zabel <henning@uni-paderborn.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*
+ *	USB-Kernel Driver for the Mustek MDC800 Digital Camera
+ *	(c) 1999/2000 Henning Zabel <henning@uni-paderborn.de>
+ *
+ *
+ *	The driver brings the USB functions of the MDC800 to Linux.
+ * To use the Camera you must support the USB Protocoll of the camera
+ * to the Kernel Node.
+ * The Driver uses a misc device Node. Create it with :
+ * mknod /dev/mustek c 180 32
+ *
+ * The driver supports only one camera.
+ *
+ * version 0.7.3
+ * bugfix : The mdc800->state field gets set to READY after the
+ * the diconnect function sets it to NOT_CONNECTED. This makes the
+ * driver running like the camera is connected and causes some
+ * hang ups.
+ *
+ * version 0.7.1
+ * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload
+ * problems when compiled as Module.
+ * (04/04/2000)
+ *
+ * The mdc800 driver gets assigned the USB Minor 32-47. The Registration
+ * was updated to use these values.
+ * (26/03/2000)
+ *
+ * The Init und Exit Module Function are updated.
+ * (01/03/2000)
+ *
+ * version 0.7.0
+ * Rewrite of the driver : The driver now uses URB's. The old stuff
+ * has been removed.
+ *
+ * version 0.6.0
+ * Rewrite of this driver: The Emulation of the rs232 protocoll
+ * has been removed from the driver. A special executeCommand function
+ * for this driver is included to gphoto.
+ * The driver supports two kind of communication to bulk endpoints.
+ * Either with the dev->bus->ops->bulk... or with callback function.
+ * (09/11/1999)
+ *
+ * version 0.5.0:
+ *	first Version that gets a version number. Most of the needed
+ * functions work.
+ * (20/10/1999)
+ */
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+
+#include <linux/usb.h>
+
+#define VERSION 	"0.7.3"
+#define RELEASE_DATE 	"(24/04/2000)"
+
+/* Vendor and Product Information */
+#define MDC800_VENDOR_ID 	0x055f
+#define MDC800_PRODUCT_ID	0xa800
+
+/* Timeouts (msec) */
+#define TO_DOWNLOAD_GET_READY		1500
+#define TO_DOWNLOAD_GET_BUSY		1500
+#define TO_WRITE_GET_READY		1000
+#define TO_DEFAULT_COMMAND		5000
+#define TO_READ_FROM_IRQ 		TO_DEFAULT_COMMAND
+#define TO_GET_READY			TO_DEFAULT_COMMAND
+
+/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
+#define MDC800_DEVICE_MINOR_BASE 32
+
+
+/**************************************************************************
+	Data and structs
+***************************************************************************/
+
+
+typedef enum {
+	NOT_CONNECTED, READY, WORKING, DOWNLOAD
+} mdc800_state;
+
+
+/* Data for the driver */
+struct mdc800_data
+{
+	struct usb_device *	dev;			// Device Data
+	mdc800_state 		state;
+
+	unsigned int		endpoint [4];
+
+	purb_t			irq_urb;
+	wait_queue_head_t	irq_wait;
+	char*			irq_urb_buffer;
+
+	int			camera_busy;          // is camera busy ?
+	int 			camera_request_ready; // Status to synchronize with irq
+	char 			camera_response [8];	 // last Bytes send after busy
+
+	purb_t   		write_urb;
+	char*			write_urb_buffer;
+	wait_queue_head_t	write_wait;
+
+
+	purb_t	   		download_urb;
+	char*			download_urb_buffer;
+	wait_queue_head_t	download_wait;
+	int			download_left;		// Bytes left to download ?
+
+
+	/* Device Data */
+	char			out [64];	// Answer Buffer
+	int 			out_ptr;		// Index to the first not readen byte
+	int			out_count;	// Bytes in the buffer
+
+	int			open;			// Camera device open ?
+	int			rw_lock;		// Block read <-> write
+
+	char 			in [8];			// Command Input Buffer
+	int  			in_count;
+
+	int			pic_index;		// Cache for the Imagesize (-1 for nothing cached )
+	int			pic_len;
+};
+
+
+/* Specification of the Endpoints */
+static struct usb_endpoint_descriptor mdc800_ed [4] =
+{
+	{ 0,0, 0x01, 0x02,  8, 0,0,0 },
+	{ 0,0, 0x82, 0x03,  8, 0,0,0 },
+	{ 0,0, 0x03, 0x02, 64, 0,0,0 },
+	{ 0,0, 0x84, 0x02, 64, 0,0,0 }
+};
+
+
+/* The Variable used by the driver */
+static struct mdc800_data* mdc800=0;
+
+
+/***************************************************************************
+	The USB Part of the driver
+****************************************************************************/
+
+static int mdc800_endpoint_equals (struct usb_endpoint_descriptor *a,struct usb_endpoint_descriptor *b)
+{
+	return (
+		   ( a->bEndpointAddress == b->bEndpointAddress )
+		&& ( a->bmAttributes     == b->bmAttributes     )
+		&& ( a->wMaxPacketSize   == b->wMaxPacketSize   )
+	);
+}
+
+
+/*
+ * Checks wether the camera responds busy
+ */
+static int mdc800_isBusy (char* ch)
+{
+	int i=0;
+	while (i<8)
+	{
+		if (ch [i] != (char)0x99)
+			return 0;
+		i++;
+	}
+	return 1;
+}
+
+
+/*
+ * Checks wether the Camera is ready
+ */
+static int mdc800_isReady (char *ch)
+{
+	int i=0;
+	while (i<8)
+	{
+		if (ch [i] != (char)0xbb)
+			return 0;
+		i++;
+	}
+	return 1;
+}
+
+
+
+/*
+ * USB IRQ Handler for InputLine
+ */
+static void mdc800_usb_irq (struct urb *urb)
+{
+	int data_received=0, wake_up;
+	unsigned char* b=urb->transfer_buffer;
+	struct mdc800_data* mdc800=urb->context;
+
+	if (urb->status >= 0)
+	{
+
+		//dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+
+		if (mdc800_isBusy (b))
+		{
+			if (!mdc800->camera_busy)
+			{
+				mdc800->camera_busy=1;
+				dbg ("gets busy");
+			}
+		}
+		else
+		{
+			if (mdc800->camera_busy && mdc800_isReady (b))
+			{
+				mdc800->camera_busy=0;
+				dbg ("gets ready");
+			}
+		}
+		if (!(mdc800_isBusy (b) || mdc800_isReady (b)))
+		{
+			/* Store Data in camera_answer field */
+			dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+
+			memcpy (mdc800->camera_response,b,8);
+			data_received=1;
+		}
+	}
+	wake_up= ( mdc800->camera_request_ready > 0 )
+				&&
+				(
+					((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy))
+				||
+					((mdc800->camera_request_ready == 2) && data_received)
+				||
+					((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
+				||
+					(urb->status < 0)
+				);
+
+	if (wake_up)
+	{
+		mdc800->camera_request_ready=0;
+		wake_up_interruptible (&mdc800->irq_wait);
+	}
+}
+
+
+/*
+ * Waits a while until the irq responds that camera is ready
+ *
+ *  mode : 0: Wait for camera gets ready
+ *         1: Wait for receiving data
+ *         2: Wait for camera gets busy
+ *
+ * msec: Time to wait
+ */
+static int mdc800_usb_waitForIRQ (int mode, int msec)
+{
+	mdc800->camera_request_ready=1+mode;
+
+	interruptible_sleep_on_timeout (&mdc800->irq_wait, msec*HZ/1000);
+
+	if (mdc800->camera_request_ready>0)
+	{
+		mdc800->camera_request_ready=0;
+		err ("timeout waiting for camera.");
+		return -1;
+	}
+	
+	if (mdc800->state == NOT_CONNECTED)
+	{
+		warn ("Camera gets disconnected during waiting for irq.");
+		mdc800->camera_request_ready=0;
+		return -2;
+	}
+	
+	return 0;
+}
+
+
+/*
+ * The write_urb callback function
+ */
+static void mdc800_usb_write_notify (struct urb *urb)
+{
+	struct mdc800_data* mdc800=urb->context;
+
+	if (urb->status != 0)
+	{
+		err ("writing command fails (status=%i)", urb->status);
+	}
+	else
+	{	
+		mdc800->state=READY;
+	}
+	wake_up_interruptible (&mdc800->write_wait);
+}
+
+
+/*
+ * The download_urb callback function
+ */
+static void mdc800_usb_download_notify (struct urb *urb)
+{
+	struct mdc800_data* mdc800=urb->context;
+
+	if (urb->status == 0)
+	{
+		/* Fill output buffer with these data */
+		memcpy (mdc800->out,  urb->transfer_buffer, 64);
+		mdc800->out_count=64;
+		mdc800->out_ptr=0;
+		mdc800->download_left-=64;
+		if (mdc800->download_left == 0)
+		{
+			mdc800->state=READY;
+		}
+	}
+	else
+	{
+		err ("request bytes fails (status:%i)", urb->status);
+	}
+	wake_up_interruptible (&mdc800->download_wait);
+}
+
+
+/***************************************************************************
+	Probing for the Camera
+ ***************************************************************************/
+
+static struct usb_driver mdc800_usb_driver;
+
+/*
+ * Callback to search the Mustek MDC800 on the USB Bus
+ */
+static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum )
+{
+	int 										i,j;
+	struct usb_interface_descriptor	*intf_desc;
+	int irq_interval=0;
+
+	dbg ("(mdc800_usb_probe) called.");
+
+
+	if (dev->descriptor.idVendor != MDC800_VENDOR_ID)
+		return 0;
+	if (dev->descriptor.idProduct != MDC800_PRODUCT_ID)
+		return 0;
+
+	if (mdc800->dev != 0)
+	{
+		warn ("only one Mustek MDC800 is supported.");
+		return 0;
+	}
+
+	if (dev->descriptor.bNumConfigurations != 1)
+	{
+		err ("probe fails -> wrong Number of Configuration");
+		return 0;
+	}
+	intf_desc=&dev->actconfig->interface[ifnum].altsetting[0];
+
+	if (
+			( intf_desc->bInterfaceClass != 0xff )
+		||	( intf_desc->bInterfaceSubClass != 0 )
+		|| ( intf_desc->bInterfaceProtocol != 0 )
+		|| ( intf_desc->bNumEndpoints != 4)
+	)
+	{
+		err ("probe fails -> wrong Interface");
+		return 0;
+	}
+
+	/* Check the Endpoints */
+	for (i=0; i<4; i++)
+	{
+		mdc800->endpoint[i]=-1;
+		for (j=0; j<4; j++)
+		{
+			if (mdc800_endpoint_equals (&intf_desc->endpoint [j],&mdc800_ed [i]))
+			{
+				mdc800->endpoint[i]=intf_desc->endpoint [j].bEndpointAddress ;
+				if (i==1)
+				{
+					irq_interval=intf_desc->endpoint [j].bInterval;
+				}
+
+				continue;
+			}
+		}
+		if (mdc800->endpoint[i] == -1)
+		{
+			err ("probe fails -> Wrong Endpoints.");
+			return 0;
+		}
+	}
+
+
+	usb_driver_claim_interface (&mdc800_usb_driver, &dev->actconfig->interface[ifnum], mdc800);
+	if (usb_set_interface (dev, ifnum, 0) < 0)
+	{
+		err ("MDC800 Configuration fails.");
+		return 0;
+	}
+
+	info ("Found Mustek MDC800 on USB.");
+
+	mdc800->dev=dev;
+	mdc800->state=READY;
+	mdc800->open=0;
+	mdc800->rw_lock=0;
+
+	/* Setup URB Structs */
+	FILL_INT_URB (
+		mdc800->irq_urb,
+		mdc800->dev,
+		usb_rcvintpipe (mdc800->dev,mdc800->endpoint [1]),
+		mdc800->irq_urb_buffer,
+		8,
+		mdc800_usb_irq,
+		mdc800,
+		irq_interval
+	);
+
+	FILL_BULK_URB (
+		mdc800->write_urb,
+		mdc800->dev,
+		usb_sndbulkpipe (mdc800->dev, mdc800->endpoint[0]),
+		mdc800->write_urb_buffer,
+		8,
+		mdc800_usb_write_notify,
+		mdc800
+	);
+
+	FILL_BULK_URB (
+		mdc800->download_urb,
+		mdc800->dev,
+		usb_rcvbulkpipe (mdc800->dev, mdc800->endpoint [3]),
+		mdc800->download_urb_buffer,
+		64,
+		mdc800_usb_download_notify,
+		mdc800
+	);
+
+	return mdc800;
+}
+
+
+/*
+ * Disconnect USB device (maybe the MDC800)
+ */
+static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr)
+{
+	struct mdc800_data* mdc800=(struct mdc800_data*) ptr;
+
+	dbg ("(mdc800_usb_disconnect) called");
+
+	if (mdc800->state == NOT_CONNECTED)
+		return;
+	
+	mdc800->state=NOT_CONNECTED;
+
+	usb_unlink_urb (mdc800->irq_urb);
+	usb_unlink_urb (mdc800->write_urb);
+	usb_unlink_urb (mdc800->download_urb);
+
+	usb_driver_release_interface (&mdc800_usb_driver, &dev->actconfig->interface[1]);
+
+	mdc800->dev=0;
+	info ("Mustek MDC800 disconnected from USB.");
+}
+
+
+/***************************************************************************
+	The Misc device Part (file_operations)
+****************************************************************************/
+
+/*
+ * This Function calc the Answersize for a command.
+ */
+static int mdc800_getAnswerSize (char command)
+{
+	switch ((unsigned char) command)
+	{
+		case 0x2a:
+		case 0x49:
+		case 0x51:
+		case 0x0d:
+		case 0x20:
+		case 0x07:
+		case 0x01:
+		case 0x25:
+		case 0x00:
+			return 8;
+
+		case 0x05:
+		case 0x3e:
+			return mdc800->pic_len;
+
+		case 0x09:
+			return 4096;
+
+		default:
+			return 0;
+	}
+}
+
+
+/*
+ * Init the device: (1) alloc mem (2) Increase MOD Count ..
+ */
+static int mdc800_device_open (struct inode* inode, struct file *file)
+{
+	int retval=0;
+	
+	if (mdc800->state == NOT_CONNECTED)
+	{
+		return -EBUSY;
+	}
+
+	if (mdc800->open)
+	{
+		return -EBUSY;
+	}
+
+	mdc800->rw_lock=0;
+	mdc800->in_count=0;
+	mdc800->out_count=0;
+	mdc800->out_ptr=0;
+	mdc800->pic_index=0;
+	mdc800->pic_len=-1;
+	mdc800->download_left=0;
+
+	mdc800->camera_busy=0;
+	mdc800->camera_request_ready=0;
+
+	retval=0;
+	if (usb_submit_urb (mdc800->irq_urb))
+	{
+		err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+		return -EIO;
+	}
+
+	mdc800->open=1;
+
+	dbg ("Mustek MDC800 device opened.");
+	return 0;
+}
+
+
+/*
+ * Close the Camera and release Memory
+ */
+static int mdc800_device_release (struct inode* inode, struct file *file)
+{
+	int retval=0;
+	dbg ("Mustek MDC800 device closed.");
+
+	if (mdc800->open && (mdc800->state != NOT_CONNECTED))
+	{
+		mdc800->open=0;
+		usb_unlink_urb (mdc800->irq_urb);
+		usb_unlink_urb (mdc800->write_urb);
+		usb_unlink_urb (mdc800->download_urb);
+	}
+	else
+	{
+		retval=-EIO;
+	}
+
+	return retval;
+}
+
+
+/*
+ * The Device read callback Function
+ */
+static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, loff_t *pos)
+{
+	int   left=len, sts=len; /* single transfer size */
+	char* ptr=buf;
+
+	if (mdc800->state == NOT_CONNECTED)
+		return -EBUSY;
+
+	if (mdc800->state == WORKING)
+	{
+		warn ("Illegal State \"working\" reached during read ?!");
+		return -EBUSY;
+	}
+
+	if (!mdc800->open || mdc800->rw_lock)
+		return -EBUSY;
+	mdc800->rw_lock=1;
+
+	while (left)
+	{
+		if (signal_pending (current)) {
+			mdc800->rw_lock=0;
+			return -EINTR;
+		}
+
+		sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left;
+
+		if (sts <= 0)
+		{
+			/* Too less Data in buffer */
+			if (mdc800->state == DOWNLOAD)
+			{
+				mdc800->out_count=0;
+				mdc800->out_ptr=0;
+
+				/* Download -> Request new bytes */
+				if (usb_submit_urb (mdc800->download_urb))
+				{
+					err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+					mdc800->rw_lock=0;
+					return len-left;
+				}
+				interruptible_sleep_on_timeout (&mdc800->download_wait, TO_DOWNLOAD_GET_READY*HZ/1000);
+				if (mdc800->download_urb->status != 0)
+				{
+					err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
+					mdc800->rw_lock=0;
+					return len-left;
+				}
+			}
+			else
+			{
+				/* No more bytes -> that's an error*/
+				mdc800->rw_lock=0;
+				return -EIO;
+			}
+		}
+		else
+		{
+			/* memcpy Bytes */
+			memcpy (ptr, &mdc800->out [mdc800->out_ptr], sts);
+			ptr+=sts;
+			left-=sts;
+			mdc800->out_ptr+=sts;
+		}
+	}
+
+	mdc800->rw_lock=0;
+	return len-left;
+}
+
+
+/*
+ * The Device write callback Function
+ * If a 8Byte Command is received, it will be send to the camera.
+ * After this the driver initiates the request for the answer or
+ * just waits until the camera becomes ready.
+ */
+static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos)
+{
+	int i=0;
+
+	if (mdc800->state != READY)
+		return -EBUSY;
+
+	if (!mdc800->open || mdc800->rw_lock)
+		return -EBUSY;
+	mdc800->rw_lock=1;
+
+	while (i<len)
+	{
+		if (signal_pending (current)) {
+			mdc800->rw_lock=0;
+			return -EINTR;
+		}
+
+		/* check for command start */
+		if (buf [i] == (char) 0x55)
+		{
+			mdc800->in_count=0;
+			mdc800->out_count=0;
+			mdc800->out_ptr=0;
+			mdc800->download_left=0;
+		}
+
+		/* save command byte */
+		if (mdc800->in_count < 8)
+		{
+			mdc800->in[mdc800->in_count]=buf[i];
+			mdc800->in_count++;
+		}
+		else
+		{
+			err ("Command is to long !\n");
+			mdc800->rw_lock=0;
+			return -EIO;
+		}
+
+		/* Command Buffer full ? -> send it to camera */
+		if (mdc800->in_count == 8)
+		{
+			int answersize;
+
+			if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
+			{
+				err ("Camera didn't get ready.\n");
+				mdc800->rw_lock=0;
+				return -EIO;
+			}
+
+			answersize=mdc800_getAnswerSize (mdc800->in[1]);
+
+			mdc800->state=WORKING;
+			memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
+			if (usb_submit_urb (mdc800->write_urb))
+			{
+				err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+				mdc800->rw_lock=0;
+				return -EIO;
+			}
+			interruptible_sleep_on_timeout (&mdc800->write_wait, TO_WRITE_GET_READY*HZ/1000);
+			if (mdc800->state == WORKING)
+			{
+				usb_unlink_urb (mdc800->write_urb);
+				mdc800->rw_lock=0;
+				return -EIO;
+			}
+
+			switch ((unsigned char) mdc800->in[1])
+			{
+				case 0x05: /* Download Image */
+				case 0x3e: /* Take shot in Fine Mode (WCam Mode) */
+					if (mdc800->pic_len < 0)
+					{
+						err ("call 0x07 before 0x05,0x3e");
+						mdc800->state=READY;
+						mdc800->rw_lock=0;
+						return -EIO;
+					}
+					mdc800->pic_len=-1;
+
+				case 0x09: /* Download Thumbnail */
+					mdc800->download_left=answersize+64;
+					mdc800->state=DOWNLOAD;
+					mdc800_usb_waitForIRQ (0,TO_DOWNLOAD_GET_BUSY);
+					break;
+
+
+				default:
+					if (answersize)
+					{
+
+						if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
+						{
+							err ("requesting answer from irq fails");
+							mdc800->rw_lock=0;
+							return -EIO;
+						}
+
+						/* Write dummy data, (this is ugly but part of the USB Protokoll */
+						/* if you use endpoint 1 as bulk and not as irq */
+						memcpy (mdc800->out, mdc800->camera_response,8);
+
+						/* This is the interpreted answer */
+						memcpy (&mdc800->out[8], mdc800->camera_response,8);
+
+						mdc800->out_ptr=0;
+						mdc800->out_count=16;
+
+						/* Cache the Imagesize, if command was getImageSize */
+						if (mdc800->in [1] == (char) 0x07)
+						{
+							mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2];
+
+							dbg ("cached imagesize = %i",mdc800->pic_len);
+						}
+
+					}
+					else
+					{
+						if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
+						{
+							err ("Command Timeout.");
+							mdc800->rw_lock=0;
+							return -EIO;
+						}
+					}
+					mdc800->state=READY;
+					break;
+			}
+		}
+		i++;
+	}
+	mdc800->rw_lock=0;
+	return i;
+}
+
+
+/***************************************************************************
+	Init and Cleanup this driver (Structs and types)
+****************************************************************************/
+
+/* File Operations of this drivers */
+static struct file_operations mdc800_device_ops =
+{
+	read:		mdc800_device_read,
+	write:		mdc800_device_write,
+	open:		mdc800_device_open,
+	release:	mdc800_device_release,
+};
+
+
+
+/*
+ * USB Driver Struct for this device
+ */
+static struct usb_driver mdc800_usb_driver =
+{
+	"mdc800",
+	mdc800_usb_probe,
+	mdc800_usb_disconnect,
+	{ 0,0 },
+	&mdc800_device_ops,
+	MDC800_DEVICE_MINOR_BASE
+};
+
+
+
+/************************************************************************
+	Init and Cleanup this driver (Main Functions)
+*************************************************************************/
+
+#define try(A)           if ((A) == 0) goto cleanup_on_fail;
+#define try_free_mem(A)  if (A != 0) { kfree (A); A=0; }
+#define try_free_urb(A)  if (A != 0) { usb_free_urb (A); A=0; }
+
+int __init usb_mdc800_init (void)
+{
+	/* Allocate Memory */
+	try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL));
+
+	mdc800->dev=0;
+	mdc800->open=0;
+	mdc800->state=NOT_CONNECTED;
+	memset(mdc800, 0, sizeof(struct mdc800_data));
+
+	init_waitqueue_head (&mdc800->irq_wait);
+	init_waitqueue_head (&mdc800->write_wait);
+	init_waitqueue_head (&mdc800->download_wait);
+
+	try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL));
+	try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL));
+	try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL));
+
+	try (mdc800->irq_urb=usb_alloc_urb (0));
+	try (mdc800->download_urb=usb_alloc_urb (0));
+	try (mdc800->write_urb=usb_alloc_urb (0));
+
+	/* Register the driver */
+	if (usb_register (&mdc800_usb_driver) < 0)
+		goto cleanup_on_fail;
+
+	info ("Mustek Digital Camera Driver " VERSION " (MDC800)");
+	info (RELEASE_DATE " Henning Zabel <henning@uni-paderborn.de>");
+
+	return 0;
+
+	/* Clean driver up, when something fails */
+
+cleanup_on_fail:
+
+	if (mdc800 != 0)
+	{
+		err ("can't alloc memory!");
+
+		try_free_mem (mdc800->download_urb_buffer);
+		try_free_mem (mdc800->write_urb_buffer);
+		try_free_mem (mdc800->irq_urb_buffer);
+
+		try_free_urb (mdc800->write_urb);
+		try_free_urb (mdc800->download_urb);
+		try_free_urb (mdc800->irq_urb);
+
+		kfree (mdc800);
+	}
+	mdc800=0;
+	return -1;
+}
+
+
+void __exit usb_mdc800_cleanup (void)
+{
+	usb_deregister (&mdc800_usb_driver);
+
+	usb_free_urb (mdc800->irq_urb);
+	usb_free_urb (mdc800->download_urb);
+	usb_free_urb (mdc800->write_urb);
+
+	kfree (mdc800->irq_urb_buffer);
+	kfree (mdc800->write_urb_buffer);
+	kfree (mdc800->download_urb_buffer);
+
+	kfree (mdc800);
+	mdc800=0;
+}
+
+
+MODULE_AUTHOR ("Henning Zabel <henning@uni-paderborn.de>");
+MODULE_DESCRIPTION ("USB Driver for Mustek MDC800 Digital Camera");
+
+module_init (usb_mdc800_init);
+module_exit (usb_mdc800_cleanup);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/microtek.c linux.18p8/drivers/usb/microtek.c
--- linux.vanilla/drivers/usb/microtek.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/microtek.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,1055 @@
+/* Driver for Microtek Scanmaker X6 USB scanner, and possibly others.
+ *
+ * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com>
+ * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
+ *
+ * Parts shamelessly stolen from usb-storage and copyright by their
+ * authors. Thanks to Matt Dharm for giving us permission!
+ *
+ * This driver implements a SCSI host controller driver and a USB
+ * device driver. To avoid confusion, all the USB related stuff is
+ * prefixed by mts_usb_ and all the SCSI stuff by mts_scsi_.
+ * 
+ * Microtek (www.microtek.com) did not release the specifications for
+ * their USB protocol to us, so we had to reverse engineer them. We
+ * don't know for which models they are valid.
+ *
+ * The X6 USB has three bulk endpoints, one output (0x1) down which
+ * commands and outgoing data are sent, and two input: 0x82 from which
+ * normal data is read from the scanner (in packets of maximum 32
+ * bytes) and from which the status byte is read, and 0x83 from which
+ * the results of a scan (or preview) are read in up to 64 * 1024 byte
+ * chunks by the Windows driver. We don't know how much it is possible
+ * to read at a time from 0x83.
+ *
+ * It seems possible to read (with URB transfers) everything from 0x82
+ * in one go, without bothering to read in 32 byte chunks.
+ *
+ * There seems to be an optimisation of a further READ implicit if
+ * you simply read from 0x83.
+ *
+ * Guessed protocol:
+ *
+ *	Send raw SCSI command to EP 0x1
+ *
+ *	If there is data to receive:
+ *		If the command was READ datatype=image:
+ *			Read a lot of data from EP 0x83
+ *		Else:
+ *			Read data from EP 0x82
+ *	Else:
+ *		If there is data to transmit:
+ *			Write it to EP 0x1
+ *
+ *	Read status byte from EP 0x82
+ *
+ * References:
+ *
+ * The SCSI command set for the scanner is available from
+ *	ftp://ftp.microtek.com/microtek/devpack/
+ *
+ * Microtek NV sent us a more up to date version of the document. If
+ * you want it, just send mail.
+ *
+ * Status:
+ *
+ *	This driver does not work properly yet.
+ *	Untested with multiple scanners.
+ *	Untested on SMP.
+ *	Untested on UHCI.
+ *
+ * History:
+ *
+ *	20000417 starting history
+ *	20000417 fixed load oops
+ *	20000417 fixed unload oops
+ *	20000419 fixed READ IMAGE detection
+ *	20000424 started conversion to use URBs
+ *	20000502 handled short transfers as errors
+ *	20000513 rename and organisation of functions (john)
+ *	20000513 added IDs for all products supported by Windows driver (john)
+ *	20000514 Rewrote mts_scsi_queuecommand to use URBs (john)
+ *	20000514 Version 0.0.8j
+ *      20000514 Fix reporting of non-existant devices to SCSI layer (john)
+ *	20000514 Added MTS_DEBUG_INT (john)
+ *	20000514 Changed "usb-microtek" to "microtek" for consistency (john)
+ *	20000514 Stupid bug fixes (john)
+ *	20000514 Version 0.0.9j
+ *	20000515 Put transfer context and URB in mts_desc (john)
+ *	20000515 Added prelim turn off debugging support (john)
+ *	20000515 Version 0.0.10j
+ *      20000515 Fixed up URB allocation (clear URB on alloc) (john)
+ *      20000515 Version 0.0.11j
+ *	20000516 Removed unnecessary spinlock in mts_transfer_context (john)
+ *	20000516 Removed unnecessary up on instance lock in mts_remove_nolock (john)
+ *	20000516 Implemented (badly) scsi_abort (john)
+ *	20000516 Version 0.0.12j
+ *      20000517 Hopefully removed mts_remove_nolock quasideadlock (john)
+ *      20000517 Added mts_debug_dump to print ll USB info (john)
+ *	20000518 Tweaks and documentation updates (john)
+ *	20000518 Version 0.0.13j
+ *	20000518 Cleaned up abort handling (john)
+ *	20000523 Removed scsi_command and various scsi_..._resets (john)
+ *	20000523 Added unlink URB on scsi_abort, now OHCI supports it (john)
+ *	20000523 Fixed last tiresome compile warning (john)
+ *	20000523 Version 0.0.14j (though version 0.1 has come out?)
+ *	20000602 Added primitive reset
+ *	20000602 Version 0.2.0
+ *	20000603 various cosmetic changes
+ *	20000603 Version 0.2.1
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/proc_fs.h>
+
+#include <asm/atomic.h>
+#include <linux/blk.h>
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include "../scsi/sd.h"
+
+#include "microtek.h"
+
+/* Constants */
+
+#define MTS_ABORT_TIMEOUT HZ /*jiffies*/
+
+
+/* Should we do debugging? */
+
+#define MTS_DO_DEBUG
+
+
+/* USB layer driver interface */
+
+static void *mts_usb_probe(struct usb_device *dev, unsigned int interface);
+static void mts_usb_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver mts_usb_driver = {
+	"microtek",
+	mts_usb_probe,
+	mts_usb_disconnect,
+	{ NULL, NULL } /* we need no fops. let gcc fill it */
+};
+
+
+/* Internal driver stuff */
+
+#define MTS_VERSION	"0.2.1"
+#define MTS_NAME	"microtek usb (rev " MTS_VERSION "): "
+
+#define MTS_WARNING(x...) \
+	printk( KERN_WARNING MTS_NAME ## x )
+#define MTS_ERROR(x...) \
+	printk( KERN_ERR MTS_NAME ## x )
+#define MTS_INT_ERROR(x...) \
+	MTS_ERROR( ## x )
+#define MTS_MESSAGE(x...) \
+	printk( KERN_INFO MTS_NAME ## x )
+
+#if defined MTS_DO_DEBUG
+
+#define MTS_DEBUG(x...) \
+	printk( KERN_DEBUG MTS_NAME ## x )
+
+#define MTS_DEBUG_GOT_HERE() \
+	MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __PRETTY_FUNCTION__ )
+#define MTS_DEBUG_INT() \
+	do { MTS_DEBUG_GOT_HERE(); \
+	     MTS_DEBUG("transfer = %x context = %x\n",(int)transfer,(int)context ); \
+	     MTS_DEBUG("status = %x data-length = %x sent = %x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+             mts_debug_dump(context->instance);\
+	   } while(0)
+#else
+
+#define MTS_NUL_STATEMENT do { } while(0)
+
+#define MTS_DEBUG(x...)	MTS_NUL_STATEMENT
+#define MTS_DEBUG_GOT_HERE() MTS_NUL_STATEMENT
+#define MTS_DEBUG_INT() MTS_NUL_STATEMENT
+
+#endif
+	
+
+
+#define MTS_INT_INIT()\
+	do {\
+	context = (struct mts_transfer_context*)transfer->context; \
+	if (atomic_read(&context->do_abort)) {\
+		mts_transfer_cleanup(transfer);\
+		return;\
+	}\
+	MTS_DEBUG_INT();\
+	} while (0)
+
+static inline void mts_debug_dump(struct mts_desc* desc) {
+	MTS_DEBUG("desc at 0x%x: halted = %x%x, toggle = %x%x\n",
+		  (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0],
+		  (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0]
+		);
+	MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n",
+		  usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
+		  usb_rcvbulkpipe(desc->usb_dev,desc->ep_response),
+		  usb_rcvbulkpipe(desc->usb_dev,desc->ep_image)
+		);
+}
+
+
+static inline void mts_show_command(Scsi_Cmnd *srb)
+{
+	char *what = NULL;
+
+	switch (srb->cmnd[0]) {
+	case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
+	case REZERO_UNIT: what = "REZERO_UNIT"; break;
+	case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
+	case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
+	case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
+	case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
+	case READ_6: what = "READ_6"; break;
+	case WRITE_6: what = "WRITE_6"; break;
+	case SEEK_6: what = "SEEK_6"; break;
+	case READ_REVERSE: what = "READ_REVERSE"; break;
+	case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
+	case SPACE: what = "SPACE"; break;
+	case INQUIRY: what = "INQUIRY"; break;
+	case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
+	case MODE_SELECT: what = "MODE_SELECT"; break;
+	case RESERVE: what = "RESERVE"; break;
+	case RELEASE: what = "RELEASE"; break;
+	case COPY: what = "COPY"; break;
+	case ERASE: what = "ERASE"; break;
+	case MODE_SENSE: what = "MODE_SENSE"; break;
+	case START_STOP: what = "START_STOP"; break;
+	case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
+	case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
+	case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
+	case SET_WINDOW: what = "SET_WINDOW"; break;
+	case READ_CAPACITY: what = "READ_CAPACITY"; break;
+	case READ_10: what = "READ_10"; break;
+	case WRITE_10: what = "WRITE_10"; break;
+	case SEEK_10: what = "SEEK_10"; break;
+	case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
+	case VERIFY: what = "VERIFY"; break;
+	case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
+	case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
+	case SEARCH_LOW: what = "SEARCH_LOW"; break;
+	case SET_LIMITS: what = "SET_LIMITS"; break;
+	case READ_POSITION: what = "READ_POSITION"; break;
+	case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
+	case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
+	case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
+	case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
+	case COMPARE: what = "COMPARE"; break;
+	case COPY_VERIFY: what = "COPY_VERIFY"; break;
+	case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
+	case READ_BUFFER: what = "READ_BUFFER"; break;
+	case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
+	case READ_LONG: what = "READ_LONG"; break;
+	case WRITE_LONG: what = "WRITE_LONG"; break;
+	case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
+	case WRITE_SAME: what = "WRITE_SAME"; break;
+	case READ_TOC: what = "READ_TOC"; break;
+	case LOG_SELECT: what = "LOG_SELECT"; break;
+	case LOG_SENSE: what = "LOG_SENSE"; break;
+	case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
+	case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
+	case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break;
+	case READ_12: what = "READ_12"; break;
+	case WRITE_12: what = "WRITE_12"; break;
+	case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
+	case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
+	case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
+	case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
+	case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
+	case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
+	case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
+	default:
+		MTS_DEBUG("can't decode command\n");
+		goto out;
+		break;
+	}
+	MTS_DEBUG( "Command %s (%d bytes)\n", what, srb->cmd_len);
+
+ out:
+	MTS_DEBUG( "  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	       srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], 
+	       srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
+}
+
+static inline int mts_is_aborting(struct mts_desc* desc) {
+	return (atomic_read(&desc->context.do_abort));
+}
+
+static inline void mts_request_abort(struct mts_desc* desc) {
+	MTS_DEBUG_GOT_HERE();
+	mts_debug_dump(desc);
+	atomic_set(&desc->context.do_abort,1);
+}
+
+static inline void mts_urb_abort(struct mts_desc* desc) {
+	MTS_DEBUG_GOT_HERE();
+	mts_debug_dump(desc);
+	if ( desc->urb.status == USB_ST_URB_PENDING ) {
+		usb_unlink_urb( &desc->urb );
+	}
+}
+
+static inline void mts_wait_abort(struct mts_desc* desc)
+{
+	mts_request_abort(desc);
+
+	while( !atomic_read(&desc->lock.count) ) {
+/* Is there a function to check if the semaphore is locked? */
+		schedule_timeout( MTS_ABORT_TIMEOUT ); 
+		MTS_DEBUG_GOT_HERE();
+		mts_urb_abort(desc);
+	}
+
+}
+
+
+static struct mts_desc * mts_list; /* list of active scanners */
+struct semaphore mts_list_semaphore;
+
+/* Internal list operations */
+
+static
+void mts_remove_nolock( struct mts_desc* to_remove )
+{
+	MTS_DEBUG( "removing 0x%x from list\n",
+		   (int)to_remove );
+
+	mts_wait_abort(to_remove);
+	
+	down( &to_remove->lock );
+
+	MTS_DEBUG_GOT_HERE();
+	
+	if ( to_remove != mts_list ) {
+		MTS_DEBUG_GOT_HERE();
+		if (to_remove->prev && to_remove->next)
+			to_remove->prev->next = to_remove->next;
+	} else {
+		MTS_DEBUG_GOT_HERE();
+		mts_list = to_remove->next;
+		if (mts_list) {
+			MTS_DEBUG_GOT_HERE();
+			mts_list->prev = 0;
+		}
+	}
+		
+	if ( to_remove->next ) {
+		MTS_DEBUG_GOT_HERE();
+		to_remove->next->prev = to_remove->prev;
+	}
+
+	MTS_DEBUG_GOT_HERE();
+	scsi_unregister_module(MODULE_SCSI_HA, &(to_remove->ctempl));
+	
+	kfree( to_remove );
+}
+
+static
+void mts_add_nolock( struct mts_desc* to_add )
+{
+	MTS_DEBUG( "adding 0x%x to list\n", (int)to_add );
+	
+	to_add->prev = 0;
+	to_add->next = mts_list;
+	if ( mts_list ) {
+		mts_list->prev = to_add;
+	}
+			
+	mts_list = to_add;
+}
+		
+
+
+
+/* SCSI driver interface */
+
+/* scsi related functions - dummies for now mostly */
+
+static int mts_scsi_release(struct Scsi_Host *psh)
+{
+	MTS_DEBUG_GOT_HERE();
+	
+	return 0;
+}
+
+static int mts_scsi_abort (Scsi_Cmnd *srb)
+/* interrupt context (!) */
+{
+	struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
+
+	MTS_DEBUG_GOT_HERE();
+	
+	mts_request_abort(desc);
+	mts_urb_abort(desc);
+	
+	return SCSI_ABORT_PENDING;
+}
+
+static int mts_scsi_host_reset (Scsi_Cmnd *srb)
+{
+	struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
+
+	MTS_DEBUG_GOT_HERE();
+	mts_debug_dump(desc);
+
+	usb_reset_device(desc->usb_dev);
+	return 0;  /* RANT why here 0 and not SUCCESS */
+}
+
+/* the core of the scsi part */
+
+/* faking a detection - which can't fail :-) */
+
+static int mts_scsi_detect (struct SHT * sht)
+{
+	/* Whole function stolen from usb-storage */
+	
+	struct mts_desc * desc = (struct mts_desc *)sht->proc_dir;
+	/* What a hideous hack! */
+	  
+	char local_name[48];
+
+	MTS_DEBUG_GOT_HERE();
+
+	/* set up the name of our subdirectory under /proc/scsi/ */
+	sprintf(local_name, "microtek-%d", desc->host_number);
+	sht->name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
+	/* FIXME: where is this freed ? */
+
+	if (!sht->name) {
+		MTS_ERROR( "unable to allocate memory for proc interface!!\n" );
+		return 0;
+	}
+	
+	strcpy((char *)sht->name, local_name);
+
+ 	sht->proc_dir = NULL;
+
+	/* In host->hostdata we store a pointer to desc */
+	desc->host = scsi_register(sht, sizeof(desc));
+	desc->host->hostdata[0] = (unsigned long)desc;
+/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */ 
+
+	return 1;
+}
+
+
+
+/* Main entrypoint: SCSI commands are dispatched to here */
+
+
+
+static
+int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback );
+
+static void mts_transfer_cleanup( struct urb *transfer );
+
+
+inline static
+void mts_int_submit_urb (struct urb* transfer,
+			int pipe,
+			void* data,
+			unsigned length,
+			mts_usb_urb_callback callback )
+/* Interrupt context! */
+
+/* Holding transfer->context->lock! */
+{
+	int res;
+	struct mts_transfer_context* context;
+	
+	MTS_INT_INIT();
+	
+	FILL_BULK_URB(transfer,
+		      context->instance->usb_dev,
+		      pipe,
+		      data,
+		      length,
+		      callback,
+		      context
+		);
+
+/*	transfer->transfer_flags = USB_DISABLE_SPD;*/
+	transfer->transfer_flags = USB_ASYNC_UNLINK;
+	transfer->status = 0;
+	transfer->timeout = 100;
+
+	res = usb_submit_urb( transfer );
+	if ( res ) {
+		MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
+		context->srb->result = DID_ERROR << 16;
+		context->state = mts_con_error;
+		mts_transfer_cleanup(transfer);
+	}
+	return;
+}
+
+
+static void mts_transfer_cleanup( struct urb *transfer )
+/* Interrupt context! */
+{
+	struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context;
+	
+	up( &context->instance->lock );
+	if ( context->final_callback )
+		context->final_callback(context->srb);
+
+}
+
+static void mts_transfer_done( struct urb *transfer )
+{
+	struct mts_transfer_context* context;
+
+	MTS_INT_INIT();
+
+	context->srb->result &= MTS_MAX_CHUNK_MASK;
+	context->srb->result |= (unsigned)context->status<<1;
+
+	mts_transfer_cleanup(transfer);
+
+	return;
+}
+
+
+static void mts_get_status( struct urb *transfer )
+/* Interrupt context! */
+{
+	struct mts_transfer_context* context;
+
+	MTS_INT_INIT();
+
+	context->state = mts_con_status;
+	
+	mts_int_submit_urb(transfer,
+			   usb_rcvbulkpipe(context->instance->usb_dev,
+					   context->instance->ep_response),
+			   &context->status,
+			   1,
+			   mts_transfer_done );
+	
+	
+	return;
+}
+
+static void mts_data_done( struct urb* transfer )
+/* Interrupt context! */
+{
+	struct mts_transfer_context* context;
+
+	MTS_INT_INIT();
+
+	if ( context->data_length != transfer->actual_length ) {
+#if 0
+		context->srb->resid = context->data_length - transfer->actual_length;
+#else
+		printk(KERN_WARNING "microtek.c: Don't know how to handle resid on 2.2 kernels\n");
+#endif
+	} else if ( transfer->status ) {
+		context->srb->result = DID_ERROR<<16;
+	}
+
+	mts_get_status(transfer);
+
+	return;
+}
+
+
+static void mts_command_done( struct urb *transfer )
+/* Interrupt context! */
+{
+	struct mts_transfer_context* context;
+
+	MTS_INT_INIT();
+
+	if ( transfer->status ) {
+		context->srb->result = DID_ERROR<<16;
+		mts_transfer_cleanup(transfer);
+		
+		return;
+	}
+	
+	if ( context->data ) {
+		context->state = mts_con_data;
+		mts_int_submit_urb(transfer,
+				   context->data_pipe,
+				   context->data,
+				   context->data_length,
+				   mts_data_done);
+	} else mts_get_status(transfer);
+	
+	return;
+}
+
+
+
+	static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 };
+	static const u8 mts_read_image_sig_len = 4;
+	static const unsigned char mts_direction[256/8] = {
+		0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 
+		0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+
+
+#define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1)
+
+static void
+mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc )
+{
+
+	int pipe;
+
+
+	MTS_DEBUG_GOT_HERE();
+
+	desc->context.instance = desc;
+	desc->context.srb = srb;
+	desc->context.state = mts_con_command;
+	atomic_set(&desc->context.do_abort,0);
+	
+	if ( !srb->bufflen ){
+		desc->context.data = 0;
+		desc->context.data_length = 0;
+		return;
+	} else {
+		desc->context.data = srb->buffer;
+		desc->context.data_length = srb->bufflen;
+	}
+	
+	/* can't rely on srb->sc_data_direction */
+
+	/* Brutally ripped from usb-storage */
+
+	if ( !memcmp( srb->cmnd, mts_read_image_sig, mts_read_image_sig_len )
+) { 		pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_image);
+		MTS_DEBUG( "transfering from desc->ep_image == %d\n",
+			   (int)desc->ep_image );
+	} else if ( MTS_DIRECTION_IS_IN(srb->cmnd[0]) ) {
+			pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_response);
+			MTS_DEBUG( "transfering from desc->ep_response == %d\n",
+				   (int)desc->ep_response);
+	} else {
+		MTS_DEBUG("transfering to desc->ep_out == %d\n",
+			  (int)desc->ep_out);
+		pipe = usb_sndbulkpipe(desc->usb_dev,desc->ep_out);
+	}
+	desc->context.data_pipe = pipe;
+}
+
+
+static
+int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
+{
+	struct mts_desc* desc = (struct mts_desc*)(srb->host->hostdata[0]);
+	int err = 0;
+	int res;
+
+	MTS_DEBUG_GOT_HERE();
+	mts_show_command(srb);
+	mts_debug_dump(desc);
+	
+	if ( srb->device->lun || srb->device->id || srb->device->channel ) {
+
+		MTS_DEBUG("Command to LUN=%d ID=%d CHANNEL=%d from SCSI layer\n",(int)srb->device->lun,(int)srb->device->id, (int)srb->device->channel );
+		
+		MTS_DEBUG("this device doesn't exist\n");
+
+		srb->result = DID_BAD_TARGET << 16;
+
+		if(callback)
+			callback(srb);
+
+		goto out;
+	}	
+
+	down(&desc->lock);
+
+	MTS_DEBUG_GOT_HERE();
+	mts_show_command(srb);
+	
+
+	FILL_BULK_URB(&desc->urb,
+		      desc->usb_dev,
+		      usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
+		      srb->cmnd,
+		      srb->cmd_len,
+		      mts_command_done,
+		      &desc->context
+		      );
+	
+		
+	mts_build_transfer_context( srb, desc );
+	desc->context.final_callback = callback;
+	desc->urb.timeout = 100;
+	desc->urb.transfer_flags = USB_ASYNC_UNLINK;
+	
+/*	desc->urb.transfer_flags = USB_DISABLE_SPD;*/
+
+	res=usb_submit_urb(&desc->urb);
+	
+	if(res){
+		MTS_ERROR("error %d submitting URB\n",(int)res);
+		srb->result = DID_ERROR << 16;
+
+		if(callback)
+			callback(srb);
+
+		goto out;
+	}	
+	
+	MTS_DEBUG_GOT_HERE();
+
+ out:
+	return err;
+}
+/*
+ * this defines our 'host'
+ */
+
+/* NOTE: This is taken from usb-storage, should be right. */
+
+
+static Scsi_Host_Template mts_scsi_host_template = {
+	name:           "microtek",
+	detect:		mts_scsi_detect,
+	release:	mts_scsi_release,
+	command:	0,
+	queuecommand:	mts_scsi_queuecommand,
+
+	eh_abort_handler:	mts_scsi_abort,
+	eh_device_reset_handler:0,
+	eh_bus_reset_handler:	0,
+	eh_host_reset_handler:	mts_scsi_host_reset,
+
+	can_queue:		1,
+	this_id:		-1,
+	cmd_per_lun:		1,
+	present:		0,
+	unchecked_isa_dma:	FALSE,
+	use_clustering:		FALSE,
+	use_new_eh_code:	TRUE,
+	emulated:		TRUE
+};
+
+
+/* USB layer driver interface implementation */
+
+static void mts_usb_disconnect (struct usb_device *dev, void *ptr)
+{
+	struct mts_desc* to_remove = (struct mts_desc*)ptr;
+	
+	MTS_DEBUG_GOT_HERE();
+
+	/* leave the list - lock it */
+	down(&mts_list_semaphore);
+
+	mts_remove_nolock(to_remove);
+
+	up(&mts_list_semaphore);
+}
+
+struct vendor_product
+{
+	u16 idVendor;
+	u16 idProduct;
+	char* name;
+	enum
+	{
+		mts_sup_unknown=0,
+		mts_sup_alpha,
+		mts_sup_full
+	}
+	support_status;
+} ;
+
+
+/* These are taken from the msmUSB.inf file on the Windows driver CD */
+const static struct vendor_product mts_supported_products[] =
+{
+	{
+		0x4ce, 0x300,"Phantom 336CX",mts_sup_unknown
+	},
+	{
+		0x5da, 0x94,"Phantom 336CX",mts_sup_unknown
+	},
+	{
+		0x5da, 0x99,"Scanmaker X6",mts_sup_alpha
+	},
+	{
+		0x5da, 0x9a,"Phantom C6",mts_sup_unknown
+	},
+	{
+		0x5da, 0xa0,"Phantom 336CX",mts_sup_unknown
+	},
+	{
+		0x5da, 0xa3,"ScanMaker V6USL",mts_sup_unknown
+	},
+	{
+		0x5da, 0x80a3,"ScanMaker V6USL",mts_sup_unknown
+	},
+	{
+		0x5da, 0x80ac,"Scanmaker V6UL",mts_sup_unknown
+	}
+}
+;
+const static struct vendor_product* mts_last_product = &mts_supported_products[ sizeof(mts_supported_products) / sizeof(struct vendor_product) ];
+		/* Must never be derefed, points to one after last entry */
+
+
+static void * mts_usb_probe (struct usb_device *dev, unsigned int interface)
+{
+	int i;
+	int result;
+	int ep_out = -1;
+	int ep_in_set[3]; /* this will break if we have more than three endpoints
+			   which is why we check */
+	int *ep_in_current = ep_in_set;
+	
+	struct mts_desc * new_desc;
+	struct vendor_product const* p;
+
+	/* the altsettting 0 on the interface we're probing */
+	struct usb_interface_descriptor *altsetting;
+
+	MTS_DEBUG_GOT_HERE();
+	MTS_DEBUG( "usb-device descriptor at %x\n", (int)dev );
+	
+	MTS_DEBUG( "product id = 0x%x, vendor id = 0x%x\n",
+		   (int)dev->descriptor.idProduct,
+		   (int)dev->descriptor.idVendor );
+
+	MTS_DEBUG_GOT_HERE();
+	
+	/* checking IDs */
+	for( p = mts_supported_products; p != mts_last_product; p++ )
+		if ( dev->descriptor.idVendor == p->idVendor &&
+		     dev->descriptor.idProduct == p->idProduct )
+			goto is_supported;
+		else
+			MTS_DEBUG( "doesn't appear to be model %s\n", p->name );
+
+	MTS_DEBUG( "returning NULL: unsupported\n" );
+	
+	return NULL;
+	
+ is_supported:
+
+	MTS_DEBUG_GOT_HERE();
+
+	MTS_DEBUG( "found model %s\n", p->name );
+	if ( p->support_status != mts_sup_full )
+		MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n",
+			     p->name );
+	
+	/* the altsettting 0 on the interface we're probing */
+	altsetting =
+		&(dev->actconfig->interface[interface].altsetting[0]);	
+
+	
+	/* Check if the config is sane */
+
+	if ( altsetting->bNumEndpoints != MTS_EP_TOTAL ) {
+		MTS_WARNING( "expecting %d got %d endpoints! Bailing out.\n",
+			     (int)MTS_EP_TOTAL, (int)altsetting->bNumEndpoints );
+		return NULL;
+	}
+
+	for( i = 0; i < altsetting->bNumEndpoints; i++ ) {
+		if ((altsetting->endpoint[i].bmAttributes & 
+		     USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {
+			
+			MTS_WARNING( "can only deal with bulk endpoints; endpoint %d is not bulk.\n",
+			     (int)altsetting->endpoint[i].bEndpointAddress );
+		} else {
+			if (altsetting->endpoint[i].bEndpointAddress & 
+			    USB_DIR_IN)
+				*ep_in_current++
+					= altsetting->endpoint[i].bEndpointAddress &
+					USB_ENDPOINT_NUMBER_MASK;
+			else {
+				if ( ep_out != -1 ) {
+					MTS_WARNING( "can only deal with one output endpoints. Bailing out." );
+					return NULL;
+				}
+		
+				ep_out = altsetting->endpoint[i].bEndpointAddress &
+					USB_ENDPOINT_NUMBER_MASK;
+			}
+		}
+		
+	}
+	
+
+	if ( ep_out == -1 ) {
+		MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
+		return NULL;
+	}
+	
+	
+	/* I don't understand the following fully (it's from usb-storage) -- John */
+
+	/* set the interface -- STALL is an acceptable response here */
+	result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
+	
+	MTS_DEBUG("usb_set_interface returned %d.\n",result);
+	switch( result )
+	{
+	case 0: /* no error */
+		break;
+		
+	case -EPIPE:
+		usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
+		MTS_DEBUG( "clearing clearing stall on control interface\n" );
+		break;
+		
+	default:
+		MTS_DEBUG( "unknown error %d from usb_set_interface\n",
+			(int)result );
+ 		return NULL;
+	}
+	
+	
+	/* allocating a new descriptor */
+	new_desc = (struct mts_desc *)kmalloc(sizeof(struct mts_desc), GFP_KERNEL);
+	if (new_desc == NULL)
+	{
+		MTS_ERROR("couldn't allocate scanner desc, bailing out!\n");
+		return NULL;
+	}
+
+	/* As done by usb_alloc_urb */
+	memset( new_desc, 0, sizeof(*new_desc) );
+	spin_lock_init(&new_desc->urb.lock);
+	
+		
+	/* initialising that descriptor */
+	new_desc->usb_dev = dev;
+	new_desc->interface = interface;
+
+	init_MUTEX(&new_desc->lock);
+
+	if(mts_list){
+		new_desc->host_number = mts_list->host_number+1;
+	} else {
+		new_desc->host_number = 0;
+	}
+	
+	/* endpoints */
+	
+	new_desc->ep_out = ep_out;
+	new_desc->ep_response = ep_in_set[0];
+	new_desc->ep_image = ep_in_set[1];
+	
+
+	if ( new_desc->ep_out != MTS_EP_OUT )
+		MTS_WARNING( "will this work? Command EP is not usually %d\n",
+			     (int)new_desc->ep_out );
+
+	if ( new_desc->ep_response != MTS_EP_RESPONSE )
+		MTS_WARNING( "will this work? Response EP is not usually %d\n",
+			     (int)new_desc->ep_response );
+
+	if ( new_desc->ep_image != MTS_EP_IMAGE )
+		MTS_WARNING( "will this work? Image data EP is not usually %d\n",
+			     (int)new_desc->ep_image );
+
+	
+	/* Initialize the host template based on the default one */
+	memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template)); 	
+	/* HACK from usb-storage - this is needed for scsi detection */
+	(struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */
+	
+	MTS_DEBUG("registering SCSI module\n");
+	
+	new_desc->ctempl.module = THIS_MODULE;
+	result = scsi_register_module(MODULE_SCSI_HA, &(new_desc->ctempl));	
+	/* Will get hit back in microtek_detect by this func */
+	if ( result )
+	{
+		MTS_ERROR( "error %d from scsi_register_module! Help!\n",
+			   (int)result );
+
+		/* FIXME: need more cleanup? */
+		kfree( new_desc );
+		return NULL;
+	}
+	MTS_DEBUG_GOT_HERE();
+
+	/* FIXME: the bomb is armed, must the host be registered under lock ? */
+	/* join the list - lock it */
+	down(&mts_list_semaphore);
+
+	mts_add_nolock( new_desc );
+	
+	up(&mts_list_semaphore);
+	
+	
+	MTS_DEBUG("completed probe and exiting happily\n");
+	
+	return (void *)new_desc;
+}
+
+
+
+/* get us noticed by the rest of the kernel */
+
+int __init microtek_drv_init(void)
+{
+	int result;
+	
+	MTS_DEBUG_GOT_HERE();
+	init_MUTEX(&mts_list_semaphore);
+
+	if ((result = usb_register(&mts_usb_driver)) < 0) {
+		MTS_DEBUG("usb_register returned %d\n", result );
+		return -1;
+	} else {
+		MTS_DEBUG("driver registered.\n");
+	}
+	
+	return 0;
+}
+
+void __exit microtek_drv_exit(void)
+{
+	struct mts_desc* next;
+	
+	MTS_DEBUG_GOT_HERE();
+
+	usb_deregister(&mts_usb_driver);
+
+	down(&mts_list_semaphore);
+
+	while (mts_list) {
+		/* keep track of where the next one is */
+		next = mts_list->next;
+
+		mts_remove_nolock( mts_list );
+
+		/* advance the list pointer */
+		mts_list = next;
+	}
+	
+	up(&mts_list_semaphore);
+}
+
+module_init(microtek_drv_init);
+module_exit(microtek_drv_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/microtek.h linux.18p8/drivers/usb/microtek.h
--- linux.vanilla/drivers/usb/microtek.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/microtek.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,73 @@
+ /*
+ * Driver for Microtek Scanmaker X6 USB scanner and possibly others.
+ * 
+ * (C) Copyright 2000 John Fremlin <vii@penguinpowered.com>
+ * (C) Copyright 2000 Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
+ *
+ * See microtek.c for history
+ *
+ */
+
+typedef void (*mts_scsi_cmnd_callback)(Scsi_Cmnd *);
+typedef void (*mts_usb_urb_callback) (struct urb *);
+
+
+struct mts_transfer_context
+{
+	struct mts_desc* instance;
+	mts_scsi_cmnd_callback final_callback;
+	Scsi_Cmnd *srb;
+	
+	void* data;
+	unsigned data_length;
+	int data_pipe;
+
+	enum {
+		mts_con_none,
+		mts_con_command,
+		mts_con_data,
+		mts_con_status,
+		mts_con_error,
+		mts_con_done
+	}
+	state;
+
+	atomic_t do_abort; /* when != 0 URB completion routines will
+			      return straightaway */
+	
+	u8 status; /* status returned from ep_response after command completion */
+};
+
+
+struct mts_desc {
+	struct mts_desc *next;
+	struct mts_desc *prev;
+
+	struct usb_device *usb_dev;
+	
+	int interface;
+
+	/* Endpoint addresses */
+	u8 ep_out;
+	u8 ep_response;
+	u8 ep_image;
+	
+	struct Scsi_Host * host;
+	Scsi_Host_Template ctempl;
+	int host_number;
+	
+	struct semaphore lock;
+
+	struct urb urb;
+	struct mts_transfer_context context;
+};
+
+
+#define MTS_EP_OUT	0x1
+#define MTS_EP_RESPONSE	0x2
+#define MTS_EP_IMAGE	0x3
+#define MTS_EP_TOTAL	0x3
+
+#define MTS_MAX_CHUNK_MASK ~0x3fu 
+/*maximum amount the scanner will transmit at once */ 
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/mkmap linux.18p8/drivers/usb/mkmap
--- linux.vanilla/drivers/usb/mkmap	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/mkmap	Thu Jan  1 01:00:00 1970
@@ -1,83 +0,0 @@
-#!/usr/bin/perl
-
-($ME = $0) =~ s|.*/||;
-
-$file = "maps/serial.map";
-$line = 1;
-open(PC, $file) || die("$!");
-while(<PC>)
-{
-    if(/^\s*keycode\s+(\d+)\s*=\s*(\S+)/)
-    {
-	my($idx) = int($1);
-	my($sym) = $2;
-	if(defined($map{uc($sym)}))
-	{
-	    # print STDERR "$file:$line: warning: `$sym' redefined\n";
-	}
-	$map{uc($sym)} = $idx;
-    }
-    $line++;
-}
-close(PC);
-
-$file = "maps/fixup.map";
-$line = 1;
-open(FIXUP, $file) || die("$!");
-while(<FIXUP>)
-{
-    if(/^\s*keycode\s+(\d+)\s*=\s*/)
-    {
-	my($idx) = int($1);
-	for $sym (split(/\s+/, $'))
-        {
-	    $map{uc($sym)} = $idx;
-	}
-    }
-    $line++;
-}
-close(FIXUP);
-
-$file = "maps/usb.map";
-$line = 1;
-open(USB, $file) || die("$!");
-while(<USB>)
-{
-    if(/^\s*keycode\s+(\d+)\s*=\s*/)
-    {
-	my($idx) = int($1);
-	for $sym (split(/\s+/, $'))
-        {
-	    my($val) = $map{uc($sym)};
-	    $map[$idx] = $val;
-	    if(!defined($val))
-	    {
-		print STDERR "$file:$line: warning: `$sym' undefined\n";
-	    }
-	    else
-	    {
-		last;
-	    }
-	}
-    }
-    $line++;
-}
-close(USB);
-
-print "unsigned char usb_kbd_map[256] = \n{\n";
-for($x = 0; $x < 32; $x++)
-{
-    if($x && !($x % 2))
-    {
-	print "\n";
-    }
-    print "  ";
-    for($y = 0; $y < 8; $y++)
-    {
-	my($idx) = $x * 8 + $y;
-	print sprintf("  0x%02x,",
-		      int(defined($map[$idx]) ? $map[$idx]:0));
-    }
-    print "\n";
-}
-print "};\n";
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/mouse.c linux.18p8/drivers/usb/mouse.c
--- linux.vanilla/drivers/usb/mouse.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/mouse.c	Thu Jan  1 01:00:00 1970
@@ -1,293 +0,0 @@
-/*
- * USB HID boot protocol mouse support based on MS BusMouse driver, psaux 
- * driver, and Linus's skeleton USB mouse driver. Fixed up a lot by Linus.
- *
- * Brad Keryan 4/3/1999
- *
- * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it
- * correctly. Events are added together, not queued, to keep the rodent sober.
- *
- * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events.
- * This is wrong: when an application (like X or gpm) reads the mouse device,
- * it wants to find out the mouse's current position, not its recent history.
- * The button thing turned out to be UHCI not flipping data toggle, so half the
- * packets were thrown out.
- *
- * version 0.01: Switched over to busmouse protocol, and changed the minor
- * number to 32 (same as uusbd's hidbp driver). Buttons work more sanely now, 
- * but it still doesn't generate button events unless you move the mouse.
- *
- * version 0.0: Driver emulates a PS/2 mouse, stealing /dev/psaux (sorry, I 
- * know that's not very nice). Moving in the X and Y axes works. Buttons don't
- * work right yet: X sees a lot of MotionNotify/ButtonPress/ButtonRelease 
- * combos when you hold down a button and drag the mouse around. Probably has 
- * some additional bugs on an SMP machine.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/malloc.h>
-
-#include <asm/spinlock.h>
-
-#include "usb.h"
-
-#define USB_MOUSE_MINOR 32
-
-struct mouse_state {
-	unsigned char buttons; /* current button state */
-	long dx; /* dx, dy, dz are change since last read */
-	long dy; 
-	long dz;
-	int present; /* this mouse is plugged in */
-	int active; /* someone is has this mouse's device open */
-	int ready; /* the mouse has changed state since the last read */
-	struct wait_queue *wait; /* for polling */
-	struct fasync_struct *fasync;
-	/* later, add a list here to support multiple mice */
-	/* but we will also need a list of file pointers to identify it */
-};
-
-static struct mouse_state static_mouse_state;
-
-spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
-
-static int mouse_irq(int state, void *__buffer, void *dev_id)
-{
-	signed char *data = __buffer;
-	/* finding the mouse is easy when there's only one */
-	struct mouse_state *mouse = &static_mouse_state; 
-
-	/* if a mouse moves with no one listening, do we care? no */
-	if(!mouse->active)
-		return 1;
-
-	/* if the USB mouse sends an interrupt, then something noteworthy
-	   must have happened */
-	mouse->buttons = data[0] & 0x07;
-	mouse->dx += data[1]; /* data[] is signed, so this works */
-	mouse->dy -= data[2]; /* y-axis is reversed */
-	mouse->dz += data[3];
-	mouse->ready = 1;
-
-	add_mouse_randomness((mouse->buttons << 24) + (mouse->dz << 16 ) + 
-				     (mouse->dy << 8) + mouse->dx);
-
-	wake_up_interruptible(&mouse->wait);
-	if (mouse->fasync)
-		kill_fasync(mouse->fasync, SIGIO);
-
-	return 1;
-}
-
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
-	int retval;
-	struct mouse_state *mouse = &static_mouse_state;
-
-	retval = fasync_helper(fd, filp, on, &mouse->fasync);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
-
-static int release_mouse(struct inode * inode, struct file * file)
-{
-	struct mouse_state *mouse = &static_mouse_state;
-
-	fasync_mouse(-1, file, 0);
-	if (--mouse->active)
-		return 0;
-	return 0;
-}
-
-static int open_mouse(struct inode * inode, struct file * file)
-{
-	struct mouse_state *mouse = &static_mouse_state;
-
-	if (!mouse->present)
-		return -EINVAL;
-	if (mouse->active++)
-		return 0;
-	/* flush state */
-	mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0;
-	return 0;
-}
-
-static ssize_t write_mouse(struct file * file,
-       const char * buffer, size_t count, loff_t *ppos)
-{
-	return -EINVAL;
-}
-
-/*
- * Look like a PS/2 mouse, please..
- *
- * The PS/2 protocol is fairly strange, but
- * oh, well, it's at least common..
- */
-static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_t *ppos)
-{
-	int retval = 0;
-	static int state = 0;
-	struct mouse_state *mouse = &static_mouse_state;
-
-	if (count) {
-		mouse->ready = 0;
-		switch (state) {
-		case 0: { /* buttons and sign */
-			int buttons = mouse->buttons;
-			mouse->buttons = 0;
-			if (mouse->dx < 0)
-				buttons |= 0x10;
-			if (mouse->dy < 0)
-				buttons |= 0x20;
-			put_user(buttons, buffer);
-			buffer++;
-			retval++;
-			state = 1;
-			if (!--count)
-				break;
-		}
-		case 1: { /* dx */
-			int dx = mouse->dx;
-			mouse->dx = 0;
-			put_user(dx, buffer);
-			buffer++;
-			retval++;
-			state = 2;
-			if (!--count)
-				break;
-		}
-		case 2:	{ /* dy */
-			int dy = mouse->dy;
-			mouse->dy = 0;
-			put_user(dy, buffer);
-			buffer++;
-			retval++;
-			state = 0;
-		}
-		break;
-		}
-	}
-	return retval;
-}
-
-static unsigned int mouse_poll(struct file *file, poll_table * wait)
-{
-	struct mouse_state *mouse = &static_mouse_state;
-
-	poll_wait(file, &mouse->wait, wait);
-	if (mouse->ready)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-struct file_operations usb_mouse_fops = {
-	NULL,		/* mouse_seek */
-	read_mouse,
-	write_mouse,
-	NULL, 		/* mouse_readdir */
-	mouse_poll, 	/* mouse_poll */
-	NULL, 		/* mouse_ioctl */
-	NULL,		/* mouse_mmap */
-	open_mouse,
-	NULL,		/* flush */
-	release_mouse,
-	NULL,
-	fasync_mouse,
-};
-
-static struct miscdevice usb_mouse = {
-	USB_MOUSE_MINOR, "USB mouse", &usb_mouse_fops
-};
-
-static int mouse_probe(struct usb_device *dev)
-{
-	struct usb_interface_descriptor *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct mouse_state *mouse = &static_mouse_state;
-
-	/* We don't handle multi-config mice */
-	if (dev->descriptor.bNumConfigurations != 1)
-		return -1;
-
-	/* We don't handle multi-interface mice */
-	if (dev->config[0].bNumInterfaces != 1)
-		return -1;
-
-	/* Is it a mouse interface? */
-	interface = &dev->config[0].interface[0];
-	if (interface->bInterfaceClass != 3)
-		return -1;
-	if (interface->bInterfaceSubClass != 1)
-		return -1;
-	if (interface->bInterfaceProtocol != 2)
-		return -1;
-
-	/* Multiple endpoints? What kind of mutant ninja-mouse is this? */
-	if (interface->bNumEndpoints != 1)
-		return -1;
-
-	endpoint = &interface->endpoint[0];
-
-	/* Output endpoint? Curiousier and curiousier.. */
-	if (!(endpoint->bEndpointAddress & 0x80))
-		return -1;
-
-	/* If it's not an interrupt endpoint, we'd better punt! */
-	if ((endpoint->bmAttributes & 3) != 3)
-		return -1;
-
-	printk("USB mouse found\n");
-
-	usb_set_configuration(dev, dev->config[0].bConfigurationValue);
-
-	usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), mouse_irq, endpoint->bInterval, NULL);
-
-	mouse->present = 1;
-	return 0;
-}
-
-static void mouse_disconnect(struct usb_device *dev)
-{
-	struct mouse_state *mouse = &static_mouse_state;
-
-	/* this might need work */
-	mouse->present = 0;
-}
-
-static struct usb_driver mouse_driver = {
-	"mouse",
-	mouse_probe,
-	mouse_disconnect,
-	{ NULL, NULL }
-};
-
-int usb_mouse_init(void)
-{
-	struct mouse_state *mouse = &static_mouse_state;
-
-	misc_register(&usb_mouse);
-
-	mouse->present = mouse->active = 0;
-	mouse->wait = NULL;
-	mouse->fasync = NULL;
-
-	usb_register(&mouse_driver);
-	printk(KERN_INFO "USB HID boot protocol mouse registered.\n");
-	return 0;
-}
-
-void usb_mouse_cleanup(void)
-{
-	/* this, too, probably needs work */
-	usb_deregister(&mouse_driver);
-	misc_deregister(&usb_mouse);
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/mousedev.c linux.18p8/drivers/usb/mousedev.c
--- linux.vanilla/drivers/usb/mousedev.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/mousedev.c	Fri Sep  1 14:42:09 2000
@@ -0,0 +1,468 @@
+/*
+ * $Id: mousedev.c,v 1.8 2000/05/28 17:31:36 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Input driver to PS/2 or ImPS/2 device driver module.
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#define MOUSEDEV_MINOR_BASE 	32
+#define MOUSEDEV_MINORS		32
+#define MOUSEDEV_MIX		31
+
+#include <linux/malloc.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/config.h>
+#include <linux/kcomp.h>
+
+#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
+#define CONFIG_INPUT_MOUSEDEV_SCREEN_X	1024
+#endif
+#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
+#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y	768
+#endif
+
+struct mousedev {
+	int used;
+	int open;
+	int minor;
+	wait_queue_head_t wait;
+	struct mousedev_list *list;
+	struct input_handle handle;
+	devfs_handle_t devfs;
+};
+
+struct mousedev_list {
+	struct fasync_struct *fasync;
+	struct mousedev *mousedev;
+	struct mousedev_list *next;
+	int dx, dy, dz, oldx, oldy;
+	char ps2[6];
+	unsigned long buttons;
+	unsigned char ready, buffer, bufsiz;
+	unsigned char mode, genseq, impseq;
+};
+
+#define MOUSEDEV_GENIUS_LEN	5
+#define MOUSEDEV_IMPS_LEN	6
+
+static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 };
+static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
+
+static struct input_handler mousedev_handler;
+
+static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
+static struct mousedev mousedev_mix;
+
+static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+{
+	struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
+	struct mousedev **mousedev = mousedevs;
+	struct mousedev_list *list;
+	int index, size;
+
+	while (*mousedev) {
+		list = (*mousedev)->list;
+		while (list) {
+			switch (type) {
+				case EV_ABS:
+					switch (code) {
+						case ABS_X:	
+							size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
+							list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size;
+							list->oldx += list->dx * size;
+							break;
+						case ABS_Y:
+							size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
+							list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size;
+							list->oldy -= list->dy * size;
+							break;
+					}
+					break;
+				case EV_REL:
+					switch (code) {
+						case REL_X:	list->dx += value; break;
+						case REL_Y:	list->dy -= value; break;
+						case REL_WHEEL:	if (list->mode) list->dz -= value; break;
+					}
+					break;
+
+				case EV_KEY:
+					switch (code) {
+						case BTN_0:
+						case BTN_TOUCH:
+						case BTN_LEFT:   index = 0; break;
+						case BTN_4:
+						case BTN_EXTRA:  if (list->mode > 1) { index = 4; break; }
+						case BTN_STYLUS:
+						case BTN_1:
+						case BTN_RIGHT:  index = 1; break;
+						case BTN_3:
+						case BTN_SIDE:   if (list->mode > 1) { index = 3; break; }
+						case BTN_2:
+						case BTN_STYLUS2:
+						case BTN_MIDDLE: index = 2; break;	
+						default: return;
+					}
+					switch (value) {
+						case 0: clear_bit(index, &list->buttons); break;
+						case 1: set_bit(index, &list->buttons); break;
+						case 2: return;
+					}
+					break;
+			}
+					
+			list->ready = 1;
+
+			kill_fasync(list->fasync, SIGIO);
+
+			list = list->next;
+		}
+
+		wake_up_interruptible(&((*mousedev)->wait));
+		mousedev++;
+	}
+}
+
+static int mousedev_fasync(int fd, struct file *file, int on)
+{
+	int retval;
+	struct mousedev_list *list = file->private_data;
+	retval = fasync_helper(fd, file, on, &list->fasync);
+	return retval < 0 ? retval : 0;
+}
+
+static int mousedev_release(struct inode * inode, struct file * file)
+{
+	struct mousedev_list *list = file->private_data;
+	struct mousedev_list **listptr = &list->mousedev->list;
+
+	mousedev_fasync(-1, file, 0);
+
+	while (*listptr && (*listptr != list))
+		listptr = &((*listptr)->next);
+	*listptr = (*listptr)->next;
+
+	if (!--list->mousedev->open) {
+		if (list->mousedev->minor == MOUSEDEV_MIX) {
+			struct input_handle *handle = mousedev_handler.handle;
+			while (handle) {
+				struct mousedev *mousedev = handle->private;
+				if (!mousedev->open)
+					input_close_device(handle);
+				handle = handle->hnext;
+			}
+		} else {
+			if (!mousedev_mix.open)	
+				input_close_device(&list->mousedev->handle);
+		}
+	}
+	
+	if (!--list->mousedev->used) {
+		input_unregister_minor(list->mousedev->devfs);
+		mousedev_table[list->mousedev->minor] = NULL;
+		kfree(list->mousedev);
+	}
+
+	kfree(list);
+
+	return 0;
+}
+
+static int mousedev_open(struct inode * inode, struct file * file)
+{
+	struct mousedev_list *list;
+	int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
+
+	if (i > MOUSEDEV_MINORS || !mousedev_table[i])
+		return -ENODEV;
+
+	if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
+		return -ENOMEM;
+	memset(list, 0, sizeof(struct mousedev_list));
+
+	list->mousedev = mousedev_table[i];
+	list->next = mousedev_table[i]->list;
+	mousedev_table[i]->list = list;
+	file->private_data = list;
+
+	list->mousedev->used++;
+
+	if (!list->mousedev->open++) {
+		if (list->mousedev->minor == MOUSEDEV_MIX) {
+			struct input_handle *handle = mousedev_handler.handle;
+			while (handle) {
+				struct mousedev *mousedev = handle->private;
+				if (!mousedev->open)
+					input_open_device(handle);
+				handle = handle->hnext;
+			}
+		} else {
+			if (!mousedev_mix.open)	
+				input_open_device(&list->mousedev->handle);
+		}
+	}
+
+	return 0;
+}
+
+static void mousedev_packet(struct mousedev_list *list, unsigned char off)
+{
+	list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07);
+	list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx));
+	list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
+	list->dx -= list->ps2[off + 1];
+	list->dy -= list->ps2[off + 2];
+	list->bufsiz = off + 3;
+
+	if (list->mode > 1)
+		list->ps2[off] |= ((list->buttons & 0x30) << 2);
+	
+	if (list->mode) {
+		list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
+		list->bufsiz++;
+		list->dz -= list->ps2[off + 3];
+	}
+	if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0;
+	list->buffer = list->bufsiz;
+}
+
+
+static ssize_t mousedev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
+{
+	struct mousedev_list *list = file->private_data;
+	unsigned char c;
+	int i;
+
+	for (i = 0; i < count; i++) {
+
+		c = buffer[i];
+
+		if (c == mousedev_genius_seq[list->genseq]) {
+			if (++list->genseq == MOUSEDEV_GENIUS_LEN) {
+				list->genseq = 0;
+				list->ready = 1;
+				list->mode = 2;
+			}
+		} else list->genseq = 0;
+
+		if (c == mousedev_imps_seq[list->impseq]) {
+			if (++list->impseq == MOUSEDEV_IMPS_LEN) {
+				list->impseq = 0;
+				list->ready = 1;
+				list->mode = 1;
+			}
+		} else list->impseq = 0;
+
+		list->ps2[0] = 0xfa;
+		list->bufsiz = 1;
+
+		switch (c) {
+
+			case 0xeb: /* Poll */
+				mousedev_packet(list, 1);
+				break;
+
+			case 0xf2: /* Get ID */
+				list->ps2[1] = (list->mode == 1) ? 3 : 0;
+				list->bufsiz = 2;
+				break;
+
+			case 0xe9: /* Get info */
+				if (list->mode == 2) {
+					list->ps2[1] = 0x00; list->ps2[2] = 0x33; list->ps2[3] = 0x55;
+				} else {
+					list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
+				}
+				list->bufsiz = 4;
+				break;
+		}
+
+		list->buffer = list->bufsiz;
+	}
+
+	kill_fasync(list->fasync, SIGIO);
+
+	wake_up_interruptible(&list->mousedev->wait);
+		
+	return count;
+}
+
+static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct mousedev_list *list = file->private_data;
+	int retval = 0;
+
+	if (!list->ready && !list->buffer) {
+
+		add_wait_queue(&list->mousedev->wait, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+
+		while (!list->ready) {
+
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+
+			schedule();
+		}
+
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&list->mousedev->wait, &wait);
+	}
+
+	if (retval)
+		return retval;
+
+	if (!list->buffer)
+		mousedev_packet(list, 0);
+
+	if (count > list->buffer)
+		count = list->buffer;
+
+	if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer, count))
+		return -EFAULT;
+	
+	list->buffer -= count;
+
+	return count;	
+}
+
+/* No kernel lock - fine */
+static unsigned int mousedev_poll(struct file *file, poll_table *wait)
+{
+	struct mousedev_list *list = file->private_data;
+	poll_wait(file, &list->mousedev->wait, wait);
+	if (list->ready || list->buffer)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+struct file_operations mousedev_fops = {
+	read:		mousedev_read,
+	write:		mousedev_write,
+	poll:		mousedev_poll,
+	open:		mousedev_open,
+	release:	mousedev_release,
+	fasync:		mousedev_fasync,
+};
+
+static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev)
+{
+	struct mousedev *mousedev;
+	int minor = 0;
+
+	if (!test_bit(EV_KEY, dev->evbit) ||
+	   (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit)))
+		return NULL;
+
+	if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) &&
+	    (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit)))
+		return NULL;
+
+	for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
+	if (mousedev_table[minor]) {
+		printk(KERN_ERR "mousedev: no more free mousedev devices\n");
+		return NULL;
+	}
+
+	if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
+		return NULL;
+	memset(mousedev, 0, sizeof(struct mousedev));
+	init_waitqueue_head(&mousedev->wait);
+
+	mousedev->used = 1;
+	mousedev->minor = minor;
+	mousedev_table[minor] = mousedev;
+
+	mousedev->handle.dev = dev;
+	mousedev->handle.handler = handler;
+	mousedev->handle.private = mousedev;
+
+	mousedev->devfs = input_register_minor("mouse%d", minor, MOUSEDEV_MINOR_BASE);
+
+	if (mousedev_mix.open)
+		input_open_device(&mousedev->handle);
+
+	printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
+
+	return &mousedev->handle;
+}
+
+static void mousedev_disconnect(struct input_handle *handle)
+{
+	struct mousedev *mousedev = handle->private;
+
+	if (mousedev->open || mousedev_mix.open)
+		input_close_device(handle);
+
+	if (!--mousedev->used) {
+		input_unregister_minor(mousedev->devfs);
+		mousedev_table[mousedev->minor] = NULL;
+		kfree(mousedev);
+	}
+}
+	
+static struct input_handler mousedev_handler = {
+	event:		mousedev_event,
+	connect:	mousedev_connect,
+	disconnect:	mousedev_disconnect,
+	fops:		&mousedev_fops,
+	minor:		MOUSEDEV_MINOR_BASE,
+};
+
+static int __init mousedev_init(void)
+{
+	input_register_handler(&mousedev_handler);
+
+	memset(&mousedev_mix, 0, sizeof(struct mousedev));
+	init_waitqueue_head(&mousedev_mix.wait);
+	mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
+	mousedev_mix.used = 1;
+	mousedev_mix.minor = MOUSEDEV_MIX;
+	mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
+
+	printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
+
+	return 0;
+}
+
+static void __exit mousedev_exit(void)
+{
+	input_unregister_minor(mousedev_mix.devfs);
+	input_unregister_handler(&mousedev_handler);
+}
+
+module_init(mousedev_init);
+module_exit(mousedev_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ohci-debug.c linux.18p8/drivers/usb/ohci-debug.c
--- linux.vanilla/drivers/usb/ohci-debug.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/ohci-debug.c	Thu Jan  1 01:00:00 1970
@@ -1,178 +0,0 @@
-/*
- * OHCI debugging code.  It's gross.
- *
- * (C) Copyright 1999 Gregory P. Smith
- */
-
-#include <linux/kernel.h>
-#include <asm/io.h>
-
-#include "ohci.h"
-
-void show_ohci_status(struct ohci *ohci)
-{
-	struct ohci_regs regs;
-	int i;
-
-	regs.revision = readl(&ohci->regs->revision);
-	regs.control = readl(&ohci->regs->control);
-	regs.cmdstatus = readl(&ohci->regs->cmdstatus);
-	regs.intrstatus = readl(&ohci->regs->intrstatus);
-	regs.intrenable = readl(&ohci->regs->intrenable);
-	regs.hcca = readl(&ohci->regs->hcca);
-	regs.ed_periodcurrent = readl(&ohci->regs->ed_periodcurrent);
-	regs.ed_controlhead = readl(&ohci->regs->ed_controlhead);
-	regs.ed_controlcurrent = readl(&ohci->regs->ed_controlcurrent);
-	regs.ed_bulkhead = readl(&ohci->regs->ed_bulkhead);
-	regs.ed_bulkcurrent = readl(&ohci->regs->ed_bulkcurrent);
-	regs.current_donehead = readl(&ohci->regs->current_donehead);
-	regs.fminterval = readl(&ohci->regs->fminterval);
-	regs.fmremaining = readl(&ohci->regs->fmremaining);
-	regs.fmnumber = readl(&ohci->regs->fmnumber);
-	regs.periodicstart = readl(&ohci->regs->periodicstart);
-	regs.lsthresh = readl(&ohci->regs->lsthresh);
-	regs.roothub.a = readl(&ohci->regs->roothub.a);
-	regs.roothub.b = readl(&ohci->regs->roothub.b);
-	regs.roothub.status = readl(&ohci->regs->roothub.status);
-	for (i=0; i<MAX_ROOT_PORTS; ++i)
-		regs.roothub.portstatus[i] = readl(&ohci->regs->roothub.portstatus[i]);
-
-	printk(KERN_DEBUG "  ohci revision    =  %x\n", regs.revision);
-	printk(KERN_DEBUG "  ohci control     =  %x\n", regs.control);
-	printk(KERN_DEBUG "  ohci cmdstatus   =  %x\n", regs.cmdstatus);
-	printk(KERN_DEBUG "  ohci intrstatus  =  %x\n", regs.intrstatus);
-	printk(KERN_DEBUG "  ohci intrenable  =  %x\n", regs.intrenable);
-
-	printk(KERN_DEBUG "  ohci hcca        =  %x\n", regs.hcca);
-	printk(KERN_DEBUG "  ohci ed_pdcur    =  %x\n", regs.ed_periodcurrent);
-	printk(KERN_DEBUG "  ohci ed_ctrlhead =  %x\n", regs.ed_controlhead);
-	printk(KERN_DEBUG "  ohci ed_ctrlcur  =  %x\n", regs.ed_controlcurrent);
-	printk(KERN_DEBUG "  ohci ed_bulkhead =  %x\n", regs.ed_bulkhead);
-	printk(KERN_DEBUG "  ohci ed_bulkcur  =  %x\n", regs.ed_bulkcurrent);
-	printk(KERN_DEBUG "  ohci curdonehead =  %x\n", regs.current_donehead);
-
-	printk(KERN_DEBUG "  ohci fminterval  =  %x\n", regs.fminterval);
-	printk(KERN_DEBUG "  ohci fmremaining =  %x\n", regs.fmremaining);
-	printk(KERN_DEBUG "  ohci fmnumber    =  %x\n", regs.fmnumber);
-	printk(KERN_DEBUG "  ohci pdstart     =  %x\n", regs.periodicstart);
-	printk(KERN_DEBUG "  ohci lsthresh    =  %x\n", regs.lsthresh);
-
-	printk(KERN_DEBUG "  ohci roothub.a   =  %x\n", regs.roothub.a);
-	printk(KERN_DEBUG "  ohci roothub.b   =  %x\n", regs.roothub.b);
-	printk(KERN_DEBUG "  ohci root status =  %x\n", regs.roothub.status);
-	printk(KERN_DEBUG "    roothub.port0  =  %x\n", regs.roothub.portstatus[0]);
-	printk(KERN_DEBUG "    roothub.port1  =  %x\n", regs.roothub.portstatus[1]);
-} /* show_ohci_status() */
-
-
-void show_ohci_ed(struct ohci_ed *ed)
-{
-	int stat = ed->status;
-	int skip = (stat & OHCI_ED_SKIP);
-	int mps = (stat & OHCI_ED_MPS) >> 16;
-	int isoc = (stat & OHCI_ED_F_ISOC);
-	int low_speed = (stat & OHCI_ED_S_LOW);
-	int dir = (stat & OHCI_ED_D);
-	int endnum = (stat & OHCI_ED_EN) >> 7;
-	int funcaddr = (stat & OHCI_ED_FA);
-	int halted = (ed->_head_td & 1);
-	int toggle = (ed->_head_td & 2) >> 1;
-
-	printk(KERN_DEBUG "   ohci ED:\n");
-	printk(KERN_DEBUG "     status     =  0x%x\n", stat);
-	printk(KERN_DEBUG "       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
-			skip ? "Skip " : "",
-			mps,
-			isoc ? "Isoc. " : "",
-			low_speed ? " LowSpd" : "",
-			(dir == OHCI_ED_D_IN) ? " Input" :
-			(dir == OHCI_ED_D_OUT) ? " Output" : "",
-			halted ? " Halted" : "",
-			toggle,
-			endnum,
-			funcaddr);
-	printk(KERN_DEBUG "     tail_td    =  0x%x\n", ed->tail_td);
-	printk(KERN_DEBUG "     head_td    =  0x%x\n", ed_head_td(ed));
-	printk(KERN_DEBUG "     next_ed    =  0x%x\n", ed->next_ed);
-} /* show_ohci_ed() */
-
-
-void show_ohci_td(struct ohci_td *td)
-{
-	int td_round = td->info & OHCI_TD_ROUND;
-	int td_dir = td->info & OHCI_TD_D;
-	int td_int_delay = (td->info & OHCI_TD_IOC_DELAY) >> 21;
-	int td_toggle = (td->info & OHCI_TD_DT) >> 24;
-	int td_errcnt = td_errorcount(*td);
-	int td_cc = OHCI_TD_CC_GET(td->info);
-
-	printk(KERN_DEBUG "   ohci TD hardware fields:\n");
-	printk(KERN_DEBUG "      info     =  0x%x\n", td->info);
-	printk(KERN_DEBUG "        %s%s%s%d %s\n",
-		td_round ? "Rounding " : "",
-		(td_dir == OHCI_TD_D_IN) ? "Input " :
-		(td_dir == OHCI_TD_D_OUT) ? "Output " :
-		(td_dir == OHCI_TD_D_SETUP) ? "Setup " : "",
-		"IntDelay ", td_int_delay,
-		(td_toggle < 2) ? " " :
-		(td_toggle & 1) ? "Data1 " : "Data0 ");
-	printk(KERN_DEBUG "        %s%d %s0x%x, %sAccessed, %sActive\n",
-		"ErrorCnt ", td_errcnt,
-		"ComplCode ", td_cc,
-		td_cc_accessed(*td) ? "" : "Not ",
-		td_active(*td) ? "" : "Not ");
-
-	printk(KERN_DEBUG "      cur_buf  =  0x%x\n", td->cur_buf);
-	printk(KERN_DEBUG "      next_td  =  0x%x\n", td->next_td);
-	printk(KERN_DEBUG "      buf_end  =  0x%x\n", td->buf_end);
-	printk(KERN_DEBUG "   ohci TD driver fields:\n");
-	printk(KERN_DEBUG "      data     =  %p\n", td->data);
-	printk(KERN_DEBUG "      dev_id   =  %p\n", td->dev_id);
-	printk(KERN_DEBUG "      ed       =  %p\n", td->ed);
-	if (td->data != NULL) {
-	unsigned char *d = td->data;
-	printk(KERN_DEBUG "   DATA: %02x %02x %02x %02x %02x %02x %02x %02x\n",
-			d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7] );
-	}
-} /* show_ohci_td() */
-
-
-void show_ohci_device(struct ohci_device *dev)
-{
-	int idx;
-	printk(KERN_DEBUG "  ohci_device usb       =  %p\n", dev->usb);
-	printk(KERN_DEBUG "  ohci_device ohci      =  %p\n", dev->ohci);
-	printk(KERN_DEBUG "  ohci_device ohci_hcca =  %p\n", dev->hcca);
-	for (idx=0; idx<3 /*NUM_EDS*/; ++idx) {
-		printk(KERN_DEBUG "   [ed num %d] ", idx);
-		show_ohci_ed(&dev->ed[idx]);
-	}
-	for (idx=0; idx<3 /*NUM_TDS*/; ++idx) {
-		printk(KERN_DEBUG "   [td num %d] ", idx);
-		show_ohci_td(&dev->td[idx]);
-	}
-	printk(KERN_DEBUG "  ohci_device data\n    ");
-	for (idx=0; idx<4; ++idx) {
-		printk(KERN_DEBUG " %08lx", dev->data[idx]);
-	}
-	printk(KERN_DEBUG "\n");
-} /* show_ohci_device() */
-
-
-void show_ohci_hcca(struct ohci_hcca *hcca)
-{
-	int idx;
-
-	printk(KERN_DEBUG "  ohci_hcca\n");
-
-	for (idx=0; idx<NUM_INTS; idx++) {
-		printk(KERN_DEBUG "    int_table[%2d]  == %p\n", idx, hcca->int_table +idx);
-	}
-
-	printk(KERN_DEBUG "    frame_no          == %d\n", hcca->frame_no);
-	printk(KERN_DEBUG "    donehead          == 0x%08x\n", hcca->donehead);
-} /* show_ohci_hcca() */
-
-
-/* vim:sw=8
- */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ohci-hcd.c linux.18p8/drivers/usb/ohci-hcd.c
--- linux.vanilla/drivers/usb/ohci-hcd.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/ohci-hcd.c	Thu Jan  1 01:00:00 1970
@@ -1,1489 +0,0 @@
-/*
- * OHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- *
- * The OHCI HCD layer is a simple but nearly complete implementation of what the
- * USB people would call a HCD  for the OHCI. 
- * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
- * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
- * 
- * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
- * [ Open Host Controller Interface driver for USB. ]
- * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
- * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
- * [ $Log: ohci.c,v $ ]
- * [ Revision 1.1  1999/04/05 08:32:30  greg ]
- * 
- * 
- * v2.1 1999/05/09 ep_addr correction, code clean up
- * v2.0 1999/05/04 
- * virtual root hub is now an option, 
- * memory allocation based on kmalloc and kfree now, Bus error handling, 
- * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
- * 
- * from Linus Torvalds (uhci.c) (APM not tested; hub, usb_device, bus and related stuff)
- * from Greg Smith (ohci.c) (reset controller handling, hub)
- * 
- * v1.0 1999/04/27 initial release
- * ohci-hcd.c
- */
-
-/* #define OHCI_DBG  */  /* printk some debug information */
-
- 
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-
-#include <asm/spinlock.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include "usb.h"
-#include "ohci-hcd.h"
-#include "inits.h" 
-
- 
-
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-static int handle_apm_event(apm_event_t event);
-static int apm_resume = 0;
-#endif
-
- 
-
-static struct wait_queue *control_wakeup;         
-static struct wait_queue *root_hub = NULL;
- 
-static __u8 cc_to_status[16] = { /* mapping of the OHCI CC to the UHCI status codes; first guess */
-/* Activ, Stalled, Data Buffer Err, Babble Detected : NAK recvd, CRC/Timeout, Bitstuff, reservd */
-/* No  Error  */		0x00,
-/* CRC Error  */		0x04,
-/* Bit Stuff  */		0x02,
-/* Data Togg  */ 		0x40,
-/* Stall      */		0x40,
-/* DevNotResp */		0x04,
-/* PIDCheck   */		0x04,
-/* UnExpPID   */		0x40,
-/* DataOver   */		0x20,
-/* DataUnder  */ 		0x20,
-/* reservd    */		0x40,
-/* reservd    */		0x40,
-/* BufferOver */		0x20,
-/* BuffUnder  */		0x20,
-/* Not Access */		0x80,
-/* Not Access */		0x80
- };
- 
- 
-/********
- **** Interface functions
- ***********************************************/
- 
-static int sohci_int_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
-{
-
-	struct ohci * ohci = ohci_in; 
-	usb_device_irq handler=(void *) lw0;
-	void *dev_id = (void *) lw1;
-	int ret;
-	
-	OHCI_DEBUG({ int i; printk("USB HC IRQ <<<: %x: data(%d):", ep_addr, data_len);)
-	OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
-	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
-	
- 	ret = handler(cc_to_status[status & 0xf], data, dev_id);
-	if(ret == 0) return 0; /* 0 .. do not requeue  */
-	if(status > 0) return -1; /* error occured do not requeue ? */
-	ohci_trans_req(ohci, ep_addr, 0, NULL, data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id); /* requeue int request */
-	return 0;
-}
-
-static int sohci_ctrl_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw)
-{  
-	*(int * )lw0 = status;
-	wake_up(&control_wakeup);
-
-	OHCI_DEBUG( { int i; printk("USB HC CTRL<<<: %x: ctrl(%d):", ep_addr, ctrl_len);)
-	OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) ctrl)[i]);)
-	OHCI_DEBUG( printk(" data(%d):", data_len);) 
-	OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
-	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
-    return 0;                       
-} 
-                                                             
-static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
-{
-	struct ohci * ohci = usb_dev->bus->hcpriv;
-	union ep_addr_ ep_addr;
-	
-	ep_addr.iep = 0;
-	ep_addr.bep.ep = ((pipe >> 15) & 0x0f) 		/* endpoint address */
-				| (pipe  & 0x80)  	 			/* direction */
-				| (1 << 5);						/* type = int*/
-	ep_addr.bep.fa = ((pipe >> 8) & 0x7f);			/* device address */
-
-	OHCI_DEBUG( printk("USB HC IRQ >>>: %x: every %d ms\n", ep_addr.iep, period);) 
-	
-	usb_ohci_add_ep(ohci, ep_addr.iep, period, 1, sohci_int_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
-	
-   	ohci_trans_req(ohci, ep_addr.iep, 0, NULL, ((struct ohci_device *) usb_dev->hcpriv)->data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id);
-	return 0;
-}
-
-
-static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
-{
-	struct wait_queue wait = { current, NULL }; 
-	struct ohci * ohci = usb_dev->bus->hcpriv;
-	int status;
-	union ep_addr_ ep_addr;
-
-    ep_addr.iep = 0;
-	ep_addr.bep.ep = ((pipe >> 15) & 0x0f) 		/* endpoint address */		
-				| (pipe  & 0x80)  				/* direction */
-				|  (1 << 6);					/* type = ctrl*/
-	ep_addr.bep.fa	= ((pipe >> 8) & 0x7f);				/* device address */
-	
-	status = 0xf; /* CC not Accessed */
-	OHCI_DEBUG( { int i; printk("USB HC CTRL>>>: %x: ctrl(%d):", ep_addr.iep, 8);)
-	OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) cmd)[i]);)
-	OHCI_DEBUG( printk(" data(%d):", len);) 
-	OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
-	OHCI_DEBUG( printk("\n"); })
-	
-	usb_ohci_add_ep(ohci, ep_addr.iep, 0, 1, sohci_ctrl_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
-	
-	current->state = TASK_UNINTERRUPTIBLE;
-    add_wait_queue(&control_wakeup, &wait);   
- 
-	ohci_trans_req(ohci, ep_addr.iep, 8, cmd, data, len, (__OHCI_BAG) &status, 0);
-
-	schedule_timeout(HZ/10);
-
-    remove_wait_queue(&control_wakeup, &wait); 
-     
-    OHCI_DEBUG(printk("USB HC status::: %x\n", cc_to_status[status & 0x0f]);)
-     
-	return cc_to_status[status & 0x0f];
-}
-
-
-static int sohci_usb_deallocate(struct usb_device *usb_dev) {
-    struct ohci_device *dev = usb_to_ohci(usb_dev); 
-	union ep_addr_ ep_addr;
-
-	ep_addr.iep = 0;
-	
-	OHCI_DEBUG(printk("USB HC dealloc %x\n", usb_dev->devnum);)
-
-	/* wait_ms(20); */
-
-	if(usb_dev->devnum >=0) {
-		ep_addr.bep.fa = usb_dev->devnum;
-    	usb_ohci_rm_function(((struct ohci_device *)usb_dev->hcpriv)->ohci, ep_addr.iep);
-	}
-	
-    USB_FREE(dev);
-	USB_FREE(usb_dev);
-
-	return 0;
-}
-
-static struct usb_device *sohci_usb_allocate(struct usb_device *parent) {
- 
-	struct usb_device *usb_dev;
-	struct ohci_device *dev;
-	
-	
-	USB_ALLOC(usb_dev, sizeof(*usb_dev));
-	if (!usb_dev)
-		return NULL;
-		
-	memset(usb_dev, 0, sizeof(*usb_dev));
-
-	USB_ALLOC(dev, sizeof(*dev));
-	if (!dev) {
-		USB_FREE(usb_dev);
-		return NULL;
-	}
-
-	/* Initialize "dev" */
-	memset(dev, 0, sizeof(*dev));
-
-	usb_dev->hcpriv = dev;
-	dev->usb = usb_dev;
-
-	usb_dev->parent = parent;
-
-	if (parent) {
-		usb_dev->bus = parent->bus;
-		dev->ohci = usb_to_ohci(parent)->ohci;
-	}
-	return usb_dev;
-}
-
-struct usb_operations sohci_device_operations = {
-	sohci_usb_allocate,
-	sohci_usb_deallocate,
-	sohci_control_msg,
-	sohci_request_irq,
-};
-
- 
-/******
- *** ED handling functions
- ************************************/
-
-
-
-/* 
- * search for the right place to insert an interrupt ed into the int tree 
- * do some load ballancing
- * */
-
-static int usb_ohci_int_ballance(struct ohci * ohci, int interval, int load) {
-
-  int i,j;
-  
-  j = 0;   /* search for the least loaded interrupt endpoint branch of all 32 branches */
-  for(i=0; i< 32; i++) if(ohci->ohci_int_load[j] > ohci->ohci_int_load[i]) j=i; 
-
-  if(interval < 1) interval = 1;
-  if(interval > 32) interval = 32;
-  for(i= 0; ((interval >> i) > 1 ); interval &= (0xfffe << i++ )); /* interval = 2^int(ld(interval)) */
-  
-
-  for(i=j%interval; i< 32; i+=interval) ohci->ohci_int_load[i] += load;
-  j = interval + (j % interval); 
-  
-  OHCI_DEBUG(printk("USB HC new int ed on pos : %x \n",j);)
-  
-  return j;
-}
-
-/* get the ed from the endpoint / device adress */
-
-struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in) {
-
-union ep_addr_ ep_addr;
-struct usb_ohci_ed *tmp;
-unsigned int mask;
-
-mask = 0;
-ep_addr.iep = ep_addr_in;
-
-#ifdef VROOTHUB
- if(ep_addr.bep.fa == ohci->root_hub_funct_addr) {
- 	if((ep_addr.bep.ep & 0x0f) == 0)
- 		return &ohci->ed_rh_ep0; /* root hub ep0 */
- 	else
- 		return &ohci->ed_rh_epi; /* root hub int ep */
- }
-#endif
-
- tmp = ohci->ed_func_ep0[ep_addr.bep.fa];
- mask = ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); 
- ep_addr.bep.ep &= mask; /* mask out direction of ctrl ep */
- 
-  while (tmp != NULL) {
-    if (tmp->ep_addr.iep == ep_addr.iep) 
-      return tmp;
-    tmp = tmp->ed_list;
-  }
-  return NULL;
-}
- 
-spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
-/* add a new endpoint ep_addr */
-struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr_in, int interval, int load, f_handler handler, int ep_size, int speed) {
-   
-  struct usb_ohci_ed * ed; 
-  struct usb_ohci_td * td;
-  union ep_addr_ ep_addr;
- 
-   
-  int int_junk;
- 
-  struct usb_ohci_ed *tmp;
-
-  ep_addr.iep = ep_addr_in ;
-  ep_addr.bep.ep &= ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); /* mask out direction of ctrl ep */
-
-  spin_lock(&usb_ed_lock);
-  
-  tmp =  ohci_find_ep(ohci, ep_addr.iep);
-  if (tmp != NULL) { 
-  
-#ifdef VROOTHUB
-  	if(ep_addr.bep.fa == ohci->root_hub_funct_addr) {
- 		if((ep_addr.bep.ep & 0x0f) != 0) { /* root hub int ep */
-			ohci->ed_rh_epi.handler = handler;
- 			ohci_init_rh_int_timer(ohci, interval);
- 		}
- 		else { /* root hub ep0 */
- 			 ohci->ed_rh_ep0.handler = handler;
- 		}			 	
- 	}
-
- 	else 
-#endif 
-
- 		{
- 		tmp->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7)
-  		
-    	| (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0)
-    	| (speed << 13)
-    	| ep_size <<16;
- 
-  		tmp->handler = handler; 
-  	}
- 	spin_unlock(&usb_ed_lock);
-    return tmp;    /* ed  already in use */
-  }
-  
-  
-  OHCI_ALLOC(td, sizeof(td)); /* dummy td; end of td list for ed */
-  OHCI_ALLOC(ed, sizeof(ed));
-  td->prev_td = NULL;
-  
-  ed->hw.tail_td = virt_to_bus(&td->hw);
-  ed->hw.head_td = ed->hw.tail_td;
-  ed->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7)
-  /*  | ((ep_addr.bep.port & 0x80)? 0x1000 : 0x0800 ) */
-    | (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0)
-    | (speed << 13)
-    | ep_size <<16;
-  
-  ed->handler = handler;
-
-  switch((ep_addr.bep.ep >> 5) & 0x03) {
-  case CTRL:
-    ed->hw.next_ed = 0;
-    if(ohci->ed_controltail == NULL) {
-      writel(virt_to_bus(&ed->hw), &ohci->regs->ed_controlhead);
-    }
-    else {
-      ohci->ed_controltail->hw.next_ed = virt_to_bus(&ed->hw);
-    }
-    ed->ed_prev = ohci->ed_controltail;
-    ohci->ed_controltail = ed;	  
-    break;
-  case BULK:  
-    ed->hw.next_ed = 0;
-    if(ohci->ed_bulktail == NULL) {
-      writel(virt_to_bus(&ed->hw), &ohci->regs->ed_bulkhead);
-    }
-    else {
-      ohci->ed_bulktail->hw.next_ed = virt_to_bus(&ed->hw);
-    }
-    ed->ed_prev = ohci->ed_bulktail;
-    ohci->ed_bulktail = ed;	  
-    break;
-  case INT:
-    int_junk = usb_ohci_int_ballance(ohci, interval, load);
-    ed->hw.next_ed = ohci->hc_area->ed[int_junk].next_ed; 
-    ohci->hc_area->ed[int_junk].next_ed = virt_to_bus(&ed->hw);
-    ed->ed_prev = (struct usb_ohci_ed *) &ohci->hc_area->ed[int_junk];
-    break;
-  case ISO:
-    ed->hw.next_ed = 0;
-    ohci->ed_isotail->hw.next_ed = virt_to_bus(&ed->hw);
-    ed->ed_prev = ohci->ed_isotail;
-    ohci->ed_isotail = ed;	  
-    break;
-  }
-  ed->ep_addr  = ep_addr;
-  
-  /* Add it to the "hash"-table of known endpoint descriptors */      
-  
-  ed->ed_list = ohci->ed_func_ep0[ed->ep_addr.bep.fa];
-  ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed; 
-
-  spin_unlock(&usb_ed_lock);
-  
-  OHCI_DEBUG(printk("USB HC new ed %x: %x :", ep_addr.iep, (unsigned int ) ed); )
-  OHCI_DEBUG({ int i; for( i= 0; i<8 ;i++) printk(" %4x", ((unsigned int *) ed)[i]) ; printk("\n"); }; )
-  return 0;
-}
-
-/*****
- * Request the removal of an endpoint
- * 
- * put the ep on the rm_list and request a stop of the bulk or ctrl list 
- * real removal is done at the next start of frame hardware interrupt 
- */
-int usb_ohci_rm_ep(struct ohci * ohci, struct  usb_ohci_ed *ed)
-{    
-  unsigned int flags;
-  struct usb_ohci_ed *tmp;
-  
-  OHCI_DEBUG(printk("USB HC remove ed %x: %x :\n", ed->ep_addr.iep, (unsigned int ) ed); )
-
-  spin_lock_irqsave(&usb_ed_lock, flags);
-
-  tmp = ohci->ed_func_ep0[ed->ep_addr.bep.fa];
-  if (tmp == NULL) {
-  	spin_unlock_irqrestore(&usb_ed_lock, flags);
-    return 0;
-  }
-
-  if(tmp == ed) {
-     ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed->ed_list;
-  }
-  else {
-    while (tmp->ed_list != ed) {
-      if (tmp->ed_list == NULL) {
-        spin_unlock_irqrestore(&usb_ed_lock, flags);
-		return 0;
-	  }
-      tmp = tmp->ed_list;
-    }
-    tmp->ed_list = ed->ed_list;
-  }
-  ed->ed_list = ohci->ed_rm_list;
-  ohci->ed_rm_list = ed;
-  ed->hw.info  |=  OHCI_ED_SKIP;
-
-  switch((ed->ep_addr.bep.ep >> 5) & 0x03) {
-  	case CTRL:
-    	writel_mask(~(0x01<<4), &ohci->regs->control); /* stop CTRL list */
-    	break;
-  	case BULK:
-    	writel_mask(~(0x01<<5), &ohci->regs->control); /* stop BULK list */
-    	break;
-  }
-
-
-  writel( OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
-
-  spin_unlock_irqrestore(&usb_ed_lock, flags);
-
-  return 1;
-}
-
-/* we have requested to stop the bulk or CTRL list,
- * now we can remove the eds on the rm_list */
- 
-static int ohci_rm_eds(struct ohci * ohci) {
-
-  unsigned int flags;
-  struct usb_ohci_ed *ed;
-  struct usb_ohci_ed *ed_tmp;
-  struct usb_ohci_td *td;
-  __u32 td_hw_tmp;
-  __u32 td_hw;
-  
-  spin_lock_irqsave(&usb_ed_lock, flags);
-
-  ed = ohci->ed_rm_list;
-
-  while (ed != NULL) {
-    
-    switch((ed->ep_addr.bep.ep >> 5) & 0x03) {
-    case CTRL: 
-      if(ed->ed_prev == NULL) {
-		writel(ed->hw.next_ed, &ohci->regs->ed_controlhead);
-      }
-      else {
-		ed->ed_prev->hw.next_ed = ed->hw.next_ed;
-      }
-      if(ohci->ed_controltail == ed) {
-		ohci->ed_controltail = ed->ed_prev;
-      }
-      break;
-    case BULK: 
-      if(ed->ed_prev == NULL) {
-		writel(ed->hw.next_ed, &ohci->regs->ed_bulkhead);
-      }
-      else {
-		ed->ed_prev->hw.next_ed = ed->hw.next_ed;
-      }
-      if(ohci->ed_bulktail == ed) {
-		ohci->ed_bulktail = ed->ed_prev;
-      }
-      break;
-    case INT: 
-      	ed->ed_prev->hw.next_ed = ed->hw.next_ed;
-      break;
-    case ISO:
-      ed->ed_prev->hw.next_ed = ed->hw.next_ed;
-      if(ohci->ed_isotail == ed) {
-		ohci->ed_isotail = ed->ed_prev;
-      }
-      break;
-    }
-    
-    if(ed->hw.next_ed != 0) ((struct usb_ohci_ed *) bus_to_virt(ed->hw.next_ed))->ed_prev = ed->ed_prev;
-    
-
-/* tds directly connected to ed */
- 
-	td_hw = ed->hw.head_td & 0xfffffff0;
-    while(td_hw != 0) {
-    	td = bus_to_virt(td_hw);
-    	td_hw_tmp = td_hw;
-    	td_hw = td->hw.next_td;
-    	OHCI_FREE(td); /* free pending tds */ 
-    	if(td_hw_tmp == ed->hw.tail_td) break;
-    	
-    }
-     
-    /* mark TDs on the hc done list (if there are any) */      
-	td_hw = readl(&ohci->regs->donehead) & 0xfffffff0;
-    while(td_hw != 0) {
-    	td = bus_to_virt(td_hw);
-    	td_hw = td->hw.next_td;
-    	if(td->ep == ed) td->ep = 0;
-   	}
- 
-    /* mark TDs on the hcca done list (if there are any) */      
-	td_hw = ohci->hc_area->hcca.done_head & 0xfffffff0 ;
-	
-    while(td_hw != 0) { 
-    	td = bus_to_virt(td_hw); 
-    	td_hw = td->hw.next_td;
-    	if(td->ep == ed) td->ep = 0;
-   	}
-
-    ed_tmp = ed;
-    ed = ed->ed_list;
-    OHCI_FREE(ed_tmp);  /* free ed */ 
-  }
-  writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
-  writel(0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
-  writel_set((0x01<<4), &ohci->regs->control);   /* start CTRL u. (BULK list) */ 
-
-  spin_unlock_irqrestore(&usb_ed_lock, flags);
-  
-  ohci->ed_rm_list = NULL;
-  OHCI_DEBUG(printk("USB HC after rm ed control: %4x  intrstat: %4x intrenable: %4x\n", readl(&ohci->regs->control),readl(&ohci->regs->intrstatus),readl(&ohci->regs->intrenable));)
- 
-
-  return 0;
-}
-
-/* remove all endpoints of a function (device) */
-int usb_ohci_rm_function( struct ohci * ohci, unsigned int ep_addr_in)
-{    
-  struct usb_ohci_ed *ed;
-  struct usb_ohci_ed *tmp;
-  union ep_addr_ ep_addr;
-
- 
-  
-  ep_addr.iep = ep_addr_in;
-
-  for(ed = ohci->ed_func_ep0[ep_addr.bep.fa]; ed != NULL;) {
-	tmp = ed;
-    ed = ed->ed_list;
-    usb_ohci_rm_ep(ohci, tmp);
-  }
- 
-
-  
-  return 1;
-}
-
-
-
-
-
-/******
- *** TD handling functions
- ************************************/
-
-
-#define FILL_TD(TD_PT, HANDLER, INFO, DATA, LEN, LW0, LW1)  \
-    td_pt = (TD_PT); \
-    td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); \
-    td_pt1->ep = usb_ep; \
-    td_pt1->handler = (HANDLER); \
-    td_pt1->buffer_start = (DATA); \
-    td_pt1->lw0 = (LW0); \
-    td_pt1->lw1 = (LW1); \
-    td_pt1->hw.info = (INFO); \
-    td_pt1->hw.cur_buf = virt_to_bus(DATA); \
-    td_pt1->hw.buf_end = td_pt1->hw.cur_buf + (LEN) - 1; \
-    td_pt1->hw.next_td = virt_to_bus(td_pt); \
-    usb_ep->hw.tail_td = virt_to_bus(td_pt); \
-    td_pt->prev_td = td_pt1; \
-    td_pt->hw.next_td = 0
-
-spinlock_t usb_req_lock = SPIN_LOCK_UNLOCKED;
-
-int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) {
-
-  int ed_type;
-  unsigned int flags;
-  struct usb_ohci_td *td_pt;
-  struct usb_ohci_td *td_pt1;
-  struct usb_ohci_td *td_pt_a1, *td_pt_a2, *td_pt_a3;
-  struct usb_ohci_ed *usb_ep;
-  f_handler handler;
-
-  
- td_pt_a1 =NULL;
- td_pt_a2 =NULL;
- td_pt_a3 =NULL;
-  
-  usb_ep = ohci_find_ep(ohci, ep_addr);
-  if(usb_ep == NULL ) return -1; /* not known ep */
-  
-  handler = usb_ep->handler;
- 
-#ifdef VROOTHUB 
-  if(usb_ep == &ohci->ed_rh_ep0) { /* root hub ep 0 control endpoint */  
-    root_hub_control_msg(ohci, 8, ctrl, data, data_len, lw0, lw1, handler);
-    return 0;
-  }
-
-  if(usb_ep == &ohci->ed_rh_epi) { /* root hub interrupt endpoint */
-  
-    root_hub_int_req(ohci, 8, ctrl, data, data_len, lw0, lw1, handler);  
-	return 0;
-  }
-#endif
-  /*  struct usb_ohci_ed * usb_ep = usb_ohci_add_ep(pipe, ohci, interval, 1); */
- 
-   ed_type = ((((union ep_addr_)ep_addr).bep.ep >> 5) & 0x07);
-  
-  switch(ed_type) {
-  case BULK_IN:
-  case BULK_OUT:   
-  case INT_IN:
-  case INT_OUT:    
-    OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1));
-    break;
-
-  case CTRL_IN:
-  case CTRL_OUT:
-    OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1));
-    OHCI_ALLOC(td_pt_a3, sizeof(td_pt_a3));  
-    if(data_len > 0) {
-      OHCI_ALLOC(td_pt_a2, sizeof(td_pt_a2));
-    }
-    break;
-
-  case ISO_IN:
-  case ISO_OUT:
-
-  }
-    
-  spin_lock_irqsave(&usb_req_lock, flags);
-  
-  switch(ed_type) {
-  case BULK_IN:
-    FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 );
-    writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
-    break;
-
-  case BULK_OUT: 
-    FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 );
-    writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
-    break;
-
-  case INT_IN: 
-    FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 );  
-    break;
-
-  case INT_OUT: 
-    FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 );
-    break;
-
-  case CTRL_IN: 
-    FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 );  
-    if(data_len > 0) { 
-      FILL_TD( td_pt_a2, NULL, TD_CC | TD_R |  TD_DP_IN | TD_T_DATA1, data, data_len, 0, 0 );  
-    } 
-    FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_OUT | TD_T_DATA1, NULL, 0, lw0, lw1 );
-    writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
-    break;
-
-  case CTRL_OUT:     
-    FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 );  
-    if(data_len > 0) { 
-      FILL_TD( td_pt_a2, NULL, TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1, data, data_len, 0, 0 );  
-    } 
-    FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_IN | TD_T_DATA1, NULL, 0, lw0, lw1 );
-    writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
-    break;
-
-  case ISO_IN:
-  case ISO_OUT:
-    break;
-  }
-
-
-  
-
- td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); 
-
- 
-  if(td_pt_a3 != NULL) td_pt_a3->prev_td = NULL;
-  	else if (td_pt_a2 != NULL) td_pt_a2->prev_td = NULL;
-  	  	else if (td_pt_a1 != NULL) td_pt_a1->prev_td = NULL;
-  	  
-  spin_unlock_irqrestore(&usb_req_lock, flags);
-  return 0;
-}
-
-
-/******
- *** Done List handling functions
- ************************************/
-
-/* replies to the request have to be on a FIFO basis so
- * we reverse the reversed done-list */
- 
-static struct usb_ohci_td * ohci_reverse_done_list(struct ohci * ohci) {
-
-  __u32 td_list_hc;
-  struct usb_ohci_td      * td_list = NULL;
-  struct usb_ohci_td      * td_rev = NULL;
-  	
-	td_list_hc = ohci->hc_area->hcca.done_head & 0xfffffff0;
-    ohci->hc_area->hcca.done_head = 0;
-    
- 	while(td_list_hc) {
-		
-		td_list = (struct  usb_ohci_td *) bus_to_virt(td_list_hc);
-		td_list->next_dl_td = td_rev;
-			
-		td_rev = td_list;
-		td_list_hc = td_list->hw.next_td & 0xfffffff0;
-	}
- return td_list;
-}
-
-/* all done requests are replied here */
-static int usb_ohci_done_list(struct ohci *  ohci) {
-
-  struct usb_ohci_td      * td = NULL;
-  struct usb_ohci_td      * td_list; 
-  struct usb_ohci_td      * td_list_next = NULL;
-  struct usb_ohci_td      * td_err = NULL;
-	__u32 td_hw;
- 
-	
-  td_list = ohci_reverse_done_list(ohci);
-
-  while(td_list) {
-   	td_list_next = td_list->next_dl_td;
-    td = td_list;
-
-    if(td->ep == NULL) { /* removed ep */
-   		OHCI_FREE(td_list);
-   		break;
-   	}
-   	
-   	/* the HC halts an ED if an error occurs; put all pendings TDs of an halted ED on the
-   	 * done list; they are marked with an 0xf CC_error code 
-   	 */
-   	 
- 	if(TD_CC_GET(td_list->hw.info) != TD_CC_NOERROR) { /* on error move all pending tds of an ed into the done list */
- 		printk("******* USB BUS error %x @ep %x\n", TD_CC_GET(td_list->hw.info), td_list->ep->ep_addr.iep);
-    td_err= td_list;
-	td_hw = td_list->ep->hw.head_td & 0xfffffff0;
-    while(td_hw != 0) { 
-    	if(td_hw == td_list->ep->hw.tail_td) break;
-    	td = bus_to_virt(td_hw);
-    	td_err->next_dl_td = td;
-    	td_err= td;
-    	td_hw = td->hw.next_td;
-    }
-    td_list->ep->hw.head_td = td_list->ep->hw.tail_td;
-    td->next_dl_td = td_list_next;
-    td_list_next = td_list->next_dl_td;
- 	
-    }
-  /*  send the reply  */
- 	if(td_list->handler != NULL)  {
-    	if(td_list->prev_td == NULL) {
-			td_list->handler((void *) ohci,
-						td_list->ep->ep_addr.iep,
-						0, 
-						NULL, 
-						td_list->buffer_start, 
-						td_list->hw.buf_end-virt_to_bus(td_list->buffer_start)+1, 
-						TD_CC_GET(td_list->hw.info),
-						td_list->lw0,
-						td_list->lw1);
-			OHCI_FREE(td_list);			
-   	  	}
-      	else {
-      		if(td_list->prev_td->prev_td == NULL) { /* cntrl 2 Transactions dataless */
-	  		td_list->handler((void *) ohci,
-	  		            td_list->ep->ep_addr.iep,
-	  					td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1,
-	  					td_list->prev_td->buffer_start, 
-	  					NULL,
-	  					0, 
-	  					(TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info),
-						td_list->lw0,
-						td_list->lw1);
-			OHCI_FREE(td_list->prev_td);
-			OHCI_FREE(td_list);
-			}
-			else { /* cntrl 3 Transactions */
-	  			td_list->handler((void *) ohci,
-	  					td_list->ep->ep_addr.iep, 
-	  					td_list->prev_td->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->prev_td->buffer_start)+1, 
-	  					td_list->prev_td->prev_td->buffer_start, 
-	  					td_list->prev_td->buffer_start, 
-	  					td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1, 
-	  					(TD_CC_GET(td_list->prev_td->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->prev_td->hw.info)
-	  						: (TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info),
-						td_list->lw0,
-						td_list->lw1); 
-				OHCI_FREE(td_list->prev_td->prev_td);			
-				OHCI_FREE(td_list->prev_td);
-				OHCI_FREE(td_list);
-					
-			}
-      	} 
-    	
-    }
-    td_list = td_list_next;
-  }  
-  return 0; 
-}
-
-
-
-/******
- *** HC functions
- ************************************/
- 
-
- 
-void reset_hc(struct ohci *ohci) {
-	int retries = 5;
-	int timeout = 30;
-	int fminterval;
-	
-	if(readl(&ohci->regs->control) & 0x100) { /* SMM owns the HC */
-		writel(0x08,  &ohci->regs->cmdstatus); /* request ownership */
-		printk("USB HC TakeOver from SMM\n");
-		do {
-			wait_ms(100);
-			if(--retries) { 
-				printk("USB HC TakeOver timed out!\n");
-				break;
-			}
-		}
-		while(readl(&ohci->regs->control) & 0x100); 
-	}	
-		
-	writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
-	OHCI_DEBUG(printk("USB HC reset_hc: %x ; retries: %d\n", readl(&ohci->regs->control), 5-retries);)
-	fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
-	writel(1,  &ohci->regs->cmdstatus);	   /* HC Reset */
-	while ((readl(&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
-		if (--timeout == 0) {
-			printk("USB HC reset timed out!\n");
-			return;
-		}	
-		udelay(1);
-	}
-	/* set the timing */
-	fminterval |= (((fminterval -210) * 6)/7)<<16; 
-	writel(fminterval, &ohci->regs->fminterval);
-	writel(((fminterval&0x3fff)*9)/10, &ohci->regs->periodicstart);
-}
-
-
-/*
- * Reset and start an OHCI controller
- */
-void start_hc(struct ohci *ohci)
-{
-   /*  int fminterval; */
-    unsigned int mask;
-  /*  fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
-	reset_hc(ohci); */
- 
-
-	writel(virt_to_bus(&ohci->hc_area->hcca), &ohci->regs->hcca); /* a reset clears this */
- 
-	/* Choose the interrupts we care about now, others later on demand */
-	mask = OHCI_INTR_MIE | OHCI_INTR_WDH;
-	/* | OHCI_INTR_SO | OHCI_INTR_UE |OHCI_INTR_RHSC |OHCI_INTR_SF|  
-		OHCI_INTR_FNO */
-		
-
-	 
-	writel((0x00), &ohci->regs->control); /* USB Reset BUS */
-	wait_ms(10);
-	  
-	writel((0x97), &ohci->regs->control); /* USB Operational  */
-	
- 	writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */
-	wait_ms(50); 
-		
-	OHCI_DEBUG(printk("USB HC rstart_hc_operational: %x\n", readl(&ohci->regs->control)); )
- 	OHCI_DEBUG(printk("USB HC roothubstata: %x \n", readl( &(ohci->regs->roothub.a) )); )
- 	OHCI_DEBUG(printk("USB HC roothubstatb: %x \n", readl( &(ohci->regs->roothub.b) )); )
- 	OHCI_DEBUG(printk("USB HC roothubstatu: %x \n", readl( &(ohci->regs->roothub.status) )); )
- 	OHCI_DEBUG(printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) )); )
-   	OHCI_DEBUG(printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) )); )
-  
-	/* control_wakeup = NULL; */
-	writel(mask, &ohci->regs->intrenable);
-	writel(mask, &ohci->regs->intrstatus);
- 
-#ifdef VROOTHUB
-	{
-
-	struct usb_device * usb_dev;
-	struct ohci_device *dev;
-
-	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
-	dev = usb_dev->hcpriv; 
-
-	dev->ohci = ohci; 
-
-	usb_connect(usb_dev);
-
-	ohci->root_hub->usb->children[0] = usb_dev;
-
-	usb_new_device(usb_dev);
-	}
-#endif
-
- 
-	
-}
-
-
-
-
-static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
-{
-  struct ohci *ohci = __ohci;
-  struct ohci_regs *regs = ohci->regs;
- 
-  int ints; 
-
- 
- if((ohci->hc_area->hcca.done_head != 0) && !(ohci->hc_area->hcca.done_head & 0x01)) {
-    ints =  OHCI_INTR_WDH;
-  }
-  else { 
-    if((ints = (readl(&regs->intrstatus) & readl(&regs->intrenable))) == 0)
-      return;
-   } 
-   
-  ohci->intrstatus |= ints;
-  OHCI_DEBUG(printk("USB HC interrupt: %x (%x) \n", ints, readl(&ohci->regs->intrstatus));)
-
-  /* ints &= ~(OHCI_INTR_WDH);  WH Bit will be set by done list subroutine */
- /*  if(ints & OHCI_INTR_FNO) {
-   	writel(OHCI_INTR_FNO,  &regs->intrstatus);
-   	if (waitqueue_active(&ohci_tasks)) wake_up(&ohci_tasks);
-  } */
-  
-  if(ints & OHCI_INTR_WDH) {
-   	writel(OHCI_INTR_WDH,  &regs->intrdisable);	
-   	ohci->intrstatus &= (~OHCI_INTR_WDH);
-	usb_ohci_done_list(ohci); /* prepare out channel list */
-	writel(OHCI_INTR_WDH, &ohci->regs->intrstatus);
-	writel(OHCI_INTR_WDH, &ohci->regs->intrenable);
-   	 
-  }
-  
-  if(ints & OHCI_INTR_SF) {
-  	writel(OHCI_INTR_SF,  &regs->intrdisable);	
-  	writel(OHCI_INTR_SF, &ohci->regs->intrstatus);
-	ohci->intrstatus &= (~OHCI_INTR_SF);
-  	if(ohci->ed_rm_list != NULL) {
-			ohci_rm_eds(ohci);
- 	 }
-  }
-#ifndef VROOTHUB 
-  if(ints & OHCI_INTR_RHSC) {  
-  	writel(OHCI_INTR_RHSC, &regs->intrdisable);
-  	writel(OHCI_INTR_RHSC, &ohci->regs->intrstatus);
-	wake_up(&root_hub);
-
-  }
- #endif
-
-  writel(OHCI_INTR_MIE, &regs->intrenable);
-	
-}
- 
-#ifndef VROOTHUB
-/*
- * This gets called if the connect status on the root
- * hub (and the root hub only) changes.
- */
-static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr)
-{
-	struct usb_device *usb_dev;
-    struct ohci_device *dev;
-	OHCI_DEBUG(printk("uhci_connect_change: called for %d stat %x\n", port_nr,readl(&ohci->regs->roothub.portstatus[port_nr]) );)
-
-	/*
-	 * Even if the status says we're connected,
-	 * the fact that the status bits changed may
-	 * that we got disconnected and then reconnected.
-	 *
-	 * So start off by getting rid of any old devices..
-	 */
-	usb_disconnect(&ohci->root_hub->usb->children[port_nr]);
-
-	 if(!(readl(&ohci->regs->roothub.portstatus[port_nr]) & RH_PS_CCS)) {
-	 	writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[port_nr]);
-		return; /* nothing connected */
-	}
-	/*
-	 * Ok, we got a new connection. Allocate a device to it,
-	 * and find out what it wants to do..
-	 */
-	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
-	dev = usb_dev->hcpriv; 
-	dev->ohci = ohci; 
-	usb_connect(dev->usb);
-	ohci->root_hub->usb->children[port_nr] = usb_dev;
-	wait_ms(200); /* wait for powerup */
-    /* reset port/device */
- 	writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[port_nr]); /* reset port */
- 	while(!(readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_PRSC)) wait_ms(10); /* reset active ? */
- 	writel(RH_PS_PES, &ohci->regs->roothub.portstatus[port_nr]); /* enable port */
- 	wait_ms(10);
-	/* Get speed information */
-	usb_dev->slow = (readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_LSDA) ? 1 : 0;
-
-	/*
-	 * Ok, all the stuff specific to the root hub has been done.
-	 * The rest is generic for any new USB attach, regardless of
-	 * hub type.
-	 */
-	usb_new_device(usb_dev);
-}
-#endif
- 
-
-
-/*
- * Allocate the resources required for running an OHCI controller.
- * Host controller interrupts must not be running while calling this
- * function.
- *
- * The mem_base parameter must be the usable -virtual- address of the
- * host controller's memory mapped I/O registers.
- *
- * This is where OHCI triumphs over UHCI, because good is dumb.
- * Note how much simpler this function is than in uhci.c.
- *
- * OHCI hardware takes care of most of the scheduling of different
- * transfer types with the correct prioritization for us.
- */
-
-
-static struct ohci *alloc_ohci(void* mem_base)
-{
-	int i,j;
-	struct ohci *ohci;
-	struct ohci_hc_area *hc_area;
-	struct usb_bus *bus;
-	struct ohci_device *dev;
-	struct usb_device *usb;
-
-	/*
-	 * Here we allocate some dummy  EDs as well as the
-	 * OHCI host controller communications area.  The HCCA is just
-	 * a nice pool of memory with pointers to endpoint descriptors
-	 * for the different interrupts.
-	 *
-	 * The first page of memory  contains the HCCA and ohci structure
-	 */
-	hc_area = (struct  ohci_hc_area *) __get_free_pages(GFP_KERNEL, 1);
-	if (!hc_area)
-		return NULL;
-	memset(hc_area, 0, sizeof(*hc_area));
-    ohci = &hc_area->ohci;
-	ohci->irq = -1;
-	ohci->regs = mem_base;
-    
-	ohci->hc_area = hc_area;
-	/* Tell the controller where the HCCA is */
-	writel(virt_to_bus(&hc_area->hcca), &ohci->regs->hcca);
-	
- 
-	/*
-	 * Initialize the ED polling "tree",  full tree;
-         * dummy eds ed[i] (hc should skip them) 
-         * i == 0 is the end of the iso list;
-		 * 1 is the   1ms node, 
-         * 2,3        2ms nodes,
-         * 4,5,6,7    4ms nodes,
-         * 8  ... 15  8ms nodes,
-         * 16 ... 31  16ms nodes,
-         * 32 ... 63  32ms nodes
-         * Sequenzes:
-		 * 32-16- 8-4-2-1-0
-         * 33-17- 9-5-3-1-0
-         * 34-18-10-6-2-1-0
-         * 35-19-11-7-3-1-0
-         * 36-20-12-4-2-1-0
-         * 37-21-13-5-3-1-0
-         * 38-22-14-6-2-1-0
-         * 39-23-15-7-3-1-0
-         * 40-24- 8-4-2-1-0
-         * 41-25- 9-5-3-1-0
-         * 42-26-10-6-2-1-0
-         *     :      :
-         * 63-31-15-7-3-1-0
-	 */
-        hc_area->ed[ED_ISO].info |=  OHCI_ED_SKIP; /* place holder, so skip it */
-        hc_area->ed[ED_ISO].next_ed =  0x0000;       /* end of iso list */
-
-        hc_area->ed[1].next_ed = virt_to_bus(&(hc_area->ed[ED_ISO]));
-        hc_area->ed[1].info |=  OHCI_ED_SKIP; /* place holder, skip it */
-	     
-        j=1;
-        for (i = 2; i < (NUM_INTS * 2); i++) {
-          	if (i >= NUM_INTS) 
-	   		 	hc_area->hcca.int_table[i - NUM_INTS] = virt_to_bus(&(hc_area->ed[i]));
-           
-          	if( i == j*4) j *= 2;
-	    	hc_area->ed[i].next_ed = virt_to_bus(&(hc_area->ed[j+ i%j]));
-            hc_area->ed[i].info |=  OHCI_ED_SKIP; /* place holder, skip it */
-        }
-
-
-	/*
-	 * for load ballancing of the interrupt branches 
-	 */
-	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
-
-	/*
-	 * Store the end of control and bulk list eds. So, we know where we can add
-	 * elements to these lists.
-	 */
-	ohci->ed_isotail     = (struct usb_ohci_ed *) &(hc_area->ed[ED_ISO]);
-        ohci->ed_controltail = NULL;
-        ohci->ed_bulktail    = NULL;
-	
-	/*
-	 * Tell the controller where the control and bulk lists are
-	 * The lists are empty now.
-	 */	
-	writel(0, &ohci->regs->ed_controlhead);
-	writel(0, &ohci->regs->ed_bulkhead);
-
-	
-	USB_ALLOC(bus, sizeof(*bus));
-	if (!bus)
-		return NULL;
-
-	memset(bus, 0, sizeof(*bus));
-
-	ohci->bus = bus;
-	bus->hcpriv = (void *) ohci;
-	bus->op = &sohci_device_operations;
-
-	 
-	usb = sohci_usb_allocate(NULL);
-	if (!usb)
-		return NULL;
-
-	dev = ohci->root_hub = usb_to_ohci(usb);
-
-	usb->bus = bus;
-	/* bus->root_hub = ohci_to_usb(ohci->root_hub); */
-	dev->ohci = ohci;
-	
-	/* Initialize the root hub */
-	 
-	usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
-	usb_init_root_hub(usb);
-
-	return ohci;
-} 
-
-
-/*
- * De-allocate all resources..
- */
-
-static void release_ohci(struct ohci *ohci)
-{
-	int i;
-	union ep_addr_ ep_addr;
-	ep_addr.iep = 0;
-	
-    OHCI_DEBUG(printk("USB HC release ohci \n");)
-    
-	if (ohci->irq >= 0) {
-		free_irq(ohci->irq, ohci);
-		ohci->irq = -1;
-	}
-
-    /* stop hc */
-	writel(OHCI_USB_SUSPEND, &ohci->regs->control);
-		
-	/* deallocate all EDs and TDs */
-	for(i=0; i < 128; i ++) {
-		ep_addr.bep.fa = i;
-		usb_ohci_rm_function(ohci, ep_addr.iep);
-	}
-	ohci_rm_eds(ohci); /* remove eds */
-	
-    /* disconnect all devices */    
-	if(ohci->root_hub)
-		for(i = 0; i < ohci->root_hub->usb->maxchild; i++)
-			  usb_disconnect(ohci->root_hub->usb->children + i);
-	    
-    USB_FREE(ohci->root_hub->usb);
-    USB_FREE(ohci->root_hub);
-    USB_FREE(ohci->bus);
-    
-	/* unmap the IO address space */
-	iounmap(ohci->regs);
-       
-	
-	free_pages((unsigned int) ohci->hc_area, 1);
-	
-}
-
- 
-void cleanup_drivers(void);
-
-static int ohci_roothub_thread(void * __ohci)
-{
-        struct ohci *ohci = (struct ohci *)__ohci;
-        lock_kernel(); 
-
-        /*
-         * This thread doesn't need any user-level access,
-         * so get rid of all our resources..
-         */
-        printk("ohci_roothub_thread at %p\n", &ohci_roothub_thread);
-        exit_mm(current);
-        exit_files(current);
-        exit_fs(current);
-
-
-        strcpy(current->comm, "root-hub");
-
-         
-		start_hc(ohci);
-		writel( 0x10000, &ohci->regs->roothub.status);
-		wait_ms(50); /* root hub power on */
-         do {
-#ifdef CONFIG_APM
-		if (apm_resume) {
-			apm_resume = 0;
-			start_hc(ohci);
-			continue;
-		}
-#endif
- 	 
-         OHCI_DEBUG(printk("USB RH tasks: int: %x\n", ohci->intrstatus); )
-#ifndef VROOTHUB
-		/*	if (ohci->intrstatus & OHCI_INTR_RHSC)  */
-			{
-				int port_nr;
-	     		for(port_nr=0; port_nr< ohci->root_hub->usb->maxchild; port_nr++)
-	     			if(readl(&ohci->regs->roothub.portstatus[port_nr]) & (RH_PS_CSC | RH_PS_PRSC)) {		
-	     		 		ohci_connect_change(ohci, port_nr);
-	     		 		writel(0xffff0000, &ohci->regs->roothub.portstatus[port_nr]);
-	     		 	}
-	     		 ohci->intrstatus &= ~(OHCI_INTR_RHSC);
-	     		 writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
-	    	}
-#endif
- 
-         interruptible_sleep_on(&root_hub);
- 
-      	} while (!signal_pending(current)); 
-             	
-#ifdef VROOTHUB
-		ohci_del_rh_int_timer(ohci);
-#endif
- 
-
-		cleanup_drivers();
-      /*  reset_hc(ohci); */
-	 
-        release_ohci(ohci);
-        MOD_DEC_USE_COUNT;
-
-	    printk("ohci_control_thread exiting\n");
-
-        return 0;
-}
-
-
- 
-
-/*
- * Increment the module usage count, start the control thread and
- * return success.
- */
-static int found_ohci(int irq, void* mem_base)
-{
-	int retval;
-	struct ohci *ohci;
-    OHCI_DEBUG(printk("USB HC found  ohci: irq= %d membase= %x \n", irq, (int)mem_base);)
-	/* Allocate the running OHCI structures */
-	ohci = alloc_ohci(mem_base);
-	if (!ohci) {
-	  return -ENOMEM;
-	}
-
-	reset_hc(ohci);
-
-	retval = -EBUSY;
-	if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
-		int pid;
-
-		MOD_INC_USE_COUNT; 
-		ohci->irq = irq;
-		 
-		pid = kernel_thread(ohci_roothub_thread, ohci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-		if (pid >= 0) 
-		 	return 0;
-		
-
-		MOD_DEC_USE_COUNT;
-		retval = pid;
-	}
-	
-	release_ohci(ohci);
-	return retval;
-}
- 
-static int start_ohci(struct pci_dev *dev)
-{
-	unsigned int mem_base = dev->base_address[0];
-
-	/* If its OHCI, its memory */
-	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
-		return -ENODEV;
-
-	/* Get the memory address and map it for IO */
-	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	/* 
-	 * FIXME ioremap_nocache isn't implemented on all CPUs (such
-	 * as the Alpha) [?]  What should I use instead...
-	 *
-	 * The iounmap() is done on in release_ohci.
-	 */
-	mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
-
-	if (!mem_base) {
-		printk("Error mapping OHCI memory\n");
-		return -EFAULT;
-	}
-
-	return found_ohci(dev->irq, (void *) mem_base);
-} 
-
-
-
-#ifdef CONFIG_APM
-static int handle_apm_event(apm_event_t event)
-{
-	static int down = 0;
-
-	switch (event) {
-	case APM_SYS_SUSPEND:
-	case APM_USER_SUSPEND:
-		if (down) {
-			printk(KERN_DEBUG "ohci: received extra suspend event\n");
-			break;
-		}
-		down = 1;
-		break;
-	case APM_NORMAL_RESUME:
-	case APM_CRITICAL_RESUME:
-		if (!down) {
-			printk(KERN_DEBUG "ohci: received bogus resume event\n");
-			break;
-		}
-		down = 0;
-		if (waitqueue_active(&root_hub)) {
-			apm_resume = 1;
-			wake_up(&root_hub);
-		}
-		break;
-	}
-	return 0;
-}
-#endif
-
-
- int usb_mouse_init(void); 
-#ifdef MODULE
-
-void cleanup_module(void)
-{
-#ifdef CONFIG_APM
-	apm_unregister_callback(&handle_apm_event);
-#endif
-}
-
-#define ohci_hcd_init init_module
-
-#endif
-
-#define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310
-#define PCI_CLASS_SERIAL_USB_OHCI_PG 0x10
- 
-
-int ohci_hcd_init(void)
-{
-  int retval;
-  struct pci_dev *dev = NULL;
- 
-  retval = -ENODEV;
-   
-  dev = NULL;
-  while((dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev))) { /* OHCI */
-    retval = start_ohci(dev);
-    if (retval < 0) break;
-
-    
-#ifdef CONFIG_USB_MOUSE
-		usb_mouse_init();
-#endif
-#ifdef CONFIG_USB_KBD		
-		usb_kbd_init();
-#endif		
-		hub_init();
-#ifdef CONFIG_USB_AUDIO		
-		usb_audio_init();
-#endif		
-#ifdef CONFIG_APM
-		apm_register_callback(&handle_apm_event);
-#endif
-  
-    return 0;
-  }
-  return retval;
-}
-
-void cleanup_drivers(void)
-{
-	 hub_cleanup(); 
-#ifdef CONFIG_USB_MOUSE
-	 usb_mouse_cleanup();
-#endif
-}
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ohci-hcd.h linux.18p8/drivers/usb/ohci-hcd.h
--- linux.vanilla/drivers/usb/ohci-hcd.h	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/ohci-hcd.h	Thu Jan  1 01:00:00 1970
@@ -1,404 +0,0 @@
- /*
- * OHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- *
- * The OHCI HCD layer is a simple but nearly complete implementation of what the
- * USB people would call a HCD  for the OHCI. 
- * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
- * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
- * 
- * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
- * [ Open Host Controller Interface driver for USB. ]
- * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
- * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
- * [ $Log: ohci.c,v $ ]
- * [ Revision 1.1  1999/04/05 08:32:30  greg ]
- * 
- * 
- * v2.1 1999/05/09 ep_addr correction, code clean up
- * v2.0 1999/05/04 
- * v1.0 1999/04/27
- * ohci-hcd.h
- */
-
-#include <linux/config.h>
-
-#ifdef CONFIG_USB_OHCI_VROOTHUB
-#define VROOTHUB  
-#endif
-/* enables virtual root hub 
- * (root hub will be managed by the hub controller 
- *  hub.c of the alternate usb driver)
- *  last time I did more testing without virtual root hub 
- *  -> the virtual root hub could be more unstable now */
- 
- 
-  
-#ifdef OHCI_DBG
-#define OHCI_DEBUG(X) X
-#else 
-#define OHCI_DEBUG(X)
-#endif 
-
-/* for readl writel functions */
-#include <linux/list.h>
-#include <asm/io.h>
-
-/* for ED and TD structures */
-
-typedef void * __OHCI_BAG;
-typedef int (*f_handler )(void * ohci, unsigned int ep_addr, int cmd_len, void *cmd, void *data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1);
-
-
-
-struct ep_address {
-  __u8 ep;  /* bit 7: IN/-OUT, 6,5: type 10..CTRL 00..ISO  11..BULK 10..INT, 3..0: ep nr */ 
-  __u8 fa;    /* function address */
-  __u8 hc;
-  __u8 host;
-};
-
-union ep_addr_ {
-  unsigned int iep;
-  struct ep_address bep;
-};
-
-/*
- * ED and TD descriptors has to be 16-byte aligned
- */
-struct ohci_hw_ed {
-  __u32 info;       
-  __u32 tail_td;	/* TD Queue tail pointer */
-  __u32 head_td;	/* TD Queue head pointer */
-  __u32 next_ed;	/* Next ED */
-} __attribute((aligned(16)));
-
-
-struct usb_ohci_ed {
-  struct ohci_hw_ed hw;
-  /*  struct ohci * ohci; */
-  f_handler handler;
-  union ep_addr_ ep_addr;
-  struct usb_ohci_ed *ed_list;
-  struct usb_ohci_ed *ed_prev;
-} __attribute((aligned(32)));
-
- /* OHCI Hardware fields */
-struct ohci_hw_td {     
-  __u32 info;
-  __u32 cur_buf;		/* Current Buffer Pointer */
-  __u32 next_td;		/* Next TD Pointer */
-  __u32 buf_end;		/* Memory Buffer End Pointer */
-} __attribute((aligned(16)));
-
-/* TD info field */
-#define TD_CC       0xf0000000
-#define TD_CC_GET(td_p) ((td_p >>28) & 0x04)
-#define TD_EC       0x0C000000
-#define TD_T        0x03000000
-#define TD_T_DATA0  0x02000000
-#define TD_T_DATA1  0x03000000
-#define TD_T_TOGGLE 0x00000000
-#define TD_R        0x00040000
-#define TD_DI       0x00E00000
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)
-#define TD_DP       0x00180000
-#define TD_DP_SETUP 0x00000000
-#define TD_DP_IN    0x00100000
-#define TD_DP_OUT   0x00080000
-
-/* CC Codes */
-#define TD_CC_NOERROR      0x00
-#define TD_CC_CRC          0x01
-#define TD_CC_BITSTUFFING  0x02
-#define TD_CC_DATATOGGLEM  0x03
-#define TD_CC_STALL        0x04
-#define TD_DEVNOTRESP      0x05
-#define TD_PIDCHECKFAIL    0x06
-#define TD_UNEXPECTEDPID   0x07
-#define TD_DATAOVERRUN     0x08
-#define TD_DATAUNDERRUN    0x09
-#define TD_BUFFEROVERRUN   0x0C
-#define TD_BUFFERUNDERRUN  0x0D
-#define TD_NOTACCESSED     0x0F
-
-
-
-struct usb_ohci_td {
-  struct ohci_hw_td hw;
-  void *  buffer_start;
-  f_handler handler; 
-  struct usb_ohci_td *prev_td;
-  struct usb_ohci_ed *ep;
-  struct usb_ohci_td *next_dl_td;
-  __OHCI_BAG lw0;
-  __OHCI_BAG lw1;
-} __attribute((aligned(32)));
-
-
-
-/* TD types */
-#define BULK		0x03
-#define INT			0x01
-#define CTRL		0x02
-#define ISO			0x00
-/* TD types with direction */
-#define BULK_IN		0x07
-#define BULK_OUT	0x03
-#define INT_IN		0x05
-#define INT_OUT		0x01
-#define CTRL_IN		0x06
-#define CTRL_OUT	0x02
-#define ISO_IN		0x04
-#define ISO_OUT		0x00
-
-struct ohci_rep_td {
-  int cmd_len;
-  void * cmd;
-  void * data;
-  int data_len;
-  f_handler handler;
-  struct ohci_rep_td *next_td;
-  int ep_addr;
-  __OHCI_BAG lw0;
-  __OHCI_BAG lw1;
-  __u32 status;
-} __attribute((aligned(32))); 
-
-#define OHCI_ED_SKIP	(1 << 14)
-#define OHCI_ED_MPS	(0x7ff << 16)
-#define OHCI_ED_F_NORM	(0)
-#define OHCI_ED_F_ISOC	(1 << 15)
-#define OHCI_ED_S_LOW	(1 << 13)
-#define OHCI_ED_S_HIGH	(0)
-#define OHCI_ED_D	(3 << 11)
-#define OHCI_ED_D_IN	(2 << 11)
-#define OHCI_ED_D_OUT	(1 << 11)
-#define OHCI_ED_EN	(0xf << 7)
-#define OHCI_ED_FA	(0x7f)
-
- 
-/*
- * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. that the host controller is
- * told the base address of.  It must be 256-byte aligned.
- */
-#define NUM_INTS 32	/* part of the OHCI standard */
-struct ohci_hcca {
-    __u32	int_table[NUM_INTS];	/* Interrupt ED table */
-	__u16	frame_no;		/* current frame number */
-	__u16	pad1;			/* set to 0 on each frame_no change */
-	__u32	done_head;		/* info returned for an interrupt */
-	u8		reserved_for_hc[116];
-} __attribute((aligned(256)));
-
-  
-
-#define ED_INT_1	1
-#define ED_INT_2	2
-#define ED_INT_4	4
-#define ED_INT_8	8
-#define ED_INT_16	16
-#define ED_INT_32	32
-#define ED_CONTROL	64
-#define ED_BULK		65
-#define ED_ISO		0	/* same as 1ms interrupt queue */
- 
-
-/*
- * This is the maximum number of root hub ports.  I don't think we'll
- * ever see more than two as that's the space available on an ATX
- * motherboard's case, but it could happen.  The OHCI spec allows for
- * up to 15... (which is insane!)
- * 
- * Although I suppose several "ports" could be connected directly to
- * internal laptop devices such as a keyboard, mouse, camera and
- * serial/parallel ports.  hmm...  That'd be neat.
- */
-#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region.  This is Memory Mapped I/O.  You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
- */
-struct ohci_regs {
-	/* control and status registers */
-	__u32	revision;
-	__u32	control;
-	__u32	cmdstatus;
-	__u32	intrstatus;
-	__u32	intrenable;
-	__u32	intrdisable;
-	/* memory pointers */
-	__u32	hcca;
-	__u32	ed_periodcurrent;
-	__u32	ed_controlhead;
-	__u32	ed_controlcurrent;
-	__u32	ed_bulkhead;
-	__u32	ed_bulkcurrent;
-	__u32	donehead;
-	/* frame counters */
-	__u32	fminterval;
-	__u32	fmremaining;
-	__u32	fmnumber;
-	__u32	periodicstart;
-	__u32	lsthresh;
-	/* Root hub ports */
-	struct	ohci_roothub_regs {
-		__u32	a;
-		__u32	b;
-		__u32	status;
-		__u32	portstatus[MAX_ROOT_PORTS];
-	} roothub;
-} __attribute((aligned(32)));
-
-
-/* 
- * Read a MMIO register and re-write it after ANDing with (m)
- */
-#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) )
-
-/*
- * Read a MMIO register and re-write it after ORing with (b)
- */
-#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) )
-
-/*
- * cmdstatus register */
-#define OHCI_CLF  0x02
-#define OHCI_BLF  0x04
-
-/*
- * Interrupt register masks
- */
-#define OHCI_INTR_SO	(1)
-#define OHCI_INTR_WDH	(1 << 1)
-#define OHCI_INTR_SF	(1 << 2)
-#define OHCI_INTR_RD	(1 << 3)
-#define OHCI_INTR_UE	(1 << 4)
-#define OHCI_INTR_FNO	(1 << 5)
-#define OHCI_INTR_RHSC	(1 << 6)
-#define OHCI_INTR_OC	(1 << 30)
-#define OHCI_INTR_MIE	(1 << 31)
-
-/*
- * Control register masks
- */
-#define OHCI_USB_OPER		(2 << 6)
-#define OHCI_USB_SUSPEND	(3 << 6)
-
-/*
- * This is the full ohci controller description
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs. (Linus)
- */
-
-
-struct ohci {
-    	int irq;
-	    struct ohci_regs *regs;					/* OHCI controller's memory */	
-	    struct ohci_hc_area *hc_area;			/* hcca, int ed-tree, ohci itself .. */                
-        int root_hub_funct_addr;                /* Address of Root Hub endpoint */       
-        int ohci_int_load[32];                       /* load of the 32 Interrupt Chains (for load ballancing)*/     
-        struct usb_ohci_ed * ed_rm_list;        /* list of all endpoints to be removed */
-        struct usb_ohci_ed * ed_bulktail;       /* last endpoint of bulk list */
-        struct usb_ohci_ed * ed_controltail;    /* last endpoint of control list */
-        struct usb_ohci_ed * ed_isotail;        /* last endpoint of iso list */
-        struct ohci_device * root_hub;
-        struct usb_ohci_ed ed_rh_ep0;
-        struct usb_ohci_ed ed_rh_epi;
-        struct ohci_rep_td *td_rh_epi;
-        int intrstatus;
-        struct usb_ohci_ed *ed_func_ep0[128];   /* "hash"-table for ep to ed mapping */
-        struct ohci_rep_td *repl_queue;			/* for internal requests */
-        int rh_int_interval;
-        int rh_int_timer;   
-        struct usb_bus *bus;
-       
-       
-};
-
-/*
- *  Warning: This constant must not be so large as to cause the
- *  ohci_device structure to exceed one 4096 byte page.  Or "weird
- *  things will happen" as the alloc_ohci() function assumes that
- *  its less than one page at the moment.  (FIXME)
- */
-#define NUM_TDS	4		/* num of preallocated transfer descriptors */
-#define NUM_EDS 80		/* num of preallocated endpoint descriptors */
-
-struct ohci_hc_area {
-
-	struct ohci_hcca 	hcca;		/* OHCI mem. mapped IO area 256 Bytes*/
-
-	struct ohci_hw_ed		ed[NUM_EDS];	/* Endpoint Descriptors 80 * 16  : 1280 Bytes */
-	struct ohci_hw_td		td[NUM_TDS];	/* Transfer Descriptors 2 * 32   : 64 Bytes */
-        struct ohci             ohci;
-        
-};
-struct ohci_device {
-	struct usb_device	*usb;
-	struct ohci			*ohci;
-	unsigned long		data[16];
-};
-
-#define ohci_to_usb(uhci)	((ohci)->usb)
-#define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
-
-/* Debugging code */
-/*void show_ed(struct ohci_ed *ed);
-void show_td(struct ohci_td *td);
-void show_status(struct ohci *ohci); */
-
-/* hcd */
-int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int cmd_len, void  *cmd, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1); 
-struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr, int interval, int load, f_handler handler, int ep_size, int speed);
-int usb_ohci_rm_function(struct ohci * ohci, unsigned int ep_addr); 
-int usb_ohci_rm_ep(struct ohci * ohci, struct  usb_ohci_ed *ed);
-struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in);
-
-/* roothub */
-int ohci_del_rh_int_timer(struct ohci * ohci);
-int	ohci_init_rh_int_timer(struct ohci * ohci, int interval);  	
-int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void *  data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
-int root_hub_send_irq(struct ohci * ohci, void * data, int data_len );
-int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
-int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int  len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
-int send_replies(struct ohci * ohci);
-
-  
- 
-
-/* Root-Hub Register info */
-
-#define RH_PS_CCS            0x00000001   
-#define RH_PS_PES            0x00000002   
-#define RH_PS_PSS            0x00000004   
-#define RH_PS_POCI           0x00000008   
-#define RH_PS_PRS            0x00000010  
-#define RH_PS_PPS            0x00000100   
-#define RH_PS_LSDA           0x00000200    
-#define RH_PS_CSC            0x00010000 
-#define RH_PS_PESC           0x00020000   
-#define RH_PS_PSSC           0x00040000    
-#define RH_PS_OCIC           0x00080000    
-#define RH_PS_PRSC           0x00100000   
-
-
-#ifdef OHCI_DBG
-#define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d\n", -- __ohci_free_cnt)
-#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("OHCI ALLO: %d\n", ++ __ohci_free_cnt)
-#define USB_FREE(x) kfree(x); printk("USB FREE: %d\n", -- __ohci_free1_cnt)
-#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("USB ALLO: %d\n", ++ __ohci_free1_cnt)
-static int __ohci_free_cnt = 0;
-static int __ohci_free1_cnt = 0;
-#else
-#define OHCI_FREE(x) kfree(x) 
-#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) 
-#define USB_FREE(x) kfree(x) 
-#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) 
-#endif
- 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ohci-root-hub.c linux.18p8/drivers/usb/ohci-root-hub.c
--- linux.vanilla/drivers/usb/ohci-root-hub.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/ohci-root-hub.c	Thu Jan  1 01:00:00 1970
@@ -1,604 +0,0 @@
-/*
- * HCD (OHCI) Virtual Root Hub for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
- *
- * The Root Hub is build into the HC (UHCI or OHCI) hardware. 
- * This piece of code lets it look like it resides on the usb
- * like the other hubs.
- * (for anyone who wants to do a control operation on the root hub)
- *  
- * v2.1 1999/05/09 
- * v2.0 1999/05/04
- * v1.0 1999/04/27
- * ohci-root-hub.c
- *  
- */
- 
-
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-
-#include "usb.h"
-#include "ohci-hcd.h" 
-
-#ifdef VROOTHUB 
-
-#include "ohci-root-hub.h"
-
-
-static __u8 root_hub_dev_des[] =
-{
-        0x12,       /*  __u8  bLength; */
-		0x01,       /*  __u8  bDescriptorType; Device */
-		0x00,	    /*  __u16 bcdUSB; v1.0 */
-        0x01,
-		0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
-		0x00,	    /*  __u8  bDeviceSubClass; */
-		0x00,       /*  __u8  bDeviceProtocol; */
-		0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
-		0x00,       /*  __u16 idVendor; */
-        0x00,
-		0x00,       /*  __u16 idProduct; */
-        0x00,
-		0x00,       /*  __u16 bcdDevice; */
-        0x00,
-		0x00,       /*  __u8  iManufacturer; */
-		0x00,       /*  __u8  iProduct; */
-		0x00,       /*  __u8  iSerialNumber; */
-        0x01        /*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-		0x09,       /*  __u8  bLength; */
-		0x02,       /*  __u8  bDescriptorType; Configuration */
-		0x19,       /*  __u16 wTotalLength; */
-        0x00,
-		0x01,       /*  __u8  bNumInterfaces; */
-		0x01,       /*  __u8  bConfigurationValue; */
-		0x00,       /*  __u8  iConfiguration; */
-		0x40,       /*  __u8  bmAttributes; 
-                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
-		0x00,       /*  __u8  MaxPower; */
-      
-     /* interface */	  
-        0x09,       /*  __u8  if_bLength; */
-        0x04,       /*  __u8  if_bDescriptorType; Interface */
-        0x00,       /*  __u8  if_bInterfaceNumber; */
-        0x00,       /*  __u8  if_bAlternateSetting; */
-        0x01,       /*  __u8  if_bNumEndpoints; */
-        0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-        0x00,       /*  __u8  if_bInterfaceSubClass; */
-        0x00,       /*  __u8  if_bInterfaceProtocol; */
-        0x00,       /*  __u8  if_iInterface; */
-     
-     /* endpoint */
-        0x07,       /*  __u8  ep_bLength; */
-        0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
-        0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-        0x03,       /*  __u8  ep_bmAttributes; Interrupt */
-        0x40,       /*  __u16 ep_wMaxPacketSize; 64 Bytes */
-        0x00,
-        0xff        /*  __u8  ep_bInterval; 255 ms */
-};
-
-/* 
-For OHCI we need just the  2nd Byte, so we 
-don't need this constant byte-array 
-
-static __u8 root_hub_hub_des[] =
-{ 
-        0x00,       *  __u8  bLength; *
-		0x29,       *  __u8  bDescriptorType; Hub-descriptor *
-        0x02,       *  __u8  bNbrPorts; *
-        0x00,       * __u16  wHubCharacteristics; *
-        0x00,
-        0x01,       *  __u8  bPwrOn2pwrGood; 2ms * 
-        0x00,       *  __u8  bHubContrCurrent; 0 mA *
-        0x00,       *  __u8  DeviceRemovable; *** 8 Ports max *** *
-        0xff        *  __u8  PortPwrCtrlMask; *** 8 ports max *** *
-};
-*/
-
-
-int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int leni, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler)
-{ 
-
-  __u32 stat;
-  __u32 rep_handler;
-  int req_reply=0;
-  union ep_addr_ ep_addr;
-  union ep_addr_ ep_addr_ret;
-        __u8 * cmd = rh_cmd;
-	__u8 * data = rh_data;
-	int i;
-	int len =leni;
-
-        __u8  bmRequestType = cmd[0];
-        __u8  bRequest      = cmd[1];
-        __u16 wValue        = cmd[3] << 8 | cmd [2];
-        __u16 wIndex        = cmd[5] << 8 | cmd [4];
-        __u16 wLength       = cmd[7] << 8 | cmd [6];
-printk("USB root hub: adr: %8x cmd(%8x): ", ohci->root_hub_funct_addr, 8);
-for(i=0;i<8;i++)
-	printk("%2x", ((char *)rh_cmd)[i]);
- 
-printk(" ; \n");
-
-	ep_addr_ret.iep = 0;
-	ep_addr_ret.bep.fa = ohci->root_hub_funct_addr;
-	ep_addr_ret.bep.ep =  (bmRequestType & 0x80) | 0x40;
-
-  switch (bmRequestType | bRequest << 8) {
-   /* Request Destination:
-      without flags: Device, 
-      RH_INTERFACE: interface, 
-      RH_ENDPOINT: endpoint,
-      RH_CLASS means HUB here, 
-      RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
-   */
-  
-   case RH_GET_STATUS:
-     len = 2; 
-     data[0] = 0x01;
-     data[1] = 0x00;
-     req_reply = RH_ACK; 
-     break;
-   case RH_GET_STATUS | RH_INTERFACE:
-     len = 2; 
-     data[0] = 0x00;
-     data[1] = 0x00;     
-     req_reply = RH_ACK;
-     break;
-   case RH_GET_STATUS | RH_ENDPOINT:
-     len = 2; 
-     data[0] = 0x00;
-     data[1] = 0x00;     
-     req_reply = RH_ACK;
-     break;
-   case RH_GET_STATUS | RH_CLASS: /* HUB_STATUS */
-     stat = readl(&ohci->regs->roothub.status) & 0x7fff7fff; /* bit 31 u. 15 has other meaning */ 
-     data[0] = stat & 0xff;
-     data[1] = (stat >> 8) & 0xff;
-     data[2] = (stat >> 16) & 0xff;
-     data[3] = (stat >> 24) & 0xff;
-     len = 4;
-     req_reply = RH_ACK; 
-     break;
-   case RH_GET_STATUS | RH_OTHER | RH_CLASS: /* PORT_STATUS */
-     stat = readl(&ohci->regs->roothub.portstatus[wIndex-1]);
-     data[0] = stat & 0xff;
-     data[1] = (stat >> 8) & 0xff;
-     data[2] = (stat >> 16) & 0xff;
-     data[3] = (stat >> 24) & 0xff;
-     len = 4;
-     req_reply = RH_ACK; 
-     printk("rh: stat %4x wIndex %4x;\n", stat , wIndex);
-     break;
-
-   case RH_CLEAR_FEATURE:
-     switch (wValue) {
-       case (RH_DEVICE_REMOTE_WAKEUP):
-       default:
-     }
-     break;
-
-   case RH_CLEAR_FEATURE | RH_ENDPOINT:  
-     switch (wValue) {
-       case (RH_ENDPOINT_STALL): 
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       default:
-     }
-     break;
-
-   case RH_CLEAR_FEATURE | RH_CLASS:
-     switch (wValue) {
-       /*     case (RH_C_HUB_LOCAL_POWER):  OHCI says: no switching of this one */
-       case (RH_C_HUB_OVER_CURRENT):
-         writel(RH_PS_OCIC, &ohci->regs->roothub.status);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       default:
-     }
-     break;
-   case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-     switch (wValue) {
-       case (RH_PORT_ENABLE):
-	     writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_SUSPEND):
-         writel(RH_PS_POCI, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_POWER):
-         writel(RH_PS_LSDA, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_CONNECTION):
-         writel(RH_PS_CSC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_ENABLE):
-         writel(RH_PS_PESC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_SUSPEND):
-         writel(RH_PS_PSSC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_OVER_CURRENT):
-         writel(RH_PS_OCIC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_C_PORT_RESET):
-         writel(RH_PS_PRSC, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       /*
-       case (RH_PORT_CONNECTION):
-       case (RH_PORT_OVER_CURRENT):
-       case (RH_PORT_RESET):
-       case (RH_PORT_LOW_SPEED):
-       */
-       default:
-     }
-     break;
-   case RH_SET_FEATURE:  
-     switch (wValue) {
-       case (RH_DEVICE_REMOTE_WAKEUP):
-       default:
-     }
-     break;
-
-   case RH_SET_FEATURE | RH_ENDPOINT:
-     switch (wValue) {
-       case (RH_ENDPOINT_STALL):
-       default:
-     }
-     break;
-
-   case RH_SET_FEATURE | RH_CLASS: 
-     switch (wValue) {
-       /* case (RH_C_HUB_LOCAL_POWER): Root Hub has no local Power 
-       case (RH_C_HUB_OVER_CURRENT): */
-      default:
-     }
-     break;
-   case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-     switch (wValue) {
-       case (RH_PORT_SUSPEND):
-         writel(RH_PS_PSS, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_RESET):
-         if((readl(&ohci->regs->roothub.portstatus[wIndex-1]) &1) != 0)  /* BUG IN HUP CODE *********/
-         writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_POWER):
-         writel(RH_PS_PPS, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       case (RH_PORT_ENABLE):
-         writel(RH_PS_PES, &ohci->regs->roothub.portstatus[wIndex-1]);
-         len=0;
-         req_reply = RH_ACK;
-         break;
-       /*
-       case (RH_PORT_CONNECTION):
-       case (RH_PORT_OVER_CURRENT):
-       case (RH_PORT_LOW_SPEED):
-       case (RH_C_PORT_CONNECTION):
-       case (RH_C_PORT_ENABLE):
-       case (RH_C_PORT_SUSPEND):
-       case (RH_C_PORT_OVER_CURRENT):
-       case (RH_C_PORT_RESET):
-       */
-       default:  
-     }
-     break;
-
-  case RH_SET_ADDRESS:
-     ohci->root_hub_funct_addr = wValue; 
-	/* ohci->ed_func_ep0[wValue] = &ohci->ed_rh_ep0;
-	 ohci->ed_func_ep0[wValue]->ep_addr.bep.fa = wValue; 
-	 ohci->ed_func_ep0[wValue]->ed_list = &ohci->ed_rh_epi; */
-	 ohci->ed_rh_epi.ed_list = NULL;
-	 ohci->ed_rh_epi.ep_addr.bep.fa = wValue;
-	 ohci->ed_rh_epi.ep_addr.bep.ep = 0xa1; /* Int in port 1 */
-     ohci->ed_func_ep0[0]= NULL;
-     len = 0;
-     req_reply = RH_ACK;
-     break;
-
-   case RH_GET_DESCRIPTOR:
-     switch ((wValue & 0xff00) >> 8) {
-     case (0x01): /* device descriptor */
-       len = min(sizeof(root_hub_dev_des), wLength);
-       memcpy(data, root_hub_dev_des, len);
-       req_reply = RH_ACK;
-       break;
-     case (0x02): /* configuration descriptor */
-       len = min(sizeof(root_hub_config_des), wLength);
-       memcpy(data, root_hub_config_des, len);
-       req_reply = RH_ACK;
-       break;
-     case (0x03): /* string descriptors */
-     default:
-     }
-     break;
-  case RH_GET_DESCRIPTOR | RH_CLASS:
-     data[1] = 0x29;
-     stat = readl(&ohci->regs->roothub.a);  
-     data[2] = stat & 0xff;        /* number of ports */
-     data[0] = (data[2] / 8) * 2 + 9; /* length of descriptor */
-     if(data[0] > wLength) {
-       req_reply =  RH_REQ_ERR;
-       break;
-     }
-     data[3] = (stat >> 8) & 0xff;
-     data[4] = (stat >> 16) & 0xff;
-     data[5] = (stat >> 24) & 0xff;
-     data[6] = 0; /* Root Hub needs no current from bus */
-     stat = readl(&ohci->regs->roothub.b); 
-     if(data[2] <= 8) { /* less than 8 Ports */
-       data[7] = stat & 0xff;
-       data[8] = (stat >> 16) & 0xff; /* 0xff for USB Rev. 1.1 ?, stat >> 16 for USB Rev. 1.0 */
-     }
-     else {
-       data[7] = stat & 0xff;
-       data[8] = (stat >> 8) & 0xff;
-       data[9] = (stat >> 16) & 0xff;  /* 0xff for USB Rev. 1.1?, stat >> 16 for USB Rev. 1.0 */
-       data[10] = (stat >> 24) & 0xff; /* 0xff for USB Rev. 1.1?, stat >> 24 for USB Rev. 1.0 */
-     }
-     len = data[0];
-     req_reply = RH_ACK;
-     break;
-
-   case RH_SET_DESCRIPTOR:
-     break;
-
-   case RH_GET_CONFIGURATION:
-     len = 1;
-     data[0] = 0x01;
-     req_reply = RH_ACK;
-     break;
-
-   case RH_SET_CONFIGURATION: /* start it up */
-     writel( 0x10000, &ohci->regs->roothub.status);
-     /*writel( OHCI_INTR_RHSC, &ohci->regs->intrenable);*/
-     len = 0;
-     req_reply = RH_ACK;
-     break;
-   /*  Optional or meaningless requests 
-     case RH_GET_STATE | RH_OTHER | RH_CLASS:
-     case RH_GET_INTERFACE | RH_INTERFACE:
-     case RH_SET_INTERFACE | RH_INTERFACE:
-     case RH_SYNC_FRAME | RH_ENDPOINT: 
-   */
-
-  /* Vendor Requests, we are the vendor!
-	Will the USB-Consortium give us a Vendor Id
-	for a virtual hub-device :-) ?
-     We could use these requests for configuration purposes on the HCD Driver, not used in the altenate usb !*/ 
-
-  case RH_SET_FEATURE | RH_VENDOR: /* remove all endpoints of device wIndex = Dev << 8  */
-    switch(wValue) {
-    case RH_REMOVE_EP:
-      ep_addr.iep = 0;
-      ep_addr.bep.ep = wIndex & 0xff;
-      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
-      usb_ohci_rm_function(ohci, ep_addr.iep);
-      len=0;
-      req_reply = RH_ACK;
-      break;
-    }
-    break;
-  case RH_SET_FEATURE | RH_ENDPOINT | RH_VENDOR: /* remove endpoint wIndex = Dev << 8 | EP */
-    switch(wValue) {
-    case RH_REMOVE_EP: 
-      ep_addr.iep = 0;
-      ep_addr.bep.ep = wIndex & 0xff;
-      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
-      usb_ohci_rm_ep(ohci, ohci_find_ep(ohci, ep_addr.iep));
-      len=0;
-      req_reply = RH_ACK;
-      break;
-    }
-    break;
-  case RH_SET_EP | RH_ENDPOINT | RH_VENDOR:   
-    ep_addr.bep.ep = data[0];
-    ep_addr.bep.fa = data[1];
-    ep_addr.bep.hc = data[2];
-    ep_addr.bep.host = data[3];  
-    rep_handler  = data[7] << 24 |data[6] << 16 | data[5] << 8 | data[4];
-    /*  struct usb_ohci_ed *usb_ohci_add_ep(union ep_addr_ ep_addr,
-	struct ohci * ohci, int interval, int load, int (*handler)(int, void*), int ep_size, int speed) */
-    usb_ohci_add_ep(ohci, ep_addr.iep, data[8], data[9], (f_handler) rep_handler, data[11] << 8 | data[10] , data[12]);
-    len=0;
-    req_reply = RH_ACK;
-    break;
-
-  default: 
-  }
- printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) ));
-  printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) ));
-
-  /* if (req_reply == RH_ACK) len; */
-  queue_reply(ohci, ep_addr_ret.iep, 8, rh_cmd, data, len, lw0, lw1, handler);
-  return 0;
-}
-
-int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void *  data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler){
-
-	struct ohci_rep_td *td;
- 	struct ohci_rep_td *tmp;
- 	union ep_addr_ ep_addr;
- 	
- 	td = kmalloc(sizeof(td),GFP_KERNEL);
- 	tmp = ohci->td_rh_epi;
- 	td->next_td = NULL;
- 	if(tmp == NULL) { /* queue td */
- 		ohci->td_rh_epi = td;	
- 	}
- 	else {
- 		while(tmp->next_td != NULL) tmp = tmp->next_td;
- 		tmp->next_td = td;
- 	}
- 	ep_addr.iep = 0;
- 	ep_addr.bep.fa = ohci->root_hub_funct_addr;
- 	ep_addr.bep.ep = 0xA1; /* INT IN EP endpoint 1 */
-  	td->cmd_len = 0;
-  	td->cmd = NULL;
-  	td->data = data;
-  	td->data_len = data_len;
-  	td->handler = handler; 
-  	td->next_td = NULL;
-  	td->ep_addr = ep_addr.iep;
-	td->lw0 = lw0;
-	td->lw1 = lw1;
-	ohci_init_rh_int_timer(ohci, 255);
-	return 0;
-}
-
-
-/* prepare Interrupt pipe transaction data; HUP INTERRUPT ENDPOINT */ 
-int root_hub_send_irq(struct ohci * ohci, void * rh_data, int rh_len ) {
-
-  int num_ports;
-  int i;
-  int ret;
-  int len;
-
-  __u8 * data = rh_data;
-
-  num_ports = readl(&ohci->regs->roothub.a) & 0xff; 
-  data[0] = (readl(&ohci->regs->roothub.status) & 0x00030000)>0?1:0;
-  ret = data[0];
-
-  for(i=0; i < num_ports; i++) {
-    data[i/8] |= ((readl(&ohci->regs->roothub.portstatus[i]) & 0x001f0000)>0?1:0) << ((i+1) % 8);
-    ret += data[i/8];
-  }
-  len = i/8 + 1;
-  
-  if (ret > 0) return len;
-
-  return  RH_NACK;
-}
-
-
-
-
- 
-static struct timer_list rh_int_timer;
-
-/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
-static void rh_int_timer_do(unsigned long ptr) {
-	int len; 
-	int interval;
-	struct ohci * ohci = (struct ohci *) ptr;
-    struct ohci_rep_td *td = ohci->td_rh_epi;
-
-	if(td != NULL) { /* if ther is a TD handle the INT request */
-		
-		len = root_hub_send_irq(ohci, td->data, td->data_len );
-		if(len > 0) {
-			ohci->td_rh_epi = td->next_td;
-			td->next_td = ohci->repl_queue; 
-			ohci->repl_queue = td;
-			send_replies(ohci);
-		}
-	}	
-	interval = ohci->rh_int_interval;
-	init_timer(& rh_int_timer);
-	rh_int_timer.function = rh_int_timer_do;
-	rh_int_timer.data = (unsigned long) ohci;
-	rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
-	add_timer(&rh_int_timer);
-}
-
-/* Root Hub INTs are polled by this timer */
-int ohci_init_rh_int_timer(struct ohci * ohci, int interval) {
-
-	if(!(ohci->rh_int_timer)) { 
-		ohci->rh_int_timer = 1;
-		ohci->rh_int_interval = interval;
-		init_timer(& rh_int_timer);
-		rh_int_timer.function = rh_int_timer_do;
-		rh_int_timer.data = (unsigned long) ohci;
-		rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
-		add_timer(&rh_int_timer);
-	}
-	return 0;
-}
-
-int ohci_del_rh_int_timer(struct ohci * ohci) {
-	del_timer(&rh_int_timer);
-	return 0;
-}
-/* for root hub replies, queue the reply, (it will be sent immediately now) */
-
-int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int  len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler) {
-
- struct ohci_rep_td *td;
- int status = 0;
- 
-printk("queue_reply ep: %x len: %x\n", ep_addr, len);
-td = kmalloc(sizeof(td), GFP_KERNEL);
-
-  if (len < 0) { status = len; len = 0;}
-  td->cmd_len = cmd_len;
-  td->cmd = cmd;
-  td->data = data;
-  td->data_len = len;
-  td->handler = handler; 
-  td->next_td = ohci->repl_queue; ohci->repl_queue = td;
-  td->ep_addr = ep_addr;
-  td->lw0 = lw0;
-  td->lw1 = lw1;
-  td->status = status;
-  send_replies(ohci);
-return 0;
-}
-
-/* for root hub replies; send the reply */
-int send_replies(struct ohci * ohci) { 
-	struct ohci_rep_td *td;
-	struct ohci_rep_td *tmp;
-
-	td = ohci->repl_queue; ohci->repl_queue = NULL;
-	while ( td != NULL) {
-		td->handler((void *) ohci, td->ep_addr,td->cmd_len,td->cmd, td->data, td->data_len, td->status, td->lw0, td->lw1); 
-		tmp = td;
-		td = td->next_td;
-	
-		kfree(tmp);
-	}
-	return 0;
-}
- 
-#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ohci-root-hub.h linux.18p8/drivers/usb/ohci-root-hub.h
--- linux.vanilla/drivers/usb/ohci-root-hub.h	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/ohci-root-hub.h	Thu Jan  1 01:00:00 1970
@@ -1,71 +0,0 @@
-/*
- * HCD (OHCI) Virtual Root Hub Protocol for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
- *
- * The Root Hub is build into the HC (UHCI or OHCI) hardware. 
- * This piece of code lets it look like it resides on the bus 
- * like the other hubs.
- * (for anyone who wants to do a control operation on the root hub)
- *  
- * v1.0 1999/04/27
- * ohci-root-hub.h
- *  
- */
- 
-/* destination of request */
-#define RH_INTERFACE               0x01
-#define RH_ENDPOINT                0x02
-#define RH_OTHER                   0x03
-
-#define RH_CLASS                   0x20
-#define RH_VENDOR                  0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS           0x0080
-#define RH_CLEAR_FEATURE        0x0100
-#define RH_SET_FEATURE          0x0300
-#define RH_SET_ADDRESS			0x0500
-#define RH_GET_DESCRIPTOR		0x0680
-#define RH_SET_DESCRIPTOR       0x0700
-#define RH_GET_CONFIGURATION	0x0880
-#define RH_SET_CONFIGURATION	0x0900
-#define RH_GET_STATE            0x0280
-#define RH_GET_INTERFACE        0x0A80
-#define RH_SET_INTERFACE        0x0B00
-#define RH_SYNC_FRAME           0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP               0x2000
-
-
-/* Hub port features */
-#define RH_PORT_CONNECTION         0x00
-#define RH_PORT_ENABLE             0x01
-#define RH_PORT_SUSPEND            0x02
-#define RH_PORT_OVER_CURRENT       0x03
-#define RH_PORT_RESET              0x04
-#define RH_PORT_POWER              0x08
-#define RH_PORT_LOW_SPEED          0x09
-#define RH_C_PORT_CONNECTION       0x10
-#define RH_C_PORT_ENABLE           0x11
-#define RH_C_PORT_SUSPEND          0x12
-#define RH_C_PORT_OVER_CURRENT     0x13
-#define RH_C_PORT_RESET            0x14  
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER       0x00
-#define RH_C_HUB_OVER_CURRENT      0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP    0x00
-#define RH_ENDPOINT_STALL          0x01
-
-/* Our Vendor Specific feature */
-#define RH_REMOVE_EP               0x00
-
-
-#define RH_ACK                     0x01
-#define RH_REQ_ERR                 -1
-#define RH_NACK                    0x00
- 
-#define min(a,b) (((a)<(b))?(a):(b))  
- 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ohci.c linux.18p8/drivers/usb/ohci.c
--- linux.vanilla/drivers/usb/ohci.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/ohci.c	Thu Jan  1 01:00:00 1970
@@ -1,1669 +0,0 @@
-/*
- * Open Host Controller Interface driver for USB.
- *
- * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
- *
- * This is the "other" host controller interface for USB.  You will
- * find this on many non-Intel based motherboards, and of course the
- * Mac.  As Linus hacked his UHCI driver together first, I modeled
- * this after his.. (it should be obvious)
- *
- * From the programming standpoint the OHCI interface seems a little
- * prettier and potentially less CPU intensive.  This remains to be
- * proven.  In reality, I don't believe it'll make one darn bit of
- * difference.  USB v1.1 is a slow bus by today's standards.
- *
- * OHCI hardware takes care of most of the scheduling of different
- * transfer types with the correct prioritization for us.
- *
- * To get started in USB, I used the "Universal Serial Bus System
- * Architecture" book by Mindshare, Inc.  It was a reasonable introduction
- * and overview of USB and the two dominant host controller interfaces
- * however you're better off just reading the real specs available
- * from www.usb.org as you'll need them to get enough detailt to
- * actually implement a HCD.  The book has many typos and omissions
- * Beware, the specs are the victim of a committee.
- *
- * This code was written with Guinness on the brain, xsnow on the desktop
- * and Orbital, Orb, Enya & Massive Attack on the CD player.  What a life!  ;) 
- *
- * No filesystems were harmed in the development of this code.
- *
- * $Id: ohci.c,v 1.26 1999/05/11 07:34:47 greg Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/malloc.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-
-#include <asm/spinlock.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include "ohci.h"
-#include "inits.h"
-
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-static int handle_apm_event(apm_event_t event);
-static int apm_resume = 0;
-#endif
-
-static struct wait_queue *ohci_configure = NULL;
-
-#ifdef OHCI_TIMER
-static struct timer_list ohci_timer;	/* timer for root hub polling */
-#endif
-
-
-static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td)
-{
-	unsigned int status;
-
-	status = td->info & OHCI_TD_CC;
-
-	/* TODO Debugging code for TD failures goes here */
-
-	return status;
-} /* ohci_td_result() */
-
-
-static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED;
-
-/*
- * Add a TD to the end of the TD list on a given ED.  If td->next_td
- * points to any more TDs, they will be added as well (naturally).
- * Otherwise td->next_td must be 0.
- * 
- * The SKIP flag will be cleared after this function.
- *
- * Important!  This function needs locking and atomicity as it works
- * in parallel with the HC's DMA.  Locking ohci_edtd_lock while using
- * the function is a must.
- *
- * This function can be called by the interrupt handler.
- */
-static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed)
-{
-	/* don't let the HC pull anything from underneath us */
-	ed->status |= OHCI_ED_SKIP;
-
-	if (ed_head_td(ed) == 0) {	/* empty list, put it on the head */
-		set_ed_head_td(ed, virt_to_bus(td));
-		ed->tail_td = 0;
-	} else {
-		struct ohci_td *tail, *head;
-		head = (ed_head_td(ed) == 0) ? NULL : bus_to_virt(ed_head_td(ed));
-		tail = (ed->tail_td == 0) ? NULL : bus_to_virt(ed->tail_td);
-		if (!tail) {	/* no tail, single element list */
-			td->next_td = head->next_td;
-			head->next_td = virt_to_bus(td);
-			ed->tail_td = virt_to_bus(td);
-		} else {	/* append to the list */
-			td->next_td = tail->next_td;
-			tail->next_td = virt_to_bus(td);
-			ed->tail_td = virt_to_bus(td);
-		}
-	}
-
-	/* save the ED link in each of the TDs added */
-	td->ed = ed;
-	while (td->next_td != 0) {
-		td = bus_to_virt(td->next_td);
-		td->ed = ed;
-	}
-
-	/* turn off the SKIP flag */
-	ed->status &= ~OHCI_ED_SKIP;
-} /* ohci_add_td_to_ed() */
-
-
-inline void ohci_start_control(struct ohci *ohci)
-{
-	/* tell the HC to start processing the control list */
-	writel(OHCI_CMDSTAT_CLF, &ohci->regs->cmdstatus);
-}
-
-inline void ohci_start_bulk(struct ohci *ohci)
-{
-	/* tell the HC to start processing the bulk list */
-	writel(OHCI_CMDSTAT_BLF, &ohci->regs->cmdstatus);
-}
-
-inline void ohci_start_periodic(struct ohci *ohci)
-{
-	/* enable processing periodc transfers starting next frame */
-	writel_set(OHCI_USB_PLE, &ohci->regs->control);
-}
-
-inline void ohci_start_isoc(struct ohci *ohci)
-{
-	/* enable processing isoc. transfers starting next frame */
-	writel_set(OHCI_USB_IE, &ohci->regs->control);
-}
-
-/*
- * Add an ED to the hardware register ED list pointed to by hw_listhead_p
- */
-static void ohci_add_ed_to_hw(struct ohci_ed *ed, void* hw_listhead_p)
-{
-	__u32 listhead;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ohci_edtd_lock, flags);
-	
-	listhead = readl(hw_listhead_p);
-
-	/* if the list is not empty, insert this ED at the front */
-	/* XXX should they go on the end? */
-	if (listhead) {
-		ed->next_ed = listhead;
-	}
-
-	/* update the hardware listhead pointer */
-	writel(virt_to_bus(ed), hw_listhead_p);
-
-	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
-} /* ohci_add_ed() */
-
-
-/*
- *  Put another control ED on the controller's list
- */
-void ohci_add_control_ed(struct ohci *ohci, struct ohci_ed *ed)
-{
-	ohci_add_ed_to_hw(ed, &ohci->regs->ed_controlhead);
-	ohci_start_control(ohci);
-} /* ohci_add_control_ed() */
-
-
-#if 0
-/*
- *  Put another control ED on the controller's list
- */
-void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
-{
-	ohci_add_ed_to_hw(ed, /* XXX */);
-	ohci_start_periodic(ohci);
-} /* ohci_add_control_ed() */
-#endif
-
-
-/*
- *  Remove an ED from the HC list whos bus headpointer is pointed to
- *  by hw_listhead_p
- *  
- *  Note that the SKIP bit is left on in the removed ED.
- */
-void ohci_remove_ed_from_hw(struct ohci_ed *ed, __u32* hw_listhead_p)
-{
-	unsigned long flags;
-	struct ohci_ed *cur;
-	__u32 bus_ed = virt_to_bus(ed);
-	__u32 bus_cur;
-
-	if (ed == NULL || !bus_ed)
-		return;
-
-	/* tell the controller this skip ED */
-	ed->status |= OHCI_ED_SKIP;
-
-	bus_cur = readl(hw_listhead_p);
-
-	if (bus_cur == 0)
-		return;   /* the list is already empty */
-
-	cur = bus_to_virt(bus_cur);
-
-	spin_lock_irqsave(&ohci_edtd_lock, flags);
-
-	/* if its the head ED, move the head */
-	if (bus_cur == bus_ed) {
-		writel(cur->next_ed, hw_listhead_p);
-	} else if (cur->next_ed != 0) {
-		struct ohci_ed *prev;
-
-		/* walk the list and unlink the ED if found */
-		for (;;) {
-			prev = cur;
-			cur = bus_to_virt(cur->next_ed);
-
-			if (virt_to_bus(cur) == bus_ed) {
-				/* unlink from the list */
-				prev->next_ed = cur->next_ed;
-				break;
-			}
-
-			if (cur->next_ed == 0)
-				break;
-		}
-	}
-
-	/* clear any links from the ED for safety */
-	ed->next_ed = 0;
-
-	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
-} /* ohci_remove_ed_from_hw() */
-
-/*
- *  Remove an ED from the controller's control list.  Note that the SKIP bit
- *  is left on in the removed ED.
- */
-inline void ohci_remove_control_ed(struct ohci *ohci, struct ohci_ed *ed)
-{
-	ohci_remove_ed_from_hw(ed, &ohci->regs->ed_controlhead);
-}
-
-/*
- *  Remove an ED from the controller's bulk list.  Note that the SKIP bit
- *  is left on in the removed ED.
- */
-inline void ohci_remove_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
-{
-	ohci_remove_ed_from_hw(ed, &ohci->regs->ed_bulkhead);
-}
-
-
-/*
- *  Remove a TD from the given EDs TD list.
- */
-static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
-{
-	unsigned long flags;
-	struct ohci_td *head_td;
-
-	if ((td == NULL) || (ed == NULL))
-		return;
-
-	spin_lock_irqsave(&ohci_edtd_lock, flags);
-
-	if (ed_head_td(ed) == 0)
-		return;
-
-	/* set the "skip me bit" in this ED */
-	ed->status |= OHCI_ED_SKIP;
-
-	/* XXX Assuming this list will never be circular */
-
-	head_td = bus_to_virt(ed_head_td(ed));
-	if (virt_to_bus(td) == ed_head_td(ed)) {
-		/* It's the first TD, remove it. */
-		set_ed_head_td(ed, head_td->next_td);
-	} else {
-		struct ohci_td *prev_td, *cur_td;
-
-		/* FIXME: collapse this into a nice simple loop :) */
-		if (head_td->next_td != 0) {
-			prev_td = head_td;
-			cur_td = bus_to_virt(head_td->next_td);
-			for (;;) {
-				if (td == cur_td) {
-					/* remove it */
-					prev_td->next_td = cur_td->next_td;
-					break;
-				}
-				if (cur_td->next_td == 0)
-					break;
-				prev_td = cur_td;
-				cur_td = bus_to_virt(cur_td->next_td);
-			}
-		}
-	}
-
-	td->next_td = 0;  /* remove the TDs links */
-	td->ed = NULL;
-
-	/* TODO return this TD to the pool of free TDs */
-
-	/* unset the "skip me bit" in this ED */
-	ed->status &= ~OHCI_ED_SKIP;
-
-	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
-} /* ohci_remove_td_from_ed() */
-
-
-/*
- * Get a pointer (virtual) to an available TD from the given device's
- * pool.
- *
- * Return NULL if none are left.
- */
-static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
-{
-	int idx;
-
-	for (idx=0; idx < NUM_TDS; idx++) {
-		if (!td_allocated(dev->td[idx])) {
-			struct ohci_td *new_td = &dev->td[idx];
-			/* zero out the TD */
-			memset(new_td, 0, sizeof(*new_td));
-			/* mark the new TDs as unaccessed */
-			new_td->info = OHCI_TD_CC_NEW;
-			/* mark it as allocated */
-			allocate_td(new_td);
-			return new_td;
-		}
-	}
-
-	printk("usb-ohci error: unable to allocate a TD\n");
-	return NULL;
-} /* ohci_get_free_td() */
-
-
-/*
- *  Initialize a TD
- *
- * 	dir = OHCI_TD_D_IN, OHCI_TD_D_OUT, or OHCI_TD_D_SETUP
- * 	toggle = TOGGLE_AUTO, TOGGLE_DATA0, TOGGLE_DATA1
- */
-inline struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 flags, void *data, __u32 len, void *dev_id, usb_device_irq completed)
-{
-	/* hardware fields */
-	td->info = OHCI_TD_CC_NEW |
-		(dir & OHCI_TD_D) |
-		(toggle & OHCI_TD_DT) |
-		flags;
-	td->cur_buf = (data == NULL) ? 0 : virt_to_bus(data);
-	td->buf_end = (len == 0) ? 0 : td->cur_buf + len - 1;
-
-	/* driver fields */
-	td->data = data;
-	td->dev_id = dev_id;
-	td->completed = completed;
-
-	return td;
-} /* ohci_fill_new_td() */
-
-
-/**********************************
- * OHCI interrupt list operations *
- **********************************/
-
-/*
- * Request an interrupt handler for one "pipe" of a USB device.
- * (this function is pretty minimal right now)
- *
- * At the moment this is only good for input interrupts. (ie: for a
- * mouse or keyboard)
- *
- * Period is desired polling interval in ms.  The closest, shorter
- * match will be used.  Powers of two from 1-32 are supported by OHCI.
- */
-static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
-	usb_device_irq handler, int period, void *dev_id)
-{
-	struct ohci_device *dev = usb_to_ohci(usb);
-	struct ohci_td *td;
-	struct ohci_ed *interrupt_ed;	/* endpoint descriptor for this irq */
-
-	/*
-	 * Pick a good frequency endpoint based on the requested period
-	 */
-	interrupt_ed = &dev->ohci->root_hub->ed[ms_to_ed_int(period)];
-
-	/*
-	 * Set the max packet size, device speed, endpoint number, usb
-	 * device number (function address), and type of TD.
-	 *
-	 * FIXME: Isochronous transfers need a pool of special 32 byte
-	 * TDs (32 byte aligned) in order to be supported.
-	 */
-	interrupt_ed->status = \
-		ed_set_maxpacket(usb_maxpacket(pipe)) |
-		ed_set_speed(usb_pipeslow(pipe)) |
-		usb_pipe_endpdev(pipe) |
-		OHCI_ED_F_NORM;
-
-	td = ohci_get_free_td(dev);
-	/* FIXME: check for NULL */
-
-	/* Fill in the TD */
-	ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)),
-			TOGGLE_AUTO,
-			OHCI_TD_ROUND,
-			dev->data, DATA_BUF_LEN,
-			dev_id, handler);
-	/*
-	 * TODO: be aware that OHCI won't advance out of the 4kb
-	 * page cur_buf started in.  It'll wrap around to the start
-	 * of the page...  annoying or useful? you decide.
-	 *
-	 * We should make sure dev->data doesn't cross a page...
-	 */
-
-	/* FIXME: this just guarantees that its the end of the list */
-	td->next_td = 0;
-
-	/* Linus did this. see asm/system.h; scary concept... I don't
-	 * know if its needed here or not but it won't hurt. */
-	wmb();
-
-	/*
-	 *  Put the TD onto our ED
-	 */
-	{
-		unsigned long flags;
-		spin_lock_irqsave(&ohci_edtd_lock, flags);
-		ohci_add_td_to_ed(td, interrupt_ed);
-		spin_unlock_irqrestore(&ohci_edtd_lock, flags);
-	}
-
-#if 0
-	/* Assimilate the new ED into the collective */
-	/*
-	 *  When dynamic ED allocation is done, this call will be
-	 *  useful.  For now, the correct ED already on the
-	 *  controller's proper periodic ED lists was chosen above.
-	 */
-	ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
-#else
-	/* enable periodic (interrupt) transfers on the HC */
-	ohci_start_periodic(dev->ohci);
-#endif
-
-	return 0;
-} /* ohci_request_irq() */
-
-
-/*
- * Control thread operations:
- */
-static struct wait_queue *control_wakeup;
-
-/*
- *  This is the handler that gets called when a control transaction
- *  completes.
- *
- *  This function is called from the interrupt handler.
- */
-static int ohci_control_completed(int stats, void *buffer, void *dev_id)
-{
-	wake_up(&control_wakeup);
-	return 0;
-} /* ohci_control_completed() */
-
-
-/*
- * Send or receive a control message on a "pipe"
- *
- * The cmd parameter is a pointer to the 8 byte setup command to be
- * sent.  FIXME:  This is a devrequest in usb.h.  The function
- * should be updated to accept a devrequest* instead of void*..
- *
- * A control message contains:
- *   - The command itself
- *   - An optional data phase (if len > 0)
- *   - Status complete phase
- */
-static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len)
-{
-	struct ohci_device *dev = usb_to_ohci(usb);
-	/*
-	 * ideally dev->ed should be linked into the root hub's
-	 * control_ed list and used instead of just using it directly.
-	 * This could present a problem as is with more than one
-	 * device.  (but who wants to use a keyboard AND a mouse
-	 * anyways? ;)
-	 */
-	struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
-	struct ohci_td *setup_td, *data_td, *status_td;
-	struct wait_queue wait = { current, NULL };
-
-#if 0
-	printk(KERN_DEBUG "entering ohci_control_msg %p (ohci_dev: %p) pipe 0x%x, cmd %p, data %p, len %d\n", usb, dev, pipe, cmd, data, len);
-#endif
-
-	/*
-	 * Set the max packet size, device speed, endpoint number, usb
-	 * device number (function address), and type of TD.
-	 *
-	 */
-	control_ed->status = \
-		ed_set_maxpacket(usb_maxpacket(pipe)) |
-		ed_set_speed(usb_pipeslow(pipe)) |
-		usb_pipe_endpdev(pipe) |
-		OHCI_ED_F_NORM;
-
-	/*
-	 * Build the control TD
-	 */
-
-	/* get a TD to send this control message with */
-	setup_td = ohci_get_free_td(dev);
-	/* TODO check for NULL */
-
-	/*
-	 * Set the not accessed condition code, allow odd sized data,
-	 * and set the data transfer type to SETUP.  Setup DATA always
-	 * uses a DATA0 packet.
-	 *
-	 * The setup packet contains a devrequest (usb.h) which
-	 * will always be 8 bytes long.  FIXME: the cmd parameter
-	 * should be a pointer to one of these instead of a void* !!!
-	 */
-	ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0,
-			OHCI_TD_IOC_OFF,
-			cmd, 8,		/* cmd is always 8 bytes long */
-			NULL, NULL);
-
-	/* allocate the next TD */
-	data_td = ohci_get_free_td(dev);  /* TODO check for NULL */
-
-	/* link to the next TD */
-	setup_td->next_td = virt_to_bus(data_td);
-
-	if (len > 0) {
-
-		/* build the Control DATA TD, it starts with a DATA1. */
-		ohci_fill_new_td(data_td, td_set_dir_out(usb_pipeout(pipe)),
-				TOGGLE_DATA1,
-				OHCI_TD_ROUND | OHCI_TD_IOC_OFF,
-				data, len,
-				NULL, NULL);
-
-		/*
-		 * XXX we should check that the data buffer doesn't
-		 * cross a 4096 byte boundary.  If so, it needs to be
-		 * copied into a single 4096 byte aligned area for the
-		 * OHCI's TD logic to see it all, or multiple TDs need
-		 * to be made for each page.
-		 *
-		 * It's not likely a control transfer will run into
-		 * this problem.. (famous last words)
-		 */
-
-		status_td = ohci_get_free_td(dev);  /* TODO check for NULL */
-		data_td->next_td = virt_to_bus(status_td);
-	} else {
-		status_td = data_td; /* no data_td, use it for status */
-	}
-
-	/* The control status packet always uses a DATA1 */
-	ohci_fill_new_td(status_td,
-			td_set_dir_in(usb_pipeout(pipe) | (len == 0)),
-			TOGGLE_DATA1,
-			0,
-			NULL, 0,
-			NULL, ohci_control_completed);
-	status_td->next_td = 0; /* end of TDs */
-
-	/*
-	 * Start the control transaction..
-	 */
-	current->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue(&control_wakeup, &wait);
-
-	/*
-	 * Add the chain of 2-3 control TDs to the control ED's TD list
-	 */
-	{
-		unsigned long flags;
-		spin_lock_irqsave(&ohci_edtd_lock, flags);
-		ohci_add_td_to_ed(setup_td, control_ed);
-		spin_unlock_irqrestore(&ohci_edtd_lock, flags);
-	}
-
-#if 0
-	/* complete transaction debugging output (before) */
-	printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed));
-	show_ohci_ed(control_ed);
-	printk(KERN_DEBUG " Setup TD %lx:\n", virt_to_bus(setup_td));
-	show_ohci_td(setup_td);
-	if (data_td != status_td) {
-		printk(KERN_DEBUG " Data TD %lx:\n", virt_to_bus(data_td));
-		show_ohci_td(data_td);
-	}
-	printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td));
-	show_ohci_td(status_td);
-#endif
-
-	/* Give the ED to the HC */
-	ohci_add_control_ed(dev->ohci, control_ed);
-
-	/* FIXME:
-	 * this should really check to see that the transaction completed.
-	 */
-	schedule_timeout(HZ/10);
-
-	remove_wait_queue(&control_wakeup, &wait);
-
-#if 0
-	/* complete transaction debugging output (after) */
-	printk(KERN_DEBUG " (after) Control ED:\n");
-	show_ohci_ed(control_ed);
-	printk(KERN_DEBUG " (after) Setup TD:\n");
-	show_ohci_td(setup_td);
-	if (data_td != status_td) {
-		printk(KERN_DEBUG " (after) Data TD:\n");
-		show_ohci_td(data_td);
-	}
-	printk(KERN_DEBUG " (after) Status TD:\n");
-	show_ohci_td(status_td);
-#endif
-
-	/* clean up incase it failed */
-	/* XXX only do this if their ed pointer still points to control_ed
-	 * incase they've been reclaimed and used by something else
-	 * already. -greg */
-	ohci_remove_td_from_ed(setup_td, control_ed);
-	ohci_remove_td_from_ed(data_td, control_ed);
-	ohci_remove_td_from_ed(status_td, control_ed);
-
-	/* remove the control ED */
-	ohci_remove_control_ed(dev->ohci, control_ed);
-
-#if 0
-	printk(KERN_DEBUG "leaving ohci_control_msg\n");
-#endif
-
-	return ohci_td_result(dev, status_td);
-} /* ohci_control_msg() */
-
-
-/*
- * Allocate a new USB device to be attached to an OHCI controller
- */
-static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
-{
-	struct usb_device *usb_dev;
-	struct ohci_device *dev;
-
-	/*
-	 * Allocate the generic USB device
-	 */
-	usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
-	if (!usb_dev)
-		return NULL;
-
-	memset(usb_dev, 0, sizeof(*usb_dev));
-
-	/*
-	 * Allocate an OHCI device (EDs and TDs for this device)
-	 */
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		kfree(usb_dev);
-		return NULL;
-	}
-
-	memset(dev, 0, sizeof(*dev));
-
-	/*
-	 * Link them together
-	 */
-	usb_dev->hcpriv = dev;
-	dev->usb = usb_dev;
-
-	/*
-	 * Link the device to its parent (hub, etc..) if any.
-	 */
-	usb_dev->parent = parent;
-
-	if (parent) {
-		usb_dev->bus = parent->bus;
-		dev->ohci = usb_to_ohci(parent)->ohci;
-	}
-
-	return usb_dev;
-} /* ohci_usb_allocate() */
-
-
-/*
- * Free a usb device.
- *
- * TODO This function needs to take better care of the EDs and TDs, etc.
- */
-static int ohci_usb_deallocate(struct usb_device *usb_dev)
-{
-	kfree(usb_to_ohci(usb_dev));
-	kfree(usb_dev);
-	return 0;
-}
-
-
-/*
- * functions for the generic USB driver
- */
-struct usb_operations ohci_device_operations = {
-	ohci_usb_allocate,
-	ohci_usb_deallocate,
-	ohci_control_msg,
-	ohci_request_irq,
-};
-
-
-/*
- * Reset an OHCI controller.  Returns >= 0 on success.
- *
- * Afterwards the HC will be in the "suspend" state which prevents you
- * from writing to some registers.  Bring it to the operational state
- * ASAP.
- */
-static int reset_hc(struct ohci *ohci)
-{
-	int timeout = 1000;  /* prevent an infinite loop */
-
-#if 0
-	printk(KERN_DEBUG "usb-ohci: resetting HC %p\n", ohci);
-#endif
-
-	writel(~0x0, &ohci->regs->intrdisable);    /* Disable HC interrupts */
-	writel(1, &ohci->regs->cmdstatus);	   /* HC Reset */
-	writel_mask(0x3f, &ohci->regs->control);   /* move to UsbReset state */
-
-	while ((readl(&ohci->regs->cmdstatus) & OHCI_CMDSTAT_HCR) != 0) {
-		if (!--timeout) {
-			printk("usb-ohci: USB HC reset timed out!\n");
-			return -1;
-		}
-		udelay(1);
-	}
-
-	printk(KERN_DEBUG "usb-ohci: HC %p reset.\n", ohci);
-
-	return 0;
-} /* reset_hc() */
-
-
-/*
- * Reset and start an OHCI controller.  Returns >= 0 on success.
- */
-static int start_hc(struct ohci *ohci)
-{
-	int ret = 0;
-	int fminterval;
-
-	fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
-#if 0
-	printk(KERN_DEBUG "entering start_hc %p\n", ohci);
-#endif
-
-	if (reset_hc(ohci) < 0)
-		return -1;
-
-	/* restore registers cleared by the reset */
-	writel(virt_to_bus(ohci->root_hub->hcca), &ohci->regs->hcca);
-
-	/*
-	 * XXX Should fminterval also be set here?
-	 * The spec suggests 0x2edf [11,999]. (FIXME: make this a constant)
-	 */
-	fminterval |= (0x2edf << 16);
-	writel(fminterval, &ohci->regs->fminterval);
-	/* Start periodic transfers at 90% of fminterval (fmremaining
-	 * counts down; this will put them in the first 10% of the
-	 * frame). */
-	writel((0x2edf*9)/10, &ohci->regs->periodicstart);
-
-	/*
-	 * FNO (frame number overflow) could be enabled...  they
-	 * occur every 32768 frames (every 32-33 seconds).  This is
-	 * useful for debugging and as a bus heartbeat. -greg
-	 */
-	/* Choose the interrupts we care about */
-	writel( OHCI_INTR_MIE | /* OHCI_INTR_RHSC | */
-		OHCI_INTR_WDH | OHCI_INTR_FNO,
-		&ohci->regs->intrenable);
-
-	/* Enter the USB Operational state & start the frames a flowing.. */
-	writel_set(OHCI_USB_OPER, &ohci->regs->control);
-	
-	/* Enable control lists */
-	writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control);
-
-	/* Turn on power to the root hub ports (thanks Roman!) */
-	writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status );
-
-	printk("usb-ohci: host controller operational\n");
-
-	return ret;
-} /* start_hc() */
-
-
-/*
- * Reset a root hub port
- */
-static void ohci_reset_port(struct ohci *ohci, unsigned int port)
-{
-	int status;
-
-	/* Don't allow overflows. */
-	if (port >= MAX_ROOT_PORTS) {
-		printk("usb-ohci: bad port #%d in ohci_reset_port\n", port);
-		port = MAX_ROOT_PORTS-1;
-	}
-
-	writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);  /* Reset */
-
-	/*
-	 * Wait for the reset to complete.
-	 */
-	wait_ms(10);
-
-	/* check port status to see that the reset completed */
-	status = readl(&ohci->regs->roothub.portstatus[port]);
-	if (status & PORT_PRS) {
-		/* reset failed, try harder? */
-		printk("usb-ohci: port %d reset failed, retrying\n", port);
-		writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);
-		wait_ms(50);
-	}
-
-	/* TODO we might need to re-enable the port here or is that
-	 * done elsewhere? */
-
-} /* ohci_reset_port */
-
-
-/*
- * This gets called if the connect status on the root hub changes.
- */
-static void ohci_connect_change(struct ohci * ohci, int port)
-{
-	struct usb_device *usb_dev;
-	struct ohci_device *dev;
-	/* memory I/O address of the port status register */
-	void *portaddr = &ohci->regs->roothub.portstatus[port];
-	int portstatus;	
-
-	printk(KERN_DEBUG "ohci_connect_change(%p, %d)\n", ohci, port);
-
-	/*
-	 * Because of the status change we have to forget
-	 * everything we think we know about the device
-	 * on this root hub port.  It may have changed.
-	 */
-	usb_disconnect(ohci->root_hub->usb->children + port);
-
-	portstatus = readl(portaddr);
-
-	/* disable the port if nothing is connected */
-	if (!(portstatus & PORT_CCS)) {
-		writel(PORT_CCS, portaddr);
-		return;
-	}
-
-	/*
-	 * Allocate a device for the new thingy that's been attached
-	 */
-	usb_dev = ohci_usb_allocate(ohci->root_hub->usb);
-	dev = usb_dev->hcpriv;
-
-	dev->ohci = ohci;
-
-	usb_connect(dev->usb);
-
-	/* link it into the bus's device tree */
-	ohci->root_hub->usb->children[port] = usb_dev;
-
-	wait_ms(200); /* wait for powerup; XXX is this needed? */
-	ohci_reset_port(ohci, port);
-
-	/* Get information on speed by using LSD */
-	usb_dev->slow = readl(portaddr) & PORT_LSDA ? 1 : 0;
-
-	/*
-	 * Do generic USB device tree processing on the new device.
-	 */
-	usb_new_device(usb_dev);
-
-} /* ohci_connect_change() */
-
-
-/*
- * This gets called when the root hub configuration
- * has changed.  Just go through each port, seeing if
- * there is something interesting happening.
- */
-static void ohci_check_configuration(struct ohci *ohci)
-{
-	struct ohci_regs *regs = ohci->regs;
-	int num = 0;
-	int maxport = readl(&ohci->regs->roothub) & 0xff;
-
-#if 1
-	printk(KERN_DEBUG "entering ohci_check_configuration %p\n", ohci);
-#endif
-
-	do {
-		if (readl(&regs->roothub.portstatus[num]) & PORT_CSC) {
-			/* reset the connect status change bit */
-			writel(PORT_CSC, &regs->roothub.portstatus[num]);
-			/* check the port for a nifty device */
-			ohci_connect_change(ohci, num);
-		}
-	} while (++num < maxport);
-
-#if 0
-	printk(KERN_DEBUG "leaving ohci_check_configuration %p\n", ohci);
-#endif
-} /* ohci_check_configuration() */
-
-
-
-/*
- * Check root hub port status and wake the control thread up if
- * anything has changed.
- *
- * This function is called from the interrupt handler.
- */
-static void ohci_root_hub_events(struct ohci *ohci)
-{
-	if (waitqueue_active(&ohci_configure)) {
-		int num = 0;
-		int maxport = ohci->root_hub->usb->maxchild;
-
-		do {
-			if (readl(&ohci->regs->roothub.portstatus[num]) &
-					PORT_CSC) {
-				if (waitqueue_active(&ohci_configure))
-					wake_up(&ohci_configure);
-				return;
-			}
-		} while (++num < maxport);
-	}
-} /* ohci_root_hub_events() */
-
-
-/*
- * The done list is in reverse order; we need to process TDs in the
- * order they were finished (FIFO).  This function builds the FIFO
- * list using the next_dl_td pointer.
- *
- * This function originally by Roman Weissgaerber (weissg@vienna.at)
- *
- * This function is called from the interrupt handler.
- */
-static struct ohci_td * ohci_reverse_donelist(struct ohci * ohci)
-{
-	__u32 td_list_hc;
-	struct ohci_hcca *hcca = ohci->root_hub->hcca;
-	struct ohci_td *td_list = NULL;
-	struct ohci_td *td_rev = NULL;
-  	
-	td_list_hc = hcca->donehead & 0xfffffff0;
-	hcca->donehead = 0;
-
- 	while(td_list_hc) {
-		td_list = (struct ohci_td *) bus_to_virt(td_list_hc);
-		td_list->next_dl_td = td_rev;
-			
-		td_rev = td_list;
-		td_list_hc = td_list->next_td & 0xfffffff0;
-	}
-
-	return td_list;
-} /* ohci_reverse_donelist() */
-
-
-/*
- * Collect this interrupt's goodies off of the list of finished TDs
- * that the OHCI controller is kind enough to setup for us.
- *
- * This function is called from the interrupt handler.
- */
-static void ohci_reap_donelist(struct ohci *ohci)
-{
-	struct ohci_td *td;		/* used for walking the list */
-
-	spin_lock(&ohci_edtd_lock);
-
-	/* create the FIFO ordered donelist */
-	td = ohci_reverse_donelist(ohci);
-
-	while (td != NULL) {
-		struct ohci_td *next_td = td->next_dl_td;
-
-		/* FIXME: munge td->info into a future standard status format */
-		/* Check if TD should be re-queued */
-		if ((td->completed != NULL) &&
-		    (td->completed(OHCI_TD_CC_GET(td->info), td->data, td->dev_id)))
-		{
-			/* Mark the TD as active again:
-			 * Set the not accessed condition code
-			 * FIXME: should this reset OHCI_TD_ERRCNT?
-			 */
-			td->info |= OHCI_TD_CC_NEW;
-
-			/* point it back to the start of the data buffer */
-			td->cur_buf = virt_to_bus(td->data);
-
-			/* XXX disabled for debugging reasons right now.. */
-			/* insert it back on its ED */
-			ohci_add_td_to_ed(td, td->ed);
-		} else {
-			/* return it to the pool of free TDs */
-			ohci_free_td(td);
-		}
-
-		td = next_td;
-	}
-
-	spin_unlock(&ohci_edtd_lock);
-} /* ohci_reap_donelist() */
-
-
-#if 0
-static int in_int = 0;
-#endif
-/*
- * Get annoyed at the controller for bothering us.
- * This pretty much follows the OHCI v1.0a spec, section 5.3.
- */
-static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
-{
-	struct ohci *ohci = __ohci;
-	struct ohci_regs *regs = ohci->regs;
-	struct ohci_hcca *hcca = ohci->root_hub->hcca;
-	__u32 status, context;
-
-#if 0
-	/* for debugging to keep IRQs from running away. */
-	if (in_int >= 2)
-		return;
-	++in_int;
-	return;
-#endif
-
-	/* Save the status of the interrupts that are enabled */
-	status = readl(&regs->intrstatus);
-	status &= readl(&regs->intrenable);
-
-
-	/* make context = the interrupt status bits that we care about */
-	if (hcca->donehead != 0) {
-		context = OHCI_INTR_WDH;   /* hcca donehead needs processing */
-		if (hcca->donehead & 1) {
-			context |= status;  /* other status change to check */
-		}
-	} else {
-		context = status;
-		if (!context) {
-			/* TODO increment a useless interrupt counter here */
-			return;
-		}
-	}
-
-	/* Disable HC interrupts */
-	writel(OHCI_INTR_MIE, &regs->intrdisable);
-
-	/* Process the done list */
-	if (context & OHCI_INTR_WDH) {
-		/* See which TD's completed.. */
-		ohci_reap_donelist(ohci);
-
-		/* reset the done queue and tell the controller */
-		hcca->donehead = 0;
-		writel(OHCI_INTR_WDH, &regs->intrstatus);
-
-		context &= ~OHCI_INTR_WDH;  /* mark this as checked */
-	}
-
-	/* Process any root hub status changes */
-	if (context & OHCI_INTR_RHSC) {
-		/* Wake the thread to process root hub events */
-		if (waitqueue_active(&ohci_configure))
-			wake_up(&ohci_configure);
-
-		writel(OHCI_INTR_RHSC, &regs->intrstatus);
-		/* 
-		 * Don't unset RHSC in context; it should be disabled.
-		 * The control thread will re-enable it after it has
-		 * checked the root hub status.
-		 */
-	} else {
-		/* check the root hub status anyways. Some controllers
-		 * might not generate the interrupt properly. (?) */
-		ohci_root_hub_events(ohci);
-	}
-
-	/* Check those "other" pesky bits */
-	if (context & (OHCI_INTR_FNO)) {
-		writel(OHCI_INTR_FNO, &regs->intrstatus);
-		context &= ~OHCI_INTR_FNO;  /* mark this as checked */
-	}
-	if (context & OHCI_INTR_SO) {
-		writel(OHCI_INTR_SO, &regs->intrstatus);
-		context &= ~OHCI_INTR_SO;  /* mark this as checked */
-	}
-	if (context & OHCI_INTR_RD) {
-		writel(OHCI_INTR_RD, &regs->intrstatus);
-		context &= ~OHCI_INTR_RD;  /* mark this as checked */
-	}
-	if (context & OHCI_INTR_UE) {
-		/* FIXME: need to have the control thread reset the
-		 * controller now and keep a count of unrecoverable
-		 * errors.  If there are too many, it should just shut
-		 * the broken controller down entirely. */
-		writel(OHCI_INTR_UE, &regs->intrstatus);
-		context &= ~OHCI_INTR_UE;  /* mark this as checked */
-	}
-	if (context & OHCI_INTR_OC) {
-		writel(OHCI_INTR_OC, &regs->intrstatus);
-		context &= ~OHCI_INTR_OC;  /* mark this as checked */
-	}
-
-	/* Mask out any remaining unprocessed interrupts so we don't
-	 * get any more of them. */
-	if (context & ~OHCI_INTR_MIE) {
-		writel(context, &regs->intrdisable);
-	}
-
-	/* Re-enable HC interrupts */
-	writel(OHCI_INTR_MIE, &regs->intrenable);
-
-} /* ohci_interrupt() */
-
-
-/*
- * Allocate the resources required for running an OHCI controller.
- * Host controller interrupts must not be running while calling this
- * function or the penguins will get angry.
- *
- * The mem_base parameter must be the usable -virtual- address of the
- * host controller's memory mapped I/O registers.
- */
-static struct ohci *alloc_ohci(void* mem_base)
-{
-	int i;
-	struct ohci *ohci;
-	struct usb_bus *bus;
-	struct ohci_device *dev;
-	struct usb_device *usb;
-
-#if 0
-	printk(KERN_DEBUG "entering alloc_ohci %p\n", mem_base);
-#endif
-
-	ohci = kmalloc(sizeof(*ohci), GFP_KERNEL);
-	if (!ohci)
-		return NULL;
-
-	memset(ohci, 0, sizeof(*ohci));
-
-	ohci->irq = -1;
-	ohci->regs = mem_base;
-	INIT_LIST_HEAD(&ohci->interrupt_list);
-
-	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
-	if (!bus)
-		return NULL;
-
-	memset(bus, 0, sizeof(*bus));
-
-	ohci->bus = bus;
-	bus->hcpriv = ohci;
-	bus->op = &ohci_device_operations;
-
-	/*
-	 * Allocate the USB device structure and root hub.
-	 *
-	 * Here we allocate our own root hub and TDs as well as the
-	 * OHCI host controller communications area.  The HCCA is just
-	 * a nice pool of memory with pointers to endpoint descriptors
-	 * for the different interrupts.
-	 */
-	usb = ohci_usb_allocate(NULL);
-	if (!usb)
-		return NULL;
-
-	dev = ohci->root_hub = usb_to_ohci(usb);
-
-	usb->bus = bus;
-
-	/* Initialize the root hub */
-	dev->ohci = ohci;    /* link back to the controller */
-
-	/*
-	 * Allocate the Host Controller Communications Area on a 256
-	 * byte boundary.  XXX take the easy way out and just grab a
-	 * page as that's guaranteed to have a nice boundary.
-	 */
-	dev->hcca = (struct ohci_hcca *) __get_free_page(GFP_KERNEL);
-
-	/* Tell the controller where the HCCA is */
-	writel(virt_to_bus(dev->hcca), &ohci->regs->hcca);
-
-#if 0
-	printk(KERN_DEBUG "usb-ohci: HCCA allocated at %p (bus %p)\n", dev->hcca, (void*)virt_to_bus(dev->hcca));
-#endif
-
-	/* Get the number of ports on the root hub */
-	usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
-	if (usb->maxchild > MAX_ROOT_PORTS) {
-		printk("usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS);
-		usb->maxchild = MAX_ROOT_PORTS;
-	}
-	if (usb->maxchild < 1) {
-		printk("usb-ohci: Less than one root hub port? Impossible!\n");
-		usb->maxchild = 1;
-	}
-	printk("usb-ohci: %d root hub ports found\n", usb->maxchild);
-
-	/*
-	 * Initialize the ED polling "tree" (for simplicity's sake in
-	 * this driver many nodes in the tree will be identical)
-	 */
-	dev->ed[ED_INT_32].next_ed = virt_to_bus(&dev->ed[ED_INT_16]);
-	dev->ed[ED_INT_16].next_ed = virt_to_bus(&dev->ed[ED_INT_8]);
-	dev->ed[ED_INT_8].next_ed = virt_to_bus(&dev->ed[ED_INT_4]);
-	dev->ed[ED_INT_4].next_ed = virt_to_bus(&dev->ed[ED_INT_2]);
-	dev->ed[ED_INT_2].next_ed = virt_to_bus(&dev->ed[ED_INT_1]);
-
-	/*
-	 * Initialize the polling table to call interrupts at the
-	 * intended intervals.
-	 */
-	dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]);
-	for (i = 1; i < NUM_INTS; i++) {
-		if (i & 1)
-			dev->hcca->int_table[i] =
-				virt_to_bus(&dev->ed[ED_INT_16]);
-		else if (i & 2)
-			dev->hcca->int_table[i] =
-				virt_to_bus(&dev->ed[ED_INT_8]);
-		else if (i & 4)
-			dev->hcca->int_table[i] =
-				virt_to_bus(&dev->ed[ED_INT_4]);
-		else if (i & 8)
-			dev->hcca->int_table[i] =
-				virt_to_bus(&dev->ed[ED_INT_2]);
-		else if (i & 16)
-			dev->hcca->int_table[i] =
-				virt_to_bus(&dev->ed[ED_INT_1]);
-	}
-
-	/*
-	 * Tell the controller where the control and bulk lists are
-	 * The lists start out empty.
-	 */
-	writel(0, &ohci->regs->ed_controlhead);
-	writel(0, &ohci->regs->ed_bulkhead);
-	/*
-	writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead);
-	writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead);
-	*/
-
-#if 0
-	printk(KERN_DEBUG "alloc_ohci(): controller\n");
-	show_ohci_status(ohci);
-#endif
-
-#if 0
-	printk(KERN_DEBUG "leaving alloc_ohci %p\n", ohci);
-#endif
-
-	return ohci;
-} /* alloc_ohci() */
-
-
-/*
- * De-allocate all resoueces..
- */
-static void release_ohci(struct ohci *ohci)
-{
-	printk(KERN_DEBUG "entering release_ohci %p\n", ohci);
-
-#ifdef OHCI_TIMER
-	/* stop our timer */
-	del_timer(&ohci_timer);
-#endif
-	if (ohci->irq >= 0) {
-		free_irq(ohci->irq, ohci);
-		ohci->irq = -1;
-	}
-
-	/* stop all OHCI interrupts */
-	writel(~0x0, &ohci->regs->intrdisable);
-
-	if (ohci->root_hub) {
-		/* ensure that HC is stopped before releasing the HCCA */
-		writel(OHCI_USB_SUSPEND, &ohci->regs->control);
-		free_page((unsigned long) ohci->root_hub->hcca);
-		kfree(ohci->root_hub);
-		ohci->root_hub->hcca = NULL;
-		ohci->root_hub = NULL;
-	}
-
-	/* unmap the IO address space */
-	iounmap(ohci->regs);
-
-	kfree(ohci);
-
-	MOD_DEC_USE_COUNT;
-
-	/* If the ohci itself were dynamic we'd free it here */
-
-	printk(KERN_DEBUG "usb-ohci: HC resources released.\n");
-} /* release_ohci() */
-
-
-/*
- * USB OHCI control thread
- */
-static int ohci_control_thread(void * __ohci)
-{
-	struct ohci *ohci = (struct ohci *)__ohci;
-
-	/*
-	 * I'm unfamiliar with the SMP kernel locking.. where should
-	 * this be released and what does it do?  -greg
-	 */
-	lock_kernel();
-
-	/*
-	 * This thread doesn't need any user-level access,
-	 * so get rid of all of our resources..
-	 */
-	printk("ohci_control_thread code at %p\n", &ohci_control_thread);
-	exit_mm(current);
-	exit_files(current);
-	exit_fs(current);
-
-	strcpy(current->comm, "ohci-control");
-
-	/*
-	 * Damn the torpedoes, full speed ahead
-	 */
-	if (start_hc(ohci) < 0) {
-		printk("usb-ohci: failed to start the controller\n");
-		release_ohci(ohci);
-		printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
-		return 0;
-	}
-
-	for(;;) {
-		siginfo_t info;
-		int unsigned long signr;
-
-		wait_ms(200);
-
-		/* check the root hub configuration for changes. */
-		ohci_check_configuration(ohci);
-
-		/* re-enable root hub status change interrupts. */
-#if 0
-		writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
-#endif
-
-		printk(KERN_DEBUG "ohci-control thread sleeping\n");
-		interruptible_sleep_on(&ohci_configure);
-#ifdef CONFIG_APM
-		if (apm_resume) {
-			apm_resume = 0;
-			if (start_hc(ohci) < 0)
-				break;
-			continue;
-		}
-#endif
-
-		/*
-		 * If we were woken up by a signal, see if its useful,
-		 * otherwise exit.
-		 */
-		if (signal_pending(current)) {
-			/* sending SIGUSR1 makes us print out some info */
-			spin_lock_irq(&current->sigmask_lock);
-			signr = dequeue_signal(&current->blocked, &info);
-			spin_unlock_irq(&current->sigmask_lock);
-
-			if(signr == SIGUSR1) {
-				/* FIXME: have it do a full ed/td queue dump */
-				printk(KERN_DEBUG "OHCI status dump:\n");
-				show_ohci_status(ohci);
-			} else {
-				/* unknown signal, exit the thread */
-				break;
-			}
-		}
-	} /* for (;;) */
-
-	reset_hc(ohci);
-	release_ohci(ohci);
-
-	printk(KERN_DEBUG "leaving ohci_control_thread %p\n", __ohci);
-
-	return 0;
-} /* ohci_control_thread() */
-
-
-#ifdef CONFIG_APM
-static int handle_apm_event(apm_event_t event)
-{
-	static int down = 0;
-
-	switch (event) {
-	case APM_SYS_SUSPEND:
-	case APM_USER_SUSPEND:
-		if (down) {
-			printk(KERN_DEBUG "usb-ohci: received extra suspend event\n");
-			break;
-		}
-		down = 1;
-		break;
-	case APM_NORMAL_RESUME:
-	case APM_CRITICAL_RESUME:
-		if (!down) {
-			printk(KERN_DEBUG "usb-ohci: received bogus resume event\n");
-			break;
-		}
-		down = 0;
-		if (waitqueue_active(&ohci_configure)) {
-			apm_resume = 1;
-			wake_up(&ohci_configure);
-		}
-		break;
-	}
-	return 0;
-} /* handle_apm_event() */
-#endif
-
-
-#ifdef OHCI_TIMER
-/*
- * Inspired by Iñaky's driver.  This function is a timer routine that
- * is called OHCI_TIMER_FREQ times per second.  It polls the root hub
- * for status changes as on my system things are acting a bit odd at
- * the moment..
- */
-static void ohci_timer_func (unsigned long ohci_ptr)
-{
-	struct ohci *ohci = (struct ohci*)ohci_ptr;
-
-	ohci_root_hub_events(ohci);
-
-	/* press the snooze button... */
-	mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ));
-} /* ohci_timer_func() */
-#endif
-
-
-/*
- * Increment the module usage count, start the control thread and
- * return success if the controller is good.
- */
-static int found_ohci(int irq, void* mem_base)
-{
-	int retval;
-	struct ohci *ohci;
-
-#if 0
-	printk(KERN_DEBUG "entering found_ohci %d %p\n", irq, mem_base);
-#endif
-
-	/* Allocate the running OHCI structures */
-	ohci = alloc_ohci(mem_base);
-	if (!ohci) {
-		return -ENOMEM;
-	}
-
-#ifdef OHCI_TIMER
-	init_timer(&ohci_timer);
-	ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ);
-	ohci_timer.data = (unsigned long)ohci;
-	ohci_timer.function = ohci_timer_func;
-#endif
-
-	retval = -EBUSY;
-	if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
-		int pid;
-
-		ohci->irq = irq;
-
-#if 0
-		printk(KERN_DEBUG "usb-ohci: starting ohci-control thread\n");
-#endif
-
-		/* fork off the handler */
-		pid = kernel_thread(ohci_control_thread, ohci,
-				CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-		if (pid >= 0) {
-			return 0;
-		}
-
-		retval = pid;
-	} else {
-		printk("usb-ohci: Couldn't allocate interrupt %d\n", irq);
-	}
-	release_ohci(ohci);
-
-#if 0
-	printk(KERN_DEBUG "leaving found_ohci %d %p\n", irq, mem_base);
-#endif
-
-	return retval;
-} /* found_ohci() */
-
-
-/*
- * If this controller is for real, map the IO memory and proceed
- */
-static int init_ohci(struct pci_dev *dev)
-{
-	unsigned long mem_base = dev->base_address[0];
-	
-	/* If its OHCI, its memory */
-	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
-		return -ENODEV;
-
-	/* Get the memory address and map it for IO */
-	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
-
-	/* no interrupt won't work... */
-	if (dev->irq == 0) {
-		printk("usb-ohci: no irq assigned? check your BIOS settings.\n");
-		return -ENODEV;
-	}
-
-	/* 
-	 * FIXME ioremap_nocache isn't implemented on all CPUs (such
-	 * as the Alpha) [?]  What should I use instead...
-	 *
-	 * The iounmap() is done on in release_ohci.
-	 */
-	mem_base = (unsigned long) ioremap_nocache(mem_base, 4096);
-
-	if (!mem_base) {
-		printk("Error mapping OHCI memory\n");
-		return -EFAULT;
-	}
-        MOD_INC_USE_COUNT;
-
-	if (found_ohci(dev->irq, (void *) mem_base) < 0) {
-		MOD_DEC_USE_COUNT;
-		return -1;
-	}
-
-	return 0;
-} /* init_ohci() */
-
-#ifdef MODULE
-/*
- *  Clean up when unloading the module
- */
-void cleanup_module(void)
-{
-#ifdef CONFIG_APM
-	apm_unregister_callback(&handle_apm_event);
-#endif
-#ifdef CONFIG_USB_MOUSE
-	usb_mouse_cleanup();
-#endif
-	printk("usb-ohci: module unloaded\n");
-}
-
-#define ohci_init init_module
-
-#endif
-
-
-/* TODO this should be named following Linux convention and go in pci.h */
-#define PCI_CLASS_SERIAL_USB_OHCI ((PCI_CLASS_SERIAL_USB << 8) | 0x0010)
-
-/*
- * Search the PCI bus for an OHCI USB controller and set it up
- *
- * If anyone wants multiple controllers this will need to be
- * updated..  Right now, it just picks the first one it finds.
- */
-int ohci_init(void)
-{
-	int retval;
-	struct pci_dev *dev = NULL;
-	/*u8 type;*/
-
-	if (sizeof(struct ohci_device) > 4096) {
-		printk("usb-ohci: struct ohci_device to large\n");
-		return -ENODEV;
-	}
-
-	printk("OHCI USB Driver loading\n");
-
-	retval = -ENODEV;
-	for (;;) {
-		/* Find an OHCI USB controller */
-		dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev);
-		if (!dev)
-			break;
-
-		/* Verify that its OpenHCI by checking for MMIO */
-		/* pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
-		if (!type)
-			continue; */
-
-		/* Ok, set it up */
-		retval = init_ohci(dev);
-		if (retval < 0)
-			continue;
-
-		/* TODO check module params here to determine what to load */
-
-#ifdef CONFIG_USB_MOUSE
-		usb_mouse_init();
-#endif
-#ifdef CONFIG_USB_KBD		
-		usb_kbd_init();
-#endif		
-		hub_init();
-#ifdef CONFIG_USB_AUDIO		
-		usb_audio_init();
-#endif		
-#ifdef CONFIG_APM
-		apm_register_callback(&handle_apm_event);
-#endif
-
-		return 0; /* no error */
-	}
-	return retval;
-} /* ohci_init */
-
-/* vim:sw=8
- */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ohci.h linux.18p8/drivers/usb/ohci.h
--- linux.vanilla/drivers/usb/ohci.h	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/ohci.h	Thu Jan  1 01:00:00 1970
@@ -1,349 +0,0 @@
-#ifndef __LINUX_OHCI_H
-#define __LINUX_OHCI_H
-
-/*
- * Open Host Controller Interface data structures and defines.
- *
- * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
- *
- * $Id: ohci.h,v 1.15 1999/05/09 23:25:49 greg Exp $
- */
-
-#include <linux/list.h>
-#include <asm/io.h>
-
-#include "usb.h"
-
-struct ohci_ed;
-
-/*
- * Each TD must be aligned on a 16-byte boundary.  From the OHCI v1.0 spec
- * it does not state that TDs must be contiguious in memory (due to the
- * use of the next_td field).  This gives us extra room at the end of a
- * TD for our own driver specific data.
- *
- * This structure's size must be a multiple of 16 bytes. ?? no way, I
- * don't see why.  Alignment should be all that matters.
- */
-struct ohci_td {
-    	/* OHCI Hardware fields */
-    	__u32 info;		/* TD status & type flags */
-	__u32 cur_buf;		/* Current Buffer Pointer (bus address) */
-	__u32 next_td;		/* Next TD Pointer (bus address) */
-	__u32 buf_end;		/* Memory Buffer End Pointer (bus address) */
-
-	/* Driver specific fields */
-	struct ohci_ed *ed;		/* address of the ED this TD is on */
-	struct ohci_td *next_dl_td;	/* used during donelist processing */
-	void *data;			/* virt. address of the the buffer */
-	usb_device_irq completed;	/* Completion handler routine */
-	int allocated;			/* boolean: is this TD allocated? */
-
-	/* User or Device class driver specific fields */
-	void *dev_id;	/* user defined pointer passed to irq handler */
-} __attribute((aligned(16)));
-
-#define OHCI_TD_ROUND	(1 << 18)	/* buffer rounding bit */
-#define OHCI_TD_D	(3 << 19)	/* direction of xfer: */
-#define OHCI_TD_D_IN	(2 << 19)
-#define OHCI_TD_D_OUT	(1 << 19)
-#define OHCI_TD_D_SETUP (0 << 19)
-#define td_set_dir_in(d)	((d) ? OHCI_TD_D_IN : OHCI_TD_D_OUT )
-#define td_set_dir_out(d)	((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN )
-#define OHCI_TD_IOC_DELAY (7 << 21)	/* frame delay allowed before int. */
-#define OHCI_TD_IOC_OFF	(OHCI_TD_IOC_DELAY)	/* no interrupt on complete */
-#define OHCI_TD_DT	(3 << 24)	/* data toggle bits */
-#define TOGGLE_AUTO	(0 << 24)	/* automatic (from the ED) */
-#define TOGGLE_DATA0	(2 << 24)	/* force Data0 */
-#define TOGGLE_DATA1	(3 << 24)	/* force Data1 */
-#define td_force_toggle(b)	(((b) | 2) << 24)
-#define OHCI_TD_ERRCNT	(3 << 26)	/* error count */
-#define td_errorcount(td)	(((td).info >> 26) & 3)
-#define OHCI_TD_CC	(0xf << 28)	/* condition code */
-#define OHCI_TD_CC_GET(td_i) (((td_i) >> 28) & 0xf)
-#define OHCI_TD_CC_NEW	(OHCI_TD_CC)	/* set this on all unaccessed TDs! */
-#define td_cc_notaccessed(td)	(((td).info >> 29) == 7)
-#define td_cc_accessed(td)	(((td).info >> 29) != 7)
-#define td_cc_noerror(td)	((((td).info) & OHCI_TD_CC) == 0)
-#define td_active(td)	(!td_cc_noerror((td)) && (td_errorcount((td)) < 3))
-#define td_done(td)	(td_cc_noerror((td)) || (td_errorcount((td)) == 3))
-
-#define td_allocated(td)	((td).allocated)
-#define allocate_td(td)		((td)->allocated = 1)
-#define ohci_free_td(td)	((td)->allocated = 0)
-
-
-/*
- * The endpoint descriptors also requires 16-byte alignment
- */
-struct ohci_ed {
-	/* OHCI hardware fields */
-	__u32 status;
-	__u32 tail_td;	/* TD Queue tail pointer */
-	__u32 _head_td;	/* TD Queue head pointer, toggle carry & halted bits */
-	__u32 next_ed;	/* Next ED */
-} __attribute((aligned(16)));
-
-/* get the head_td */
-#define ed_head_td(ed)	((ed)->_head_td & 0xfffffff0)
-
-/* save the carry flag while setting the head_td */
-#define set_ed_head_td(ed, td)	((ed)->_head_td = (td) | ((ed)->_head_td & 3))
-
-#define OHCI_ED_SKIP	(1 << 14)
-#define OHCI_ED_MPS	(0x7ff << 16)
-/* FIXME: should cap at the USB max packet size [0x4ff] */
-#define ed_set_maxpacket(s)	(((s) << 16) & OHCI_ED_MPS)
-#define OHCI_ED_F_NORM	(0)
-#define OHCI_ED_F_ISOC	(1 << 15)
-#define ed_set_type_isoc(i)	((i) ? OHCI_ED_F_ISOC : OHCI_ED_F_NORM)
-#define OHCI_ED_S_LOW	(1 << 13)
-#define OHCI_ED_S_HIGH	(0)
-#define ed_set_speed(s)		((s) ? OHCI_ED_S_LOW : OHCI_ED_S_HIGH)
-#define OHCI_ED_D	(3 << 11)
-#define OHCI_ED_D_IN	(2 << 11)
-#define OHCI_ED_D_OUT	(1 << 11)
-#define ed_set_dir_in(d)	((d) ? OHCI_ED_D_IN : OHCI_ED_D_OUT)
-#define ed_set_dir_out(d)	((d) ? OHCI_ED_D_OUT : OHCI_ED_D_IN)
-#define OHCI_ED_EN	(0xf << 7)
-#define OHCI_ED_FA	(0x7f)
-
-
-/* NOTE: bits 27-31 of the status dword are reserved for the driver */
-/*
- * We'll use this status flag for to mark if an ED is in use by the
- * driver or not.  If the bit is set, it is used.
- *
- * FIXME: implement this!
- */
-#define ED_USED	(1 << 31)
-
-/*
- * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. that the host controller is
- * told the base address of.  It must be 256-byte aligned.
- */
-#define NUM_INTS 32	/* part of the OHCI standard */
-struct ohci_hcca {
-    	__u32	int_table[NUM_INTS];	/* Interrupt ED table */
-	__u16	frame_no;		/* current frame number */
-	__u16	pad1;			/* set to 0 on each frame_no change */
-	__u32	donehead;		/* info returned for an interrupt */
-	u8	reserved_for_hc[116];
-} __attribute((aligned(256)));
-
-/*
- * The TD entries here are pre-allocated as Linus did with his simple
- * UHCI implementation.  With the current state of this driver that
- * shouldn't be a problem.  However if someone ever connects 127
- * supported devices to this driver and tries to use them all at once:
- * 	a)  They're insane!
- * 	b)  They should code in dynamic allocation
- */
-struct ohci;
-
-/*
- *  Warning: These constants must not be so large as to cause the
- *  ohci_device structure to exceed one 4096 byte page.  Or "weird
- *  things will happen" as the alloc_ohci() function assumes that
- *  its less than one page.  (FIXME)
- */
-#define NUM_TDS	32		/* num of preallocated transfer descriptors */
-#define DATA_BUF_LEN 16		/* num of unsigned long's for the data buf */
-
-/*
- * For this "simple" driver we only support a single ED for each
- * polling rate.
- *
- * Later on this driver should be extended to use a full tree of EDs
- * so that there can be 32 different 32ms polling frames, etc.
- * Individual devices shouldn't need as many as the root hub in that
- * case; complicating how things are done at the moment.
- *
- * Bulk and Control transfers hang off of their own ED lists.
- */
-#define NUM_EDS 16		/* num of preallocated endpoint descriptors */
-
-#define ohci_to_usb(ohci)	((ohci)->usb)
-#define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
-
-/* The usb_device must be first! */
-struct ohci_device {
-    	struct usb_device	*usb;
-
-	struct ohci		*ohci;
-	struct ohci_hcca 	*hcca;		/* OHCI mem. mapped IO area */
-
-	struct ohci_ed		ed[NUM_EDS];	/* Endpoint Descriptors */
-	struct ohci_td		td[NUM_TDS];	/* Transfer Descriptors */
-
-	unsigned long		data[DATA_BUF_LEN];
-};
-
-/* .... */
-
-#define ED_INT_1	0
-#define ED_INT_2	1
-#define ED_INT_4	2
-#define ED_INT_8	3
-#define ED_INT_16	4
-#define ED_INT_32	5
-#define ED_CONTROL	6
-#define ED_BULK		7
-#define ED_ISO		ED_INT_1	/* same as 1ms interrupt queue */
-#define ED_FIRST_AVAIL  8		/* first non-reserved ED */
-
-/*
- * Given a period p in ms, convert it to the closest endpoint
- * interrupt frequency; rounding down.  This is a gross macro.
- * Feel free to toss it for actual code. (gasp!)
- */
-#define ms_to_ed_int(p) \
-	((p >= 32) ? ED_INT_32 : \
-	 ((p & 16) ? ED_INT_16 : \
-	  ((p & 8) ? ED_INT_8 : \
-	   ((p & 4) ? ED_INT_4 : \
-	    ((p & 2) ? ED_INT_2 : \
-	     ED_INT_1)))))  /* hmm.. scheme or lisp anyone? */
-
-/*
- * This is the maximum number of root hub ports.  I don't think we'll
- * ever see more than two as that's the space available on an ATX
- * motherboard's case, but it could happen.  The OHCI spec allows for
- * up to 15... (which is insane!)
- * 
- * Although I suppose several "ports" could be connected directly to
- * internal laptop devices such as a keyboard, mouse, camera and
- * serial/parallel ports.  hmm...  That'd be neat.
- */
-#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region.  This is Memory Mapped I/O.  You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
- */
-struct ohci_regs {
-	/* control and status registers */
-	__u32	revision;
-	__u32	control;
-	__u32	cmdstatus;
-	__u32	intrstatus;
-	__u32	intrenable;
-	__u32	intrdisable;
-	/* memory pointers */
-	__u32	hcca;
-	__u32	ed_periodcurrent;
-	__u32	ed_controlhead;
-	__u32	ed_controlcurrent;
-	__u32	ed_bulkhead;
-	__u32	ed_bulkcurrent;
-	__u32	current_donehead; /* The driver should get this from the HCCA */
-	/* frame counters */
-	__u32	fminterval;
-	__u32	fmremaining;
-	__u32	fmnumber;
-	__u32	periodicstart;
-	__u32	lsthresh;
-	/* Root hub ports */
-	struct	ohci_roothub_regs {
-		__u32	a;
-		__u32	b;
-		__u32	status;
-		__u32	portstatus[MAX_ROOT_PORTS];
-	} roothub;
-} __attribute((aligned(32)));
-
-/* 
- * Read a MMIO register and re-write it after ANDing with (m)
- */
-#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) )
-
-/*
- * Read a MMIO register and re-write it after ORing with (b)
- */
-#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) )
-
-
-#define PORT_CCS	(1)		/* port current connect status */
-#define PORT_PES	(1 << 1)	/* port enable status */
-#define PORT_PSS	(1 << 2)	/* port suspend status */
-#define PORT_POCI	(1 << 3)	/* port overcurrent indicator */
-#define PORT_PRS	(1 << 4)	/* port reset status */
-#define PORT_PPS	(1 << 8)	/* port power status */
-#define PORT_LSDA	(1 << 9)	/* port low speed dev. attached */
-#define PORT_CSC	(1 << 16)	/* port connect status change */
-#define PORT_PESC	(1 << 17)	/* port enable status change */
-#define PORT_PSSC	(1 << 18)	/* port suspend status change */
-#define PORT_OCIC	(1 << 19)	/* port over current indicator chg */
-#define PORT_PRSC	(1 << 20)	/* port reset status change */
-
-/*
- * Root Hub status register masks
- */
-#define OHCI_ROOT_LPS	(1)		/* turn off root hub ports power */
-#define OHCI_ROOT_OCI	(1 << 1)	/* Overcurrent Indicator */
-#define OHCI_ROOT_DRWE	(1 << 15)	/* Device remote wakeup enable */
-#define OHCI_ROOT_LPSC	(1 << 16)	/* turn on root hub ports power */
-#define OHCI_ROOT_OCIC	(1 << 17)	/* Overcurrent indicator change */
-#define OHCI_ROOT_CRWE	(1 << 31)	/* Clear RemoteWakeupEnable */
-
-/*
- * Interrupt register masks
- */
-#define OHCI_INTR_SO	(1)
-#define OHCI_INTR_WDH	(1 << 1)
-#define OHCI_INTR_SF	(1 << 2)
-#define OHCI_INTR_RD	(1 << 3)
-#define OHCI_INTR_UE	(1 << 4)
-#define OHCI_INTR_FNO	(1 << 5)
-#define OHCI_INTR_RHSC	(1 << 6)
-#define OHCI_INTR_OC	(1 << 30)
-#define OHCI_INTR_MIE	(1 << 31)
-
-/*
- * Control register masks
- */
-#define OHCI_USB_OPER		(2 << 6)
-#define OHCI_USB_SUSPEND	(3 << 6)
-#define OHCI_USB_PLE		(1 << 2)  /* Periodic (interrupt) list enable */
-#define OHCI_USB_IE		(1 << 3)  /* Isochronous list enable */
-#define OHCI_USB_CLE		(1 << 4)  /* Control list enable */
-#define OHCI_USB_BLE		(1 << 5)  /* Bulk list enable */
-
-/*
- * Command status register masks
- */
-#define OHCI_CMDSTAT_HCR	(1)
-#define OHCI_CMDSTAT_CLF	(1 << 1)
-#define OHCI_CMDSTAT_BLF	(1 << 2)
-#define OHCI_CMDSTAT_OCR	(1 << 3)
-#define OHCI_CMDSTAT_SOC	(3 << 16)
-
-/*
- * This is the full ohci controller description
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs. (Linus)
- */
-struct ohci {
-    	int irq;
-	struct ohci_regs *regs;			/* OHCI controller's memory */
-	struct usb_bus *bus;
-	struct ohci_device *root_hub;		/* Root hub & controller */
-	struct list_head interrupt_list;	/* List of interrupt active TDs for this OHCI */
-};
-
-#define OHCI_TIMER
-#define OHCI_TIMER_FREQ	(1)		/* frequency of OHCI status checks */
-
-/* Debugging code */
-void show_ohci_ed(struct ohci_ed *ed);
-void show_ohci_td(struct ohci_td *td);
-void show_ohci_status(struct ohci *ohci);
-void show_ohci_device(struct ohci_device *dev);
-void show_ohci_hcca(struct ohci_hcca *hcca);
-
-#endif
-/* vim:sw=8
- */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ov511.c linux.18p8/drivers/usb/ov511.c
--- linux.vanilla/drivers/usb/ov511.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/ov511.c	Fri Sep 15 12:49:09 2000
@@ -0,0 +1,3365 @@
+/*
+ * OmniVision OV511 Camera-to-USB Bridge Driver
+ *
+ * Copyright (c) 1999-2000 Mark W. McClelland
+ * Many improvements by Bret Wallach <bwallac1@san.rr.com>
+ * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
+ * Snapshot code by Kevin Moore
+ * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
+ * Changes by Claudio Matsuoka <claudio@conectiva.com>
+ * 
+ * Based on the Linux CPiA driver written by Peter Pregler,
+ * Scott J. Bertin and Johannes Erdfelt.
+ * 
+ * Please see the file: linux/Documentation/usb/ov511.txt 
+ * and the website at:  http://alpha.dyndns.org/ov511
+ * for more info.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+static const char version[] = "1.25";
+
+#define __NO_VERSION__
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/pagemap.h>
+#include <linux/usb.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include "ov511.h"
+
+#undef OV511_GBR422		/* Experimental -- sets the 7610 to GBR422 */
+
+#define OV511_I2C_RETRIES 3
+
+/* Video Size 640 x 480 x 3 bytes for RGB */
+#define MAX_FRAME_SIZE (640 * 480 * 3)
+#define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval))
+
+#define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_GREY ? 256 : 384)
+#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : \
+		     ((p) == VIDEO_PALETTE_YUV422 ? 16 : 24))
+
+/* PARAMETER VARIABLES: */
+static int autoadjust = 1;    /* CCD dynamically changes exposure, etc... */
+
+/* 0=no debug messages
+ * 1=init/detection/unload and other significant messages,
+ * 2=some warning messages
+ * 3=config/control function calls
+ * 4=most function calls and data parsing messages
+ * 5=highly repetitive mesgs
+ * NOTE: This should be changed to 0, 1, or 2 for production kernels
+ */
+static int debug = 3;
+
+/* Fix vertical misalignment of red and blue at 640x480 */
+static int fix_rgb_offset = 0;
+
+/* Snapshot mode enabled flag */
+static int snapshot = 0;
+
+/* Sensor detection override (global for all attached cameras) */
+static int sensor = 0;
+
+/* Increase this if you are getting "Failed to read sensor ID..." */
+static int i2c_detect_tries = 5;
+
+/* For legal values, see the OV7610/7620 specs under register Common F,
+ * upper nybble  (set to 0-F) */
+static int aperture = -1;
+
+/* Force image to be read in RGB instead of BGR. This option allow
+ * programs that expect RGB data (e.g. gqcam) to work with this driver. */
+static int force_rgb = 0;
+
+/* Number of seconds before inactive buffers are deallocated */
+static int buf_timeout = 5;
+
+/* Number of cameras to stream from simultaneously */
+static int cams = 1;
+
+/* Prevent apps from timing out if frame is not done in time */
+static int retry_sync = 0;
+
+/* Enable compression. This is for experimentation only; compressed images
+ * still cannot be decoded yet. */
+static int compress = 0;
+
+/* Display test pattern - doesn't work yet either */
+static int testpat = 0;
+
+MODULE_PARM(autoadjust, "i");
+MODULE_PARM_DESC(autoadjust, "CCD dynamically changes exposure");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level: 0=none, 1=init/detection, 2=warning, 3=config/control, 4=function call, 5=max");
+MODULE_PARM(fix_rgb_offset, "i");
+MODULE_PARM_DESC(fix_rgb_offset, "Fix vertical misalignment of red and blue at 640x480");
+MODULE_PARM(snapshot, "i");
+MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
+MODULE_PARM(sensor, "i");
+MODULE_PARM_DESC(sensor, "Override sensor detection");
+MODULE_PARM(i2c_detect_tries, "i");
+MODULE_PARM_DESC(i2c_detect_tries, "Number of tries to detect sensor");
+MODULE_PARM(aperture, "i");
+MODULE_PARM_DESC(aperture, "Read the OV7610/7620 specs");
+MODULE_PARM(force_rgb, "i");
+MODULE_PARM_DESC(force_rgb, "Read RGB instead of BGR");
+MODULE_PARM(buf_timeout, "i");
+MODULE_PARM_DESC(buf_timeout, "Number of seconds before buffer deallocation");
+MODULE_PARM(cams, "i");
+MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
+MODULE_PARM(retry_sync, "i");
+MODULE_PARM_DESC(retry_sync, "Prevent apps from timing out");
+MODULE_PARM(compress, "i");
+MODULE_PARM_DESC(compress, "Turn on compression (not functional yet)");
+MODULE_PARM(testpat, "i");
+MODULE_PARM_DESC(testpat, "Replace image with vertical bar testpattern (only partially working)");
+
+MODULE_AUTHOR("Mark McClelland <mwm@i.am> & Bret Wallach & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>");
+MODULE_DESCRIPTION("OV511 USB Camera Driver");
+
+char kernel_version[] = UTS_RELEASE;
+
+static struct usb_driver ov511_driver;
+
+/* I know, I know, global variables suck. This is only a temporary hack */
+int output_offset;
+
+/**********************************************************************
+ * List of known OV511-based cameras
+ **********************************************************************/
+
+static struct cam_list clist[] = {
+	{   0, "generic model (no ID)" },
+	{   3, "D-Link DSB-C300" },
+	{   4, "generic OV511/OV7610" },
+	{   5, "Puretek PT-6007" },
+	{  21, "Creative Labs WebCam 3" },
+	{  36, "Koala-Cam" },
+	{  38, "Lifeview USB Life TV" },	/* No support yet! */
+	{ 100, "Lifeview RoboCam" },
+	{ 102, "AverMedia InterCam Elite" },
+	{ 112, "MediaForte MV300" },	/* or OV7110 evaluation kit */
+	{  -1, NULL }
+};
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+static struct palette_list plist[] = {
+	{ VIDEO_PALETTE_GREY,	"GREY" },
+	{ VIDEO_PALETTE_HI240,  "HI240" },
+	{ VIDEO_PALETTE_RGB565, "RGB565" },
+	{ VIDEO_PALETTE_RGB24,	"RGB24" },
+	{ VIDEO_PALETTE_RGB32,	"RGB32" },
+	{ VIDEO_PALETTE_RGB555, "RGB555" },
+	{ VIDEO_PALETTE_YUV422, "YUV422" },
+	{ VIDEO_PALETTE_YUYV,   "YUYV" },
+	{ VIDEO_PALETTE_UYVY,   "UYVY" },
+	{ VIDEO_PALETTE_YUV420, "YUV420" },
+	{ VIDEO_PALETTE_YUV411, "YUV411" },
+	{ VIDEO_PALETTE_RAW,    "RAW" },
+	{ VIDEO_PALETTE_YUV422P,"YUV422P" },
+	{ VIDEO_PALETTE_YUV411P,"YUV411P" },
+	{ VIDEO_PALETTE_YUV420P,"YUV420P" },
+	{ VIDEO_PALETTE_YUV410P,"YUV410P" },
+	{ -1, NULL }
+};
+#endif
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the OV511 driver -claudio
+ **********************************************************************/
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+	unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+
+	if (!pgd_none(*pgd)) {
+		pmd = pmd_offset(pgd, adr);
+		if (!pmd_none(*pmd)) {
+			ptep = pte_offset(pmd, adr);
+			pte = *ptep;
+			if (pte_present(pte))
+				ret = page_address(pte_page(pte)) |
+				      (adr & (PAGE_SIZE-1));
+		}
+	}
+
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long va, kva, ret;
+
+	va = VMALLOC_VMADDR(adr);
+	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = __pa(kva);
+	return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr, page;
+
+	/* Round it off to PAGE_SIZE */
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	mem = vmalloc_32(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+		mem_map_reserve(MAP_NR(__va(page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+	unsigned long adr, page;
+
+	if (!mem)
+		return;
+
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	adr=(unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+		mem_map_unreserve(MAP_NR(__va(page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+	vfree(mem);
+}
+
+/**********************************************************************
+ * /proc interface
+ * Based on the CPiA driver version 0.7.4 -claudio
+ **********************************************************************/
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
+static struct proc_dir_entry *ov511_proc_entry = NULL;
+extern struct proc_dir_entry *video_proc_entry;
+
+#define YES_NO(x) ((x) ? "yes" : "no")
+
+static int ov511_read_proc(char *page, char **start, off_t off,
+                          int count, int *eof, void *data)
+{
+	char *out = page;
+	int i, j, len;
+	struct usb_ov511 *ov511 = data;
+
+	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
+	 *            or we need to get more sophisticated. */
+
+	out += sprintf (out, "driver_version  : %s\n", version);
+	out += sprintf (out, "custom_id       : %d\n", ov511->customid);
+	out += sprintf (out, "model           : %s\n", ov511->desc ?
+		clist[ov511->desc].description : "unknown");
+	out += sprintf (out, "streaming       : %s\n", YES_NO (ov511->streaming));
+	out += sprintf (out, "grabbing        : %s\n", YES_NO (ov511->grabbing));
+	out += sprintf (out, "compress        : %s\n", YES_NO (ov511->compress));
+	out += sprintf (out, "subcapture      : %s\n", YES_NO (ov511->sub_flag));
+	out += sprintf (out, "sub_size        : %d %d %d %d\n",
+		ov511->subx, ov511->suby, ov511->subw, ov511->subh);
+	out += sprintf (out, "data_format     : %s\n", force_rgb ? "RGB" : "BGR");
+	out += sprintf (out, "brightness      : %d\n", ov511->brightness >> 8);
+	out += sprintf (out, "colour          : %d\n", ov511->colour >> 8);
+	out += sprintf (out, "contrast        : %d\n", ov511->contrast >> 8);
+	out += sprintf (out, "num_frames      : %d\n", OV511_NUMFRAMES);
+	for (i = 0; i < OV511_NUMFRAMES; i++) {
+		out += sprintf (out, "frame           : %d\n", i);
+		out += sprintf (out, "  depth         : %d\n",
+			ov511->frame[i].depth);
+		out += sprintf (out, "  size          : %d %d\n",
+			ov511->frame[i].width, ov511->frame[i].height);
+		out += sprintf (out, "  format        : ");
+		for (j = 0; plist[j].num >= 0; j++) {
+			if (plist[j].num == ov511->frame[i].format) {
+				out += sprintf (out, "%s\n", plist[j].name);
+				break;
+			}
+		}
+		if (plist[j].num < 0)
+			out += sprintf (out, "unknown\n");
+		out += sprintf (out, "  segsize       : %d\n",
+			ov511->frame[i].segsize);
+		out += sprintf (out, "  data_buffer   : 0x%p\n",
+			ov511->frame[i].data);
+	}
+	out += sprintf (out, "snap_enabled    : %s\n", YES_NO (ov511->snap_enabled));
+	out += sprintf (out, "bridge          : %s\n",
+		ov511->bridge == BRG_OV511 ? "OV511" :
+		ov511->bridge == BRG_OV511PLUS ? "OV511+" :
+		"unknown");
+	out += sprintf (out, "sensor          : %s\n",
+		ov511->sensor == SEN_OV7610 ? "OV7610" :
+		ov511->sensor == SEN_OV7620 ? "OV7620" :
+		ov511->sensor == SEN_OV7620AE ? "OV7620AE" :
+		"unknown");
+	out += sprintf (out, "packet_size     : %d\n", ov511->packet_size);
+	out += sprintf (out, "framebuffer     : 0x%p\n", ov511->fbuf);
+	
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else
+		len = count;
+
+	*start = page + off;
+
+	return len;
+}
+
+static int ov511_write_proc(struct file *file, const char *buffer,
+                           unsigned long count, void *data)
+{
+	return -EINVAL;
+}
+
+static void create_proc_ov511_cam (struct usb_ov511 *ov511)
+{
+	char name[7];
+	struct proc_dir_entry *ent;
+	
+	if (!ov511_proc_entry || !ov511)
+		return;
+
+	sprintf(name, "video%d", ov511->vdev.minor);
+	PDEBUG (4, "creating /proc/video/ov511/%s", name);
+	
+	ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, ov511_proc_entry);
+
+	if (!ent)
+		return;
+
+	ent->data = ov511;
+	ent->read_proc = ov511_read_proc;
+	ent->write_proc = ov511_write_proc;
+	ov511->proc_entry = ent;
+}
+
+static void destroy_proc_ov511_cam (struct usb_ov511 *ov511)
+{
+	char name[7];
+	
+	if (!ov511 || !ov511->proc_entry)
+		return;
+	
+	sprintf(name, "video%d", ov511->vdev.minor);
+	PDEBUG (4, "destroying %s", name);
+	remove_proc_entry(name, ov511_proc_entry);
+	ov511->proc_entry = NULL;
+}
+
+static void proc_ov511_create(void)
+{
+	/* No current standard here. Alan prefers /proc/video/ as it keeps
+	 * /proc "less cluttered than /proc/randomcardifoundintheshed/"
+	 * -claudio
+	 */
+	if (video_proc_entry == NULL) {
+		err("Unable to initialise /proc/video/ov511");
+		return;
+	}
+
+	ov511_proc_entry = create_proc_entry("ov511", S_IFDIR, video_proc_entry);
+
+	if (ov511_proc_entry)
+		ov511_proc_entry->owner = THIS_MODULE;
+	else
+		err("Unable to initialise /proc/ov511");
+}
+
+static void proc_ov511_destroy(void)
+{
+	PDEBUG (3, "removing /proc/video/ov511");
+
+	if (ov511_proc_entry == NULL)
+		return;
+
+	remove_proc_entry("ov511", video_proc_entry);
+}
+#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
+
+
+/**********************************************************************
+ *
+ * Camera interface
+ *
+ **********************************************************************/
+
+static int ov511_reg_write(struct usb_device *dev,
+			   unsigned char reg,
+			   unsigned char value)
+{
+	int rc;
+
+	rc = usb_control_msg(dev,
+		usb_sndctrlpipe(dev, 0),
+		2 /* REG_IO */,
+		USB_TYPE_CLASS | USB_RECIP_DEVICE,
+		0, (__u16)reg, &value, 1, HZ);	
+
+	PDEBUG(5, "reg write: 0x%02X:0x%02X, 0x%x", reg, value, rc);
+
+	if (rc < 0)
+		err("reg write: error %d", rc);
+
+	return rc;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int ov511_reg_read(struct usb_device *dev, unsigned char reg)
+{
+	int rc;
+	unsigned char buffer[1];
+
+	rc = usb_control_msg(dev,
+		usb_rcvctrlpipe(dev, 0),
+		2 /* REG_IO */,
+		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
+		0, (__u16)reg, buffer, 1, HZ);
+                               
+	PDEBUG(5, "reg read: 0x%02X:0x%02X", reg, buffer[0]);
+	
+	if (rc < 0) {
+		err("reg read: error %d", rc);
+		return rc;
+	} else {
+		return buffer[0];	
+	}
+}
+
+static int ov511_i2c_write(struct usb_device *dev,
+			   unsigned char reg,
+			   unsigned char value)
+{
+	int rc, retries;
+
+	PDEBUG(5, "i2c write: 0x%02X:0x%02X", reg, value);
+
+	/* Three byte write cycle */
+	for (retries = OV511_I2C_RETRIES; ; ) {
+		/* Select camera register */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_3_BYTE, reg);
+		if (rc < 0) goto error;
+
+		/* Write "value" to I2C data port of OV511 */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_DATA_PORT, value);	
+		if (rc < 0) goto error;
+
+		/* Initiate 3-byte write cycle */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x01);
+		if (rc < 0) goto error;
+
+		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		if (rc < 0) goto error;
+
+		if ((rc&2) == 0) /* Ack? */
+			break;
+#if 0
+		/* I2C abort */	
+		ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+#endif
+		if (--retries < 0) {
+			err("i2c write retries exhausted");
+			rc = -1;
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	err("i2c write: error %d", rc);
+	return rc;
+}
+
+/* returns: negative is error, pos or zero is data */
+static int ov511_i2c_read(struct usb_device *dev, unsigned char reg)
+{
+	int rc, value, retries;
+
+	/* Two byte write cycle */
+	for (retries = OV511_I2C_RETRIES; ; ) {
+		/* Select camera register */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_SUB_ADDRESS_2_BYTE, reg);
+		if (rc < 0) goto error;
+
+		/* Initiate 2-byte write cycle */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x03);
+		if (rc < 0) goto error;
+
+		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		if (rc < 0) goto error;
+
+		if ((rc&2) == 0) /* Ack? */
+			break;
+
+		/* I2C abort */	
+		ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+
+		if (--retries < 0) {
+			err("i2c write retries exhausted");
+			rc = -1;
+			goto error;
+		}
+	}
+
+	/* Two byte read cycle */
+	for (retries = OV511_I2C_RETRIES; ; ) {
+		/* Initiate 2-byte read cycle */
+		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
+		if (rc < 0) goto error;
+
+		do rc = ov511_reg_read(dev, OV511_REG_I2C_CONTROL);
+		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
+		if (rc < 0) goto error;
+
+		if ((rc&2) == 0) /* Ack? */
+			break;
+
+		/* I2C abort */	
+		rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x10);
+		if (rc < 0) goto error;
+
+		if (--retries < 0) {
+			err("i2c read retries exhausted");
+			rc = -1;
+			goto error;
+		}
+	}
+
+	value = ov511_reg_read(dev, OV511_REG_I2C_DATA_PORT);
+
+	PDEBUG(5, "i2c read: 0x%02X:0x%02X", reg, value);
+		
+	/* This is needed to make ov511_i2c_write() work */
+	rc = ov511_reg_write(dev, OV511_REG_I2C_CONTROL, 0x05);
+	if (rc < 0)
+		goto error;
+	
+	return value;
+
+error:
+	err("i2c read: error %d", rc);
+	return rc;
+}
+
+static int ov511_write_regvals(struct usb_device *dev,
+			       struct ov511_regvals * pRegvals)
+{
+	int rc;
+
+	while (pRegvals->bus != OV511_DONE_BUS) {
+		if (pRegvals->bus == OV511_REG_BUS) {
+			if ((rc = ov511_reg_write(dev, pRegvals->reg,
+			                           pRegvals->val)) < 0)
+				goto error;
+		} else if (pRegvals->bus == OV511_I2C_BUS) {
+			if ((rc = ov511_i2c_write(dev, pRegvals->reg, 
+			                           pRegvals->val)) < 0)
+				goto error;
+		} else {
+			err("Bad regval array");
+			rc = -1;
+			goto error;
+		}
+		pRegvals++;
+	}
+	return 0;
+
+error:
+	err("write regvals: error %d", rc);
+	return rc;
+}
+
+#ifdef OV511_DEBUG 
+static void ov511_dump_i2c_range(struct usb_device *dev, int reg1, int regn)
+{
+	int i;
+	int rc;
+	for(i = reg1; i <= regn; i++) {
+		rc = ov511_i2c_read(dev, i);
+		PDEBUG(1, "OV7610[0x%X] = 0x%X", i, rc);
+	}
+}
+
+static void ov511_dump_i2c_regs(struct usb_device *dev)
+{
+	PDEBUG(3, "I2C REGS");
+	ov511_dump_i2c_range(dev, 0x00, 0x7C);
+}
+
+#if 0
+static void ov511_dump_reg_range(struct usb_device *dev, int reg1, int regn)
+{
+	int i;
+	int rc;
+	for(i = reg1; i <= regn; i++) {
+	  rc = ov511_reg_read(dev, i);
+	  PDEBUG(1, "OV511[0x%X] = 0x%X", i, rc);
+	}
+}
+
+static void ov511_dump_regs(struct usb_device *dev)
+{
+	PDEBUG(1, "CAMERA INTERFACE REGS");
+	ov511_dump_reg_range(dev, 0x10, 0x1f);
+	PDEBUG(1, "DRAM INTERFACE REGS");
+	ov511_dump_reg_range(dev, 0x20, 0x23);
+	PDEBUG(1, "ISO FIFO REGS");
+	ov511_dump_reg_range(dev, 0x30, 0x31);
+	PDEBUG(1, "PIO REGS");
+	ov511_dump_reg_range(dev, 0x38, 0x39);
+	ov511_dump_reg_range(dev, 0x3e, 0x3e);
+	PDEBUG(1, "I2C REGS");
+	ov511_dump_reg_range(dev, 0x40, 0x49);
+	PDEBUG(1, "SYSTEM CONTROL REGS");
+	ov511_dump_reg_range(dev, 0x50, 0x55);
+	ov511_dump_reg_range(dev, 0x5e, 0x5f);
+	PDEBUG(1, "OmniCE REGS");
+	ov511_dump_reg_range(dev, 0x70, 0x79);
+	ov511_dump_reg_range(dev, 0x80, 0x9f);
+	ov511_dump_reg_range(dev, 0xa0, 0xbf);
+
+}
+#endif
+#endif
+
+static int ov511_reset(struct usb_device *dev, unsigned char reset_type)
+{
+	int rc;
+	
+	PDEBUG(3, "Reset: type=0x%X", reset_type);
+	rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, reset_type);
+	rc = ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0);
+
+	if (rc < 0)
+		err("reset: command failed");
+
+	return rc;
+}
+
+/* Temporarily stops OV511 from functioning. Must do this before changing
+ * registers while the camera is streaming */
+static inline int ov511_stop(struct usb_device *dev)
+{
+	PDEBUG(4, "stopping");
+	return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x3d));
+}
+
+/* Restarts OV511 after ov511_stop() is called */
+static inline int ov511_restart(struct usb_device *dev)
+{
+	PDEBUG(4, "restarting");
+	return (ov511_reg_write(dev, OV511_REG_SYSTEM_RESET, 0x00));
+}
+
+static int ov511_set_packet_size(struct usb_ov511 *ov511, int size)
+{
+	int alt, mult;
+
+	if (ov511_stop(ov511->dev) < 0)
+		return -EIO;
+
+	mult = size >> 5;
+
+	if (ov511->bridge == BRG_OV511) {
+		if (size == 0) alt = OV511_ALT_SIZE_0;
+		else if (size == 257) alt = OV511_ALT_SIZE_257;
+		else if (size == 513) alt = OV511_ALT_SIZE_513;
+		else if (size == 769) alt = OV511_ALT_SIZE_769;
+		else if (size == 993) alt = OV511_ALT_SIZE_993;
+		else {
+			err("Set packet size: invalid size (%d)", size);
+			return -EINVAL;
+		}
+	} else if (ov511->bridge == BRG_OV511PLUS) {
+		if (size == 0) alt = OV511PLUS_ALT_SIZE_0;
+		else if (size == 33) alt = OV511PLUS_ALT_SIZE_33;
+		else if (size == 129) alt = OV511PLUS_ALT_SIZE_129;
+		else if (size == 257) alt = OV511PLUS_ALT_SIZE_257;
+		else if (size == 385) alt = OV511PLUS_ALT_SIZE_385;
+		else if (size == 513) alt = OV511PLUS_ALT_SIZE_513;
+		else if (size == 769) alt = OV511PLUS_ALT_SIZE_769;
+		else if (size == 961) alt = OV511PLUS_ALT_SIZE_961;
+		else {
+			err("Set packet size: invalid size (%d)", size);
+			return -EINVAL;
+		}
+	} else {
+		err("Set packet size: Invalid bridge type");
+		return -EINVAL;
+	}
+
+	PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size, mult, alt);
+
+	if (ov511_reg_write(ov511->dev, OV511_REG_FIFO_PACKET_SIZE, mult) < 0)
+		return -ENOMEM;
+	
+	if (usb_set_interface(ov511->dev, ov511->iface, alt) < 0) {
+		err("Set packet size: set interface error");
+		return -EBUSY;
+	}
+
+	// FIXME - Should we only reset the FIFO?
+	if (ov511_reset(ov511->dev, OV511_RESET_NOREGS) < 0)
+		return -ENOMEM;
+
+	ov511->packet_size = size;
+
+	if (ov511_restart(ov511->dev) < 0)
+		return -EIO;
+
+	return 0;
+}
+
+
+static inline int
+ov7610_set_picture(struct usb_ov511 *ov511, struct video_picture *p)
+{
+	int ret;
+	struct usb_device *dev = ov511->dev;
+
+	PDEBUG(4, "ov511_set_picture");
+
+	if (ov511_stop(dev) < 0)
+		return -EIO;
+
+	ov511->contrast = p->contrast;
+	ov511->brightness = p->brightness;
+	ov511->colour = p->colour;
+	ov511->hue = p->hue;
+	ov511->whiteness = p->whiteness;
+
+	if ((ret = ov511_i2c_read(dev, OV7610_REG_COM_B)) < 0)
+		return -EIO;
+#if 0
+	/* disable auto adjust mode */
+	if (ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0)
+		return -EIO;
+#endif
+	if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE
+		|| ov511->sensor == SEN_OV6620)
+		if (ov511_i2c_write(dev, OV7610_REG_SAT, p->colour >> 8) < 0)
+			return -EIO;
+
+	if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV6620) {
+		if (ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+			return -EIO;
+
+		if (ov511_i2c_write(dev, OV7610_REG_RED, 0xFF - (p->hue >> 8)) < 0)
+			return -EIO;
+
+		if (ov511_i2c_write(dev, OV7610_REG_BLUE, p->hue >> 8) < 0)
+			return -EIO;
+
+		if (ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0)
+			return -EIO;
+	} else if ((ov511->sensor == SEN_OV7620) 
+	         || (ov511->sensor == SEN_OV7620AE)) {
+#if 0
+		cur_con = ov511_i2c_read(dev, OV7610_REG_CNT);
+		cur_brt = ov511_i2c_read(dev, OV7610_REG_BRT);
+	        // DEBUG_CODE
+	        PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT),
+	         ov511_i2c_read(dev, OV7610_REG_BRT)); 
+
+		if (ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0)
+			return -EIO;
+#endif
+	}
+
+	if (ov511_restart(dev) < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static inline int
+ov7610_get_picture(struct usb_ov511 *ov511, struct video_picture *p)
+{
+	int ret;
+	struct usb_device *dev = ov511->dev;
+
+	PDEBUG(4, "ov511_get_picture");
+
+	if (ov511_stop(dev) < 0)
+		return -EIO;
+
+	if ((ret = ov511_i2c_read(dev, OV7610_REG_SAT)) < 0) return -EIO;
+	p->colour = ret << 8;
+
+	if ((ret = ov511_i2c_read(dev, OV7610_REG_CNT)) < 0) return -EIO;
+	p->contrast = ret << 8;
+
+	if ((ret = ov511_i2c_read(dev, OV7610_REG_BRT)) < 0) return -EIO;
+	p->brightness = ret << 8;
+
+	/* This may not be the best way to do it */
+	if ((ret = ov511_i2c_read(dev, OV7610_REG_BLUE)) < 0) return -EIO;
+	p->hue = ret << 8;
+
+	p->whiteness = 105 << 8;
+
+	/* Can we get these from frame[0]? -claudio? */
+	p->depth = ov511->frame[0].depth;
+	p->palette = ov511->frame[0].format;
+
+	if (ov511_restart(dev) < 0)
+		return -EIO;
+
+	return 0;
+}
+
+/* LNCNT values fixed by Lawrence Glaister <lg@jfm.bc.ca> */
+static struct mode_list mlist[] = {
+	/* W    H   C  PXCNT LNCNT PXDIV LNDIV M420  COMA  COML */
+	{ 640, 480, 0, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x9e },
+	{ 640, 480, 1, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x9e },
+	{ 320, 240, 0, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 320, 240, 1, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 352, 288, 0, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 352, 288, 1, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 384, 288, 0, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 384, 288, 1, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 448, 336, 0, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 448, 336, 1, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 176, 144, 0, 0x15, 0x12, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 176, 144, 1, 0x15, 0x12, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 160, 120, 0, 0x13, 0x0e, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 160, 120, 1, 0x13, 0x0e, 0x00, 0x00, 0x03, 0x04, 0x1e },
+	{ 0, 0 }
+};
+
+static int
+ov511_mode_init_regs(struct usb_ov511 *ov511,
+		     int width, int height, int mode, int sub_flag)
+{
+	int i;
+	struct usb_device *dev = ov511->dev;
+	int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; 
+	int hwscale = 0, vwscale = 0;
+
+	PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
+	       width, height, mode, sub_flag);
+
+	if (ov511_stop(ov511->dev) < 0)
+		return -EIO;
+
+	if (mode == VIDEO_PALETTE_GREY) {
+		ov511_reg_write(dev, 0x16, 0x00);
+		if (ov511->sensor == SEN_OV7610
+		    || ov511->sensor == SEN_OV7620AE) {
+			/* these aren't valid on the OV6620/OV7620 */
+			ov511_i2c_write(dev, 0x0e, 0x44);
+		}
+		ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20);
+
+		/* For snapshot */
+		ov511_reg_write(dev, 0x1e, 0x00);
+		ov511_reg_write(dev, 0x1f, 0x01);
+	} else {
+		ov511_reg_write(dev, 0x16, 0x01);
+		if (ov511->sensor == SEN_OV7610
+		    || ov511->sensor == SEN_OV7620AE) {
+			/* not valid on the OV6620/OV7620 */
+			ov511_i2c_write(dev, 0x0e, 0x04);
+		}
+		ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00);
+
+		/* For snapshot */
+		ov511_reg_write(dev, 0x1e, 0x01);
+		ov511_reg_write(dev, 0x1f, 0x03);
+	}
+
+	/* The different sensor ICs handle setting up of window differently */
+	switch (ov511->sensor) {
+	case SEN_OV7610:
+	case SEN_OV7620AE:
+		hwsbase = 0x38;
+		hwebase = 0x3a;
+		vwsbase = vwebase = 0x05;
+		break;
+	case SEN_OV6620:
+		hwsbase = 0x38;
+		hwebase = 0x39;
+		vwsbase = 0x03;
+		vwebase = 0x04;
+		break;
+	case SEN_OV7620:
+		hwsbase = 0x2c;
+		hwebase = 0x2d;
+		vwsbase = vwebase = 0x05;
+		break;
+	default:
+		err("Invalid sensor");
+		return -EINVAL;
+	}
+
+	/* Bit 5 of COM C register varies with sensor */ 
+	if (ov511->sensor == SEN_OV6620) {
+		if (width > 176 && height > 144) {  /* CIF */
+			ov511_i2c_write(dev, 0x14, 0x04);
+			hwscale = 1;
+			vwscale = 1;  /* The datasheet says 0; it's wrong */
+			hwsize = 352;
+			vwsize = 288;
+		} else {			    /* QCIF */
+			ov511_i2c_write(dev, 0x14, 0x24);
+			hwsize = 176;
+			vwsize = 144;
+		}
+	}
+	else {
+		if (width > 320 && height > 240) {  /* VGA */
+			ov511_i2c_write(dev, 0x14, 0x04);
+			hwscale = 2;
+			vwscale = 1;
+			hwsize = 640;
+			vwsize = 480;
+		} else {			    /* QVGA */
+			ov511_i2c_write(dev, 0x14, 0x24);
+			hwscale = 1;
+			hwsize = 320;
+			vwsize = 240;
+		}	
+	}
+
+	/* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
+	if (sub_flag) {
+		ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>hwscale));
+		ov511_i2c_write(dev, 0x18, hwebase+((ov511->subx+ov511->subw)>>hwscale));
+		ov511_i2c_write(dev, 0x19, vwsbase+(ov511->suby>>vwscale));
+		ov511_i2c_write(dev, 0x1a, vwebase+((ov511->suby+ov511->subh)>>vwscale));
+	} else {
+		ov511_i2c_write(dev, 0x17, hwsbase);
+		ov511_i2c_write(dev, 0x18, hwebase + (hwsize>>hwscale));
+		ov511_i2c_write(dev, 0x19, vwsbase);
+		ov511_i2c_write(dev, 0x1a, vwebase + (vwsize>>vwscale));
+	}
+
+	for (i = 0; mlist[i].width; i++) {
+		int lncnt, pxcnt, clock;
+
+		if (width != mlist[i].width || height != mlist[i].height)
+			continue;
+
+		if (!mlist[i].color && mode != VIDEO_PALETTE_GREY)
+			continue;
+
+		/* Here I'm assuming that snapshot size == image size.
+		 * I hope that's always true. --claudio
+		 */
+		pxcnt = sub_flag ? (ov511->subw >> 3) - 1 : mlist[i].pxcnt;
+		lncnt = sub_flag ? (ov511->subh >> 3) - 1 : mlist[i].lncnt;
+
+		ov511_reg_write(dev, 0x12, pxcnt);
+		ov511_reg_write(dev, 0x13, lncnt);
+		ov511_reg_write(dev, 0x14, mlist[i].pxdv);
+		ov511_reg_write(dev, 0x15, mlist[i].lndv);
+		ov511_reg_write(dev, 0x18, mlist[i].m420);
+
+		/* Snapshot additions */
+		ov511_reg_write(dev, 0x1a, pxcnt);
+		ov511_reg_write(dev, 0x1b, lncnt);
+                ov511_reg_write(dev, 0x1c, mlist[i].pxdv);
+                ov511_reg_write(dev, 0x1d, mlist[i].lndv);
+
+		/* Calculate and set the clock divisor */
+		clock = ((sub_flag ? ov511->subw * ov511->subh : width * height)
+			* (mlist[i].color ? 3 : 2) / 2) / 66000;
+		ov511_i2c_write(dev, 0x11, clock);
+
+#ifdef OV511_GBR422
+		ov511_i2c_write(dev, 0x12, mlist[i].common_A | 0x08);
+#else
+		ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x02:0x00));
+#endif
+
+		/* 7620/6620 don't have register 0x35, so play it safe */
+		if (ov511->sensor == SEN_OV7610 ||
+		    ov511->sensor == SEN_OV7620AE)
+			ov511_i2c_write(dev, 0x35, mlist[i].common_L);
+
+		break;
+	}
+
+	if (compress) {
+		ov511_reg_write(dev, 0x78, 0x03); // Turn on Y compression
+		ov511_reg_write(dev, 0x79, 0x00); // Disable LUTs
+	}
+
+	if (ov511_restart(ov511->dev) < 0)
+		return -EIO;
+
+	if (mlist[i].width == 0) {
+		err("Unknown mode (%d, %d): %d", width, height, mode);
+		return -EINVAL;
+	}
+
+#ifdef OV511_DEBUG
+	if (debug >= 5)
+		ov511_dump_i2c_regs(dev);
+#endif
+
+	return 0;
+}
+
+/**********************************************************************
+ *
+ * Color correction functions
+ *
+ **********************************************************************/
+
+/*
+ * Turn a YUV4:2:0 block into an RGB block
+ *
+ * Video4Linux seems to use the blue, green, red channel
+ * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
+ *
+ * Color space conversion coefficients taken from the excellent
+ * http://www.inforamp.net/~poynton/ColorFAQ.html
+ * In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
+ * Y values are given for all 4 pixels, but the U (Pb)
+ * and V (Pr) are assumed constant over the 2x2 block.
+ *
+ * To avoid floating point arithmetic, the color conversion
+ * coefficients are scaled into 16.16 fixed-point integers.
+ * They were determined as follows:
+ *
+ *	double brightness = 1.0;  (0->black; 1->full scale) 
+ *	double saturation = 1.0;  (0->greyscale; 1->full color)
+ *	double fixScale = brightness * 256 * 256;
+ *	int rvScale = (int)(1.402 * saturation * fixScale);
+ *	int guScale = (int)(-0.344136 * saturation * fixScale);
+ *	int gvScale = (int)(-0.714136 * saturation * fixScale);
+ *	int buScale = (int)(1.772 * saturation * fixScale);
+ *	int yScale = (int)(fixScale);	
+ */
+
+/* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
+#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
+
+static inline void
+ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, 
+	int rowPixels, unsigned char * rgb)
+{
+	const int rvScale = 91881;
+	const int guScale = -22553;
+	const int gvScale = -46801;
+	const int buScale = 116129;
+	const int yScale  = 65536;
+	int r, g, b;
+
+	g = guScale * u + gvScale * v;
+	if (force_rgb) {
+		r = buScale * u;
+		b = rvScale * v;
+	} else {
+		r = rvScale * v;
+		b = buScale * u;
+	}
+
+	yTL *= yScale; yTR *= yScale;
+	yBL *= yScale; yBR *= yScale;
+
+	/* Write out top two pixels */
+	rgb[0] = LIMIT(b+yTL); rgb[1] = LIMIT(g+yTL); rgb[2] = LIMIT(r+yTL);
+	rgb[3] = LIMIT(b+yTR); rgb[4] = LIMIT(g+yTR); rgb[5] = LIMIT(r+yTR);
+
+	/* Skip down to next line to write out bottom two pixels */
+	rgb += 3 * rowPixels;
+	rgb[0] = LIMIT(b+yBL); rgb[1] = LIMIT(g+yBL); rgb[2] = LIMIT(r+yBL);
+	rgb[3] = LIMIT(b+yBR); rgb[4] = LIMIT(g+yBR); rgb[5] = LIMIT(r+yBR);
+}
+
+/*
+ * For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments.
+ * The first 64 bytes of each segment are U, the next 64 are V.  The U and
+ * V are arranged as follows:
+ *
+ *      0  1 ...  7
+ *      8  9 ... 15
+ *           ...   
+ *     56 57 ... 63
+ *
+ * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
+ *
+ * The next 256 bytes are full resolution Y data and represent 4 squares
+ * of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121 ... 127   ...  248 249 ... 255
+ *
+ * Note that the U and V data in one segment represents a 16 x 16 pixel
+ * area, but the Y data represents a 32 x 8 pixel area.
+ *
+ * If OV511_DUMPPIX is defined, _parse_data just dumps the incoming segments,
+ * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
+ * this puts the data on the standard output and can be analyzed with the
+ * parseppm.c utility I wrote.  That's a much faster way for figuring out how
+ * this data is scrambled.
+ */
+
+#define HDIV 8
+#define WDIV (256/HDIV)
+
+#undef OV511_DUMPPIX
+
+/* #define this and OV511_DUMPPIX to disable parsing of UV data */
+#undef OV511_FORCE_MONO
+
+#ifdef OV511_GBR422
+static void
+ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
+		       int iOutY, int iOutUV, int iHalf, int iWidth)
+{
+	int k, l, m;
+	unsigned char *pIn;
+	unsigned char *pOut, *pOut1;
+
+	pIn = pIn0;
+	pOut = pOut0 + iOutUV + (force_rgb ? 2 : 0);
+		
+	for (k = 0; k < 8; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			*pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) =
+				*(pOut1 + iWidth*3 + 3) = *pIn++;
+			pOut1 += 6;
+		}
+		pOut += iWidth*3*2;
+	}
+
+	pIn = pIn0 + 64;
+	pOut = pOut0 + iOutUV + (force_rgb ? 0 : 2);
+	for (k = 0; k < 8; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			*pOut1 = *(pOut1 + 3) = *(pOut1 + iWidth*3) =
+				*(pOut1 + iWidth*3 + 3) = *pIn++;
+			pOut1 += 6;
+		}
+		pOut += iWidth*3*2;
+	}
+
+	pIn = pIn0 + 128;
+	pOut = pOut0 + iOutY + 1;
+	for (k = 0; k < 4; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			for (m = 0; m < 8; m++) {
+				*pOut1 = *pIn++;
+				pOut1 += 3;
+			}
+			pOut1 += (iWidth - 8) * 3;
+		}
+		pOut += 8 * 3;
+	}
+}
+
+#else
+
+static void
+ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0,
+		       int iOutY, int iOutUV, int iHalf, int iWidth)
+{
+#ifndef OV511_DUMPPIX
+	int k, l, m;
+	unsigned char *pIn;
+	unsigned char *pOut, *pOut1;
+
+	/* Just copy the Y's if in the first stripe */
+	if (!iHalf) {
+		pIn = pIn0 + 128;
+		pOut = pOut0 + iOutY;
+		for (k = 0; k < 4; k++) {
+			pOut1 = pOut;
+			for (l = 0; l < 8; l++) {
+				for (m = 0; m < 8; m++) {
+					*pOut1 = *pIn++;
+					pOut1 += 3;
+				}
+				pOut1 += (iWidth - 8) * 3;
+			}
+			pOut += 8 * 3;
+		}
+	}
+
+	/* Use the first half of VUs to calculate value */
+	pIn = pIn0;
+	pOut = pOut0 + iOutUV;
+	for (l = 0; l < 4; l++) {
+		for (m=0; m<8; m++) {
+			int y00 = *(pOut);
+			int y01 = *(pOut+3);
+			int y10 = *(pOut+iWidth*3);
+			int y11 = *(pOut+iWidth*3+3);
+			int v   = *(pIn+64) - 128;
+			int u   = *pIn++ - 128;
+			ov511_move_420_block(y00, y01, y10, y11, u, v, iWidth,
+				pOut);
+			pOut += 6;
+		}
+		pOut += (iWidth*2 - 16) * 3;
+	}
+
+	/* Just copy the other UV rows */
+	for (l = 0; l < 4; l++) {
+		for (m = 0; m < 8; m++) {
+			*pOut++ = *(pIn + 64);
+			*pOut = *pIn++;
+			pOut += 5;
+		}
+		pOut += (iWidth*2 - 16) * 3;
+	}
+
+	/* Calculate values if it's the second half */
+	if (iHalf) {
+		pIn = pIn0 + 128;
+		pOut = pOut0 + iOutY;
+		for (k = 0; k < 4; k++) {
+			pOut1 = pOut;
+			for (l=0; l<4; l++) {
+				for (m=0; m<4; m++) {
+					int y10 = *(pIn+8);
+					int y00 = *pIn++;
+					int y11 = *(pIn+8);
+					int y01 = *pIn++;
+					int v   = *pOut1 - 128;
+					int u   = *(pOut1+1) - 128;
+					ov511_move_420_block(y00, y01, y10,
+						y11, u, v, iWidth, pOut1);
+					pOut1 += 6;
+				}
+				pOut1 += (iWidth*2 - 8) * 3;
+				pIn += 8;
+			}
+			pOut += 8 * 3;
+		}
+	}
+#else
+
+#ifndef OV511_FORCE_MONO
+	/* Just dump pix data straight out for debug */
+	int i, j;
+
+	pOut0 += iOutY;
+	for (i = 0; i < HDIV; i++) {
+		for (j = 0; j < WDIV; j++) {
+			*pOut0++ = *pIn0++;
+			*pOut0++ = *pIn0++;
+			*pOut0++ = *pIn0++;
+		}
+		pOut0 += (iWidth - WDIV) * 3;
+	}
+#else
+
+#if 1
+	/* This converts the Y data to "black-and-white" RGB data */
+	/* Useful for experimenting with compression */
+	int k, l, m;
+	unsigned char *pIn, *pOut, *pOut1;
+
+	pIn = pIn0 + 128;
+	pOut = pOut0 + iOutY;
+	for (k = 0; k < 4; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			for (m = 0; m < 8; m++) {
+				*pOut1++ = *pIn;
+				*pOut1++ = *pIn;
+				*pOut1++ = *pIn++;
+			}
+			pOut1 += (iWidth - 8) * 3;
+		}
+		pOut += 8 * 3;
+	}
+#else
+	/* This will dump the Y channel data stream as-is */ 
+	int count;
+	unsigned char *pIn, *pOut;
+
+	pIn = pIn0 + 128;
+	pOut = pOut0 + output_offset;
+	for (count = 0; count < 256; count++) {
+		*pOut++ = *pIn;
+		*pOut++ = *pIn;
+		*pOut++ = *pIn++;
+		output_offset += 3;
+	}	
+#endif
+
+#endif
+
+#endif
+}
+#endif
+
+/* This converts YUV420 segments to YUYV */
+static void
+ov511_parse_data_yuv422(unsigned char *pIn0, unsigned char *pOut0,
+		        int iOutY, int iOutUV, int iWidth)
+{
+	int k, l, m;
+	unsigned char *pIn, *pOut, *pOut1;
+
+	pIn = pIn0 + 128;
+	pOut = pOut0 + iOutY;
+	for (k = 0; k < 4; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			for (m = 0; m < 8; m++) {
+				*pOut1 = (*pIn++);
+				pOut1 += 2;
+			}
+			pOut1 += (iWidth - 8) * 2;
+		}
+		pOut += 8 * 2;
+	}
+
+	pIn = pIn0;
+	pOut = pOut0 + iOutUV + 1;
+	for (l = 0; l < 8; l++) {
+		for (m=0; m<8; m++) {
+			int v   = *(pIn+64);
+			int u   = *pIn++;
+			
+			*pOut = u;
+			*(pOut+2) = v;
+			*(pOut+iWidth) = u;
+			*(pOut+iWidth+2) = v;
+			pOut += 4;
+		}
+		pOut += (iWidth*4 - 32);
+	}
+}
+
+static void
+ov511_parse_data_yuv420(unsigned char *pIn0, unsigned char *pOut0,
+		        int iOutY, int iOutUV, int iWidth, int iHeight)
+{
+	int k, l, m;
+	unsigned char *pIn;
+	unsigned char *pOut, *pOut1;
+	unsigned a = iWidth * iHeight;
+	unsigned w = iWidth / 2;
+
+	pIn = pIn0;
+	pOut = pOut0 + iOutUV + a;
+	for (k = 0; k < 8; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) *pOut1++ = *pIn++;
+		pOut += w;
+	}
+
+	pIn = pIn0 + 64;
+	pOut = pOut0 + iOutUV + a + a/4;
+	for (k = 0; k < 8; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) *pOut1++ = *pIn++;
+		pOut += w;
+	}
+
+	pIn = pIn0 + 128;
+	pOut = pOut0 + iOutY;
+	for (k = 0; k < 4; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			for (m = 0; m < 8; m++)
+				*pOut1++ =*pIn++;
+			pOut1 += iWidth - 8;
+		}
+		pOut += 8;
+	}
+}
+
+static void
+ov511_parse_data_yuv422p(unsigned char *pIn0, unsigned char *pOut0,
+		       int iOutY, int iOutUV, int iWidth, int iHeight)
+{
+	int k, l, m;
+	unsigned char *pIn;
+	unsigned char *pOut, *pOut1;
+	unsigned a = iWidth * iHeight;
+	unsigned w = iWidth / 2;
+
+	pIn = pIn0;
+	pOut = pOut0 + iOutUV + a;
+	for (k = 0; k < 8; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			*pOut1 = *(pOut1 + w) = *pIn++;
+			pOut1++;
+		}
+		pOut += iWidth;
+	}
+
+	pIn = pIn0 + 64;
+	pOut = pOut0 + iOutUV + a + a/2;
+	for (k = 0; k < 8; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			*pOut1 = *(pOut1 + w) = *pIn++;
+			pOut1++;
+		}
+		pOut += iWidth;
+	}
+
+	pIn = pIn0 + 128;
+	pOut = pOut0 + iOutY;
+	for (k = 0; k < 4; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			for (m = 0; m < 8; m++)
+				*pOut1++ =*pIn++;
+			pOut1 += iWidth - 8;
+		}
+		pOut += 8;
+	}
+}
+
+/*
+ * For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
+ * The segments represent 4 squares of 8x8 pixels as follows:
+ *
+ *      0  1 ...  7    64  65 ...  71   ...  192 193 ... 199
+ *      8  9 ... 15    72  73 ...  79        200 201 ... 207
+ *           ...              ...                    ...
+ *     56 57 ... 63   120 121 ... 127        248 249 ... 255
+ *
+ */ 
+static void
+ov511_parse_data_grey(unsigned char *pIn0, unsigned char *pOut0,
+		      int iOutY, int iWidth)		    
+{
+	int k, l, m;
+	unsigned char *pIn;
+	unsigned char *pOut, *pOut1;
+
+	pIn = pIn0;
+	pOut = pOut0 + iOutY;
+	for (k = 0; k < 4; k++) {
+		pOut1 = pOut;
+		for (l = 0; l < 8; l++) {
+			for (m = 0; m < 8; m++) {
+				*pOut1++ = *pIn++;
+			}
+			pOut1 += iWidth - 8;
+		}
+		pOut += 8;
+	}
+}
+
+/*
+ * fixFrameRGBoffset--
+ * My camera seems to return the red channel about 1 pixel
+ * low, and the blue channel about 1 pixel high. After YUV->RGB
+ * conversion, we can correct this easily. OSL 2/24/2000.
+ */
+static void fixFrameRGBoffset(struct ov511_frame *frame)
+{
+	int x, y;
+	int rowBytes = frame->width*3, w = frame->width;
+	unsigned char *rgb = frame->data;
+	const int shift = 1;  /* Distance to shift pixels by, vertically */
+
+	/* Don't bother with little images */
+	if (frame->width < 400) 
+		return;
+
+	/* Shift red channel up */
+	for (y = shift; y < frame->height; y++)	{
+		int lp = (y-shift)*rowBytes;     /* Previous line offset */
+		int lc = y*rowBytes;             /* Current line offset */
+		for (x = 0; x < w; x++)
+			rgb[lp+x*3+2] = rgb[lc+x*3+2]; /* Shift red up */
+	}
+
+	/* Shift blue channel down */
+	for (y = frame->height-shift-1; y >= 0; y--) {
+		int ln = (y + shift) * rowBytes;  /* Next line offset */
+		int lc = y * rowBytes;            /* Current line offset */
+		for (x = 0; x < w; x++)
+			rgb[ln+x*3+0] = rgb[lc+x*3+0]; /* Shift blue down */
+	}
+}
+
+/**********************************************************************
+ *
+ * OV511 data transfer, IRQ handler
+ *
+ **********************************************************************/
+
+static int ov511_move_data(struct usb_ov511 *ov511, urb_t *urb)
+{
+	unsigned char *cdata;
+	int i, totlen = 0;
+	int aPackNum[10];
+	struct ov511_frame *frame;
+	unsigned char *pData;
+	int iPix;
+
+	PDEBUG (4, "Moving %d packets", urb->number_of_packets);
+
+	for (i = 0; i < urb->number_of_packets; i++) {
+		int n = urb->iso_frame_desc[i].actual_length;
+		int st = urb->iso_frame_desc[i].status;
+
+		urb->iso_frame_desc[i].actual_length = 0;
+		urb->iso_frame_desc[i].status = 0;
+
+		cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+		aPackNum[i] = n ? cdata[ov511->packet_size - 1] : -1;
+
+		if (!n || ov511->curframe == -1)
+			continue;
+
+		if (st)
+			PDEBUG(2, "data error: [%d] len=%d, status=%d", i, n, st);
+
+		frame = &ov511->frame[ov511->curframe];
+		
+		/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
+		 * byte non-zero. The EOF packet has image width/height in the
+		 * 10th and 11th packets. The 9th bit is given as follows:
+		 *
+		 * bit 7: EOF
+		 *     6: compression enabled
+		 *     5: 422/420/400 modes
+		 *     4: 422/420/400 modes
+		 *     3: 1
+		 *     2: snapshot bottom on
+		 *     1: snapshot frame
+		 *     0: even/odd field
+		 */
+
+		/* Check for SOF/EOF packet */
+		if ((cdata[0] | cdata[1] | cdata[2] | cdata[3] | 
+		     cdata[4] | cdata[5] | cdata[6] | cdata[7]) ||
+		     (~cdata[8] & 0x08))
+			goto check_middle;
+
+		/* Frame end */
+		if (cdata[8] & 0x80) {
+			struct timeval *ts;
+
+			ts = (struct timeval *)(frame->data + MAX_FRAME_SIZE);
+			do_gettimeofday (ts);
+
+		 	PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d",
+				ov511->curframe, (int)(cdata[ov511->packet_size - 1]),
+				(int)(cdata[9]), (int)(cdata[10]));
+
+			if (frame->scanstate == STATE_LINES) {
+		    		int iFrameNext;
+
+				if (fix_rgb_offset)
+					fixFrameRGBoffset(frame);
+				frame->grabstate = FRAME_DONE;
+
+				if (waitqueue_active(&frame->wq)) {
+					frame->grabstate = FRAME_DONE;
+					wake_up_interruptible(&frame->wq);
+				}
+
+				/* If next frame is ready or grabbing,
+                                 * point to it */
+				iFrameNext = (ov511->curframe + 1) % OV511_NUMFRAMES;
+				if (ov511->frame[iFrameNext].grabstate == FRAME_READY
+				    || ov511->frame[iFrameNext].grabstate == FRAME_GRABBING) {
+					ov511->curframe = iFrameNext;
+					ov511->frame[iFrameNext].scanstate = STATE_SCANNING;
+				} else {
+					if (frame->grabstate == FRAME_DONE) {
+						PDEBUG(4, "Frame done! congratulations");
+					} else {
+						PDEBUG(4, "Frame not ready? state = %d",
+							ov511->frame[iFrameNext].grabstate);
+					}
+
+					ov511->curframe = -1;
+				}
+			}
+			/* Image corruption caused by misplaced frame->segment = 0
+			 * fixed by carlosf@conectiva.com.br
+			 */
+		} else {
+			/* Frame start */
+			PDEBUG(4, "Frame start, framenum = %d", ov511->curframe);
+
+			output_offset = 0;
+
+			/* Check to see if it's a snapshot frame */
+			/* FIXME?? Should the snapshot reset go here? Performance? */
+			if (cdata[8] & 0x02) {
+				frame->snapshot = 1;
+				PDEBUG(3, "snapshot detected");
+			}
+
+			frame->scanstate = STATE_LINES;
+			frame->segment = 0;
+		}
+
+check_middle:
+		/* Are we in a frame? */
+		if (frame->scanstate != STATE_LINES)
+			continue;
+
+		/* Deal with leftover from last segment, if any */
+		if (frame->segment) {
+			pData = ov511->scratch;
+			iPix = -ov511->scratchlen;
+			memmove(pData + ov511->scratchlen, cdata,
+				iPix+frame->segsize);
+		} else {
+			pData = &cdata[iPix = 9];
+	 	}
+
+		/* Parse the segments */
+		while (iPix <= (ov511->packet_size - 1) - frame->segsize &&
+		    frame->segment < frame->width * frame->height / 256) {
+			int iSegY, iSegUV;
+			int iY, jY, iUV, jUV;
+			int iOutY, iOutYP, iOutUV, iOutUVP;
+			unsigned char *pOut;
+
+			iSegY = iSegUV = frame->segment;
+			pOut = frame->data;
+			frame->segment++;
+			iPix += frame->segsize;
+
+			/* Handle subwindow */
+			if (frame->sub_flag) {
+				int iSeg1;
+
+				iSeg1 = iSegY / (ov511->subw / 32);
+				iSeg1 *= frame->width / 32;
+				iSegY = iSeg1 + (iSegY % (ov511->subw / 32));
+				if (iSegY >= frame->width * ov511->subh / 256)
+					break;
+
+				iSeg1 = iSegUV / (ov511->subw / 16);
+				iSeg1 *= frame->width / 16;
+				iSegUV = iSeg1 + (iSegUV % (ov511->subw / 16));
+
+				pOut += (ov511->subx + ov511->suby * frame->width) *
+					(frame->depth >> 3);
+			}
+
+			/* 
+			 * i counts segment lines
+			 * j counts segment columns
+			 * iOut is the offset (in bytes) of the upper left corner
+			 */
+			iY = iSegY / (frame->width / WDIV);
+			jY = iSegY - iY * (frame->width / WDIV);
+			iOutYP = iY*HDIV*frame->width + jY*WDIV;
+			iOutY = iOutYP * (frame->depth >> 3);
+			iUV = iSegUV / (frame->width / WDIV * 2);
+			jUV = iSegUV - iUV * (frame->width / WDIV * 2);
+			iOutUVP = iUV*HDIV*2*frame->width + jUV*WDIV/2;
+			iOutUV = iOutUVP * (frame->depth >> 3);
+
+			switch (frame->format) {
+			case VIDEO_PALETTE_GREY:
+				ov511_parse_data_grey (pData, pOut, iOutY, frame->width);
+				break;
+			case VIDEO_PALETTE_RGB24:
+				ov511_parse_data_rgb24 (pData, pOut, iOutY, iOutUV,
+					iY & 1, frame->width);
+				break;
+			case VIDEO_PALETTE_YUV422:
+			case VIDEO_PALETTE_YUYV:
+				ov511_parse_data_yuv422(pData, pOut, iOutY, iOutUV, frame->width);
+				break;
+			case VIDEO_PALETTE_YUV420:
+				ov511_parse_data_yuv420 (pData, pOut, iOutYP, iUV*HDIV*frame->width/2 + jUV*WDIV/4,
+					frame->width, frame->height);
+				break;
+			case VIDEO_PALETTE_YUV422P:
+				ov511_parse_data_yuv422p (pData, pOut, iOutYP, iOutUVP/2,
+					frame->width, frame->height);
+				break;
+			default:
+				err("Unsupported format: %d", frame->format);
+			}
+
+			pData = &cdata[iPix];
+		}
+
+		/* Save extra data for next time */
+		if (frame->segment < frame->width * frame->height / 256) {
+			ov511->scratchlen = (ov511->packet_size - 1) - iPix;
+			if (ov511->scratchlen < frame->segsize)
+				memmove(ov511->scratch, pData, ov511->scratchlen);
+			else
+				ov511->scratchlen = 0;
+		}
+	}
+
+	PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d",
+	       aPackNum[0], aPackNum[1], aPackNum[2], aPackNum[3], aPackNum[4],
+	       aPackNum[5],aPackNum[6], aPackNum[7], aPackNum[8], aPackNum[9]);
+
+	return totlen;
+}
+
+static void ov511_isoc_irq(struct urb *urb)
+{
+	int len;
+	struct usb_ov511 *ov511 = urb->context;
+	struct ov511_sbuf *sbuf;
+
+	if (!ov511->dev)
+		return;
+
+	if (!ov511->streaming) {
+		PDEBUG(4, "hmmm... not streaming, but got interrupt");
+		return;
+	}
+	
+	sbuf = &ov511->sbuf[ov511->cursbuf];
+
+	/* Copy the data received into our scratch buffer */
+	if (ov511->curframe >= 0) {
+		len = ov511_move_data(ov511, urb);
+	} else if (waitqueue_active(&ov511->wq)) {
+		wake_up_interruptible(&ov511->wq);
+	}
+
+	/* Move to the next sbuf */
+	ov511->cursbuf = (ov511->cursbuf + 1) % OV511_NUMSBUF;
+
+	return;
+}
+
+static int ov511_init_isoc(struct usb_ov511 *ov511)
+{
+	urb_t *urb;
+	int fx, err, n, size;
+
+	PDEBUG(3, "*** Initializing capture ***");
+
+	ov511->compress = 0;
+	ov511->curframe = -1;
+	ov511->cursbuf = 0;
+	ov511->scratchlen = 0;
+
+	if (ov511->bridge == BRG_OV511)
+		if (cams == 1)			 size = 993;
+		else if (cams == 2)		 size = 513;
+		else if (cams == 3 || cams == 4) size = 257;
+		else {
+			err("\"cams\" parameter too high!");
+			return -1;
+		}
+	else if (ov511->bridge == BRG_OV511PLUS)
+		if (cams == 1)                      size = 961;
+		else if (cams == 2)                 size = 513;
+		else if (cams == 3 || cams == 4) size = 257;
+		else if (cams >= 5 && cams <= 8)    size = 129;
+		else if (cams >= 9 && cams <= 31)   size = 33;
+		else {
+			err("\"cams\" parameter too high!");
+			return -1;
+		}
+	else {
+		err("invalid bridge type");
+		return -1;
+	}
+
+	ov511_set_packet_size(ov511, size);
+
+	for (n = 0; n < OV511_NUMSBUF; n++) {
+		urb = usb_alloc_urb(FRAMES_PER_DESC);
+	
+		if (!urb) {
+			err("init isoc: usb_alloc_urb ret. NULL");
+			return -ENOMEM;
+		}
+		ov511->sbuf[n].urb = urb;
+		urb->dev = ov511->dev;
+		urb->context = ov511;
+		urb->pipe = usb_rcvisocpipe(ov511->dev, OV511_ENDPOINT_ADDRESS);
+		urb->transfer_flags = USB_ISO_ASAP;
+		urb->transfer_buffer = ov511->sbuf[n].data;
+		urb->complete = ov511_isoc_irq;
+		urb->number_of_packets = FRAMES_PER_DESC;
+		urb->transfer_buffer_length = ov511->packet_size * FRAMES_PER_DESC;
+		for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
+			urb->iso_frame_desc[fx].offset = ov511->packet_size * fx;
+			urb->iso_frame_desc[fx].length = ov511->packet_size;
+		}
+	}
+
+	ov511->sbuf[OV511_NUMSBUF - 1].urb->next = ov511->sbuf[0].urb;
+	for (n = 0; n < OV511_NUMSBUF - 1; n++)
+		ov511->sbuf[n].urb->next = ov511->sbuf[n+1].urb;
+
+	for (n = 0; n < OV511_NUMSBUF; n++) {
+		err = usb_submit_urb(ov511->sbuf[n].urb);
+		if (err)
+			err("init isoc: usb_submit_urb(%d) ret %d", n, err);
+	}
+
+	ov511->streaming = 1;
+
+	return 0;
+}
+
+static void ov511_stop_isoc(struct usb_ov511 *ov511)
+{
+	int n;
+
+	if (!ov511->streaming || !ov511->dev)
+		return;
+
+	PDEBUG (3, "*** Stopping capture ***");
+
+	ov511_set_packet_size(ov511, 0);
+
+	ov511->streaming = 0;
+
+	/* Unschedule all of the iso td's */
+	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
+		if (ov511->sbuf[n].urb) {
+			ov511->sbuf[n].urb->next = NULL;
+			usb_unlink_urb(ov511->sbuf[n].urb);
+			usb_free_urb(ov511->sbuf[n].urb);
+			ov511->sbuf[n].urb = NULL;
+		}
+	}
+}
+
+static int ov511_new_frame(struct usb_ov511 *ov511, int framenum)
+{
+	struct ov511_frame *frame;
+
+	PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe,
+		framenum);
+	if (!ov511->dev)
+		return -1;
+
+	/* If we're not grabbing a frame right now and the other frame is */
+	/* ready to be grabbed into, then use it instead */
+	if (ov511->curframe == -1) {
+		if (ov511->frame[(framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES].grabstate == FRAME_READY)
+			framenum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
+	} else
+		return 0;
+
+	frame = &ov511->frame[framenum];
+
+	PDEBUG (4, "framenum = %d, width = %d, height = %d", framenum, 
+		frame->width, frame->height);
+
+	frame->grabstate = FRAME_GRABBING;
+	frame->scanstate = STATE_SCANNING;
+	frame->scanlength = 0;		/* accumulated in ov511_parse_data() */
+	frame->snapshot = 0;
+
+	ov511->curframe = framenum;
+
+	/* Make sure it's not too big */
+	if (frame->width > ov511->maxwidth)
+		frame->width = ov511->maxwidth;
+
+	frame->width &= ~7L;		/* Multiple of 8 */
+
+	if (frame->height > ov511->maxheight)
+		frame->height = ov511->maxheight;
+
+	frame->height &= ~3L;		/* Multiple of 4 */
+
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * Buffer management
+ *
+ ***************************************************************************/
+static int ov511_alloc(struct usb_ov511 *ov511)
+{
+	int i;
+
+	PDEBUG(4, "entered");
+	down(&ov511->buf_lock);
+
+	if (ov511->buf_state == BUF_PEND_DEALLOC) {
+		ov511->buf_state = BUF_ALLOCATED;
+		del_timer(&ov511->buf_timer);
+	}
+
+	if (ov511->buf_state == BUF_ALLOCATED)
+		goto out;
+
+	ov511->fbuf = rvmalloc(OV511_NUMFRAMES * MAX_DATA_SIZE);
+	if (!ov511->fbuf)
+		goto error;
+
+	for (i = 0; i < OV511_NUMFRAMES; i++) {
+		ov511->frame[i].grabstate = FRAME_UNUSED;
+		ov511->frame[i].data = ov511->fbuf + i * MAX_DATA_SIZE;
+		PDEBUG(4, "frame[%d] @ %p", i, ov511->frame[i].data);
+
+		ov511->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
+			MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
+		if (!ov511->sbuf[i].data) {
+			while (--i) {
+				kfree(ov511->sbuf[i].data);
+				ov511->sbuf[i].data = NULL;
+			}
+			rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE);
+			ov511->fbuf = NULL;
+			goto error;
+		}
+		PDEBUG(4, "sbuf[%d] @ %p", i, ov511->sbuf[i].data);
+	}
+	ov511->buf_state = BUF_ALLOCATED;
+out:
+	up(&ov511->buf_lock);
+	PDEBUG(4, "leaving");
+	return 0;
+error:
+	ov511->buf_state = BUF_NOT_ALLOCATED;
+	up(&ov511->buf_lock);
+	PDEBUG(4, "errored");
+	return -ENOMEM;
+}
+
+/* 
+ * - You must acquire buf_lock before entering this function.
+ * - Because this code will free any non-null pointer, you must be sure to null
+ *   them if you explicitly free them somewhere else!
+ */
+static void ov511_do_dealloc(struct usb_ov511 *ov511)
+{
+	int i;
+	PDEBUG(4, "entered");
+
+	if (ov511->fbuf) {
+		rvfree(ov511->fbuf, OV511_NUMFRAMES * MAX_DATA_SIZE);
+		ov511->fbuf = NULL;
+	}
+
+	for (i = 0; i < OV511_NUMFRAMES; i++) {
+		if (ov511->sbuf[i].data) {
+			kfree(ov511->sbuf[i].data);
+			ov511->sbuf[i].data = NULL;
+		}
+	}
+
+	PDEBUG(4, "buffer memory deallocated");
+	ov511->buf_state = BUF_NOT_ALLOCATED;
+	PDEBUG(4, "leaving");
+}
+
+static void ov511_buf_callback(unsigned long data)
+{
+	struct usb_ov511 *ov511 = (struct usb_ov511 *)data;
+	PDEBUG(4, "entered");
+	down(&ov511->buf_lock);
+
+	if (ov511->buf_state == BUF_PEND_DEALLOC)
+		ov511_do_dealloc(ov511);
+
+	up(&ov511->buf_lock);
+	PDEBUG(4, "leaving");
+}
+
+static void ov511_dealloc(struct usb_ov511 *ov511, int now)
+{
+	struct timer_list *bt = &(ov511->buf_timer);
+	PDEBUG(4, "entered");
+	down(&ov511->buf_lock);
+
+	PDEBUG(4, "deallocating buffer memory %s", now ? "now" : "later");
+
+	if (ov511->buf_state == BUF_PEND_DEALLOC) {
+		ov511->buf_state = BUF_ALLOCATED;
+		del_timer(bt);
+	}
+
+	if (now)
+		ov511_do_dealloc(ov511);
+	else {
+		ov511->buf_state = BUF_PEND_DEALLOC;
+		init_timer(bt);
+		bt->function = ov511_buf_callback;
+		bt->data = (unsigned long)ov511;
+		bt->expires = jiffies + buf_timeout * HZ;
+		add_timer(bt);
+	}
+	up(&ov511->buf_lock);
+	PDEBUG(4, "leaving");
+}
+
+/****************************************************************************
+ *
+ * V4L API
+ *
+ ***************************************************************************/
+
+static int ov511_open(struct video_device *dev, int flags)
+{
+	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+	int err = 0;
+
+	MOD_INC_USE_COUNT;
+	PDEBUG(4, "opening");
+	down(&ov511->lock);
+
+	err = -EBUSY;
+	if (ov511->user) 
+		goto out;
+
+	err = -ENOMEM;
+	if (ov511_alloc(ov511))
+		goto out;
+
+	ov511->sub_flag = 0;
+
+	err = ov511_init_isoc(ov511);
+	if (err) {
+		ov511_dealloc(ov511, 0);
+		goto out;
+	}
+
+	ov511->user++;
+
+out:
+	up(&ov511->lock);
+
+	if (err)
+		MOD_DEC_USE_COUNT;
+
+	return err;
+}
+
+static void ov511_close(struct video_device *dev)
+{
+	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+
+	PDEBUG(4, "ov511_close");
+	
+	down(&ov511->lock);
+
+	ov511->user--;
+	ov511_stop_isoc(ov511);
+
+	if (ov511->dev)
+		ov511_dealloc(ov511, 0);
+
+	up(&ov511->lock);
+
+	if (!ov511->dev) {
+		ov511_dealloc(ov511, 1);
+		video_unregister_device(&ov511->vdev);
+		kfree(ov511);
+		ov511 = NULL;
+	}
+
+	MOD_DEC_USE_COUNT;
+}
+
+static int ov511_init_done(struct video_device *dev)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	create_proc_ov511_cam((struct usb_ov511 *)dev);
+#endif
+
+	return 0;
+}
+
+static long ov511_write(struct video_device *dev, const char *buf, unsigned long count, int noblock)
+{
+	return -EINVAL;
+}
+
+static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+	struct usb_ov511 *ov511 = (struct usb_ov511 *)vdev;
+
+	PDEBUG(4, "IOCtl: 0x%X", cmd);
+
+	if (!ov511->dev)
+		return -EIO;	
+
+	switch (cmd) {
+	case VIDIOCGCAP:
+	{
+		struct video_capability b;
+
+		PDEBUG (4, "VIDIOCGCAP");
+
+		strcpy(b.name, "OV511 USB Camera");
+		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
+		b.channels = 1;
+		b.audios = 0;
+		b.maxwidth = ov511->maxwidth;
+		b.maxheight = ov511->maxheight;
+		b.minwidth = 32;
+		b.minheight = 16;
+
+		if (copy_to_user(arg, &b, sizeof(b)))
+			return -EFAULT;
+				
+		return 0;
+	}
+	case VIDIOCGCHAN:
+	{
+		struct video_channel v;
+
+		if (copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
+		if (v.channel != 0)
+			return -EINVAL;
+
+		v.flags = 0;
+		v.tuners = 0;
+		v.type = VIDEO_TYPE_CAMERA;
+		strcpy(v.name, "Camera");
+
+		if (copy_to_user(arg, &v, sizeof(v)))
+			return -EFAULT;
+				
+		return 0;
+	}
+	case VIDIOCSCHAN:
+	{
+		int v;
+
+		if (copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
+
+		if (v != 0)
+			return -EINVAL;
+
+		return 0;
+	}
+	case VIDIOCGPICT:
+	{
+		struct video_picture p;
+
+		PDEBUG (4, "VIDIOCGPICT");
+
+		if (ov7610_get_picture(ov511, &p))
+			return -EIO;
+							
+		if (copy_to_user(arg, &p, sizeof(p)))
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCSPICT:
+	{
+		struct video_picture p;
+		int i;
+
+		PDEBUG (4, "VIDIOCSPICT");
+
+		if (copy_from_user(&p, arg, sizeof(p)))
+			return -EFAULT;
+
+		if (p.palette != VIDEO_PALETTE_GREY &&
+		    p.palette != VIDEO_PALETTE_RGB24 &&
+		    p.palette != VIDEO_PALETTE_YUV422 &&
+		    p.palette != VIDEO_PALETTE_YUYV &&
+		    p.palette != VIDEO_PALETTE_YUV420 &&
+		    p.palette != VIDEO_PALETTE_YUV422P)
+			return -EINVAL;
+			
+		if (ov7610_set_picture(ov511, &p))
+			return -EIO;
+
+		PDEBUG(4, "Setting depth=%d, palette=%d", p.depth, p.palette);
+		for (i = 0; i < OV511_NUMFRAMES; i++) {
+			ov511->frame[i].depth = p.depth;
+			ov511->frame[i].format = p.palette;
+			ov511->frame[i].segsize = GET_SEGSIZE(p.palette);
+		}
+
+		return 0;
+	}
+	case VIDIOCGCAPTURE:
+	{
+		int vf;
+
+		PDEBUG (4, "VIDIOCGCAPTURE");
+
+		if (copy_from_user(&vf, arg, sizeof(vf)))
+			return -EFAULT;
+		ov511->sub_flag = vf;
+		return 0;
+	}
+	case VIDIOCSCAPTURE:
+	{
+		struct video_capture vc;
+
+		if (copy_from_user(&vc, arg, sizeof(vc)))
+			return -EFAULT;
+		if (vc.flags)
+			return -EINVAL;
+		if (vc.decimation)
+			return -EINVAL;
+
+		vc.x &= ~3L;
+		vc.y &= ~1L;
+		vc.y &= ~31L;
+
+		if (vc.width == 0)
+			vc.width = 32;
+
+		vc.height /= 16;
+		vc.height *= 16;
+		if (vc.height == 0)
+			vc.height = 16;
+
+		ov511->subx = vc.x;
+		ov511->suby = vc.y;
+		ov511->subw = vc.width;
+		ov511->subh = vc.height;
+
+		return 0;
+	}
+	case VIDIOCSWIN:
+	{
+		struct video_window vw;
+		int i, result;
+
+		if (copy_from_user(&vw, arg, sizeof(vw)))
+			return -EFAULT;
+
+		PDEBUG (4, "VIDIOCSWIN: width=%d, height=%d",
+			vw.width, vw.height);
+
+#if 0
+		if (vw.flags)
+			return -EINVAL;
+		if (vw.clipcount)
+			return -EINVAL;
+		if (vw.height != ov511->maxheight)
+			return -EINVAL;
+		if (vw.width != ov511->maxwidth)
+			return -EINVAL;
+#endif
+
+		/* If we're collecting previous frame wait
+		   before changing modes */
+		interruptible_sleep_on(&ov511->wq);
+		if (signal_pending(current)) return -EINTR;
+
+		result = ov511_mode_init_regs(ov511, vw.width, vw.height,
+			ov511->frame[0].format, ov511->sub_flag);
+		if (result < 0)
+			return result;
+
+		for (i = 0; i < OV511_NUMFRAMES; i++) {
+			ov511->frame[i].width = vw.width;
+			ov511->frame[i].height = vw.height;
+		}
+
+		return 0;
+	}
+	case VIDIOCGWIN:
+	{
+		struct video_window vw;
+
+		vw.x = 0;		/* FIXME */
+		vw.y = 0;
+		vw.width = ov511->frame[0].width;
+		vw.height = ov511->frame[0].height;
+		vw.chromakey = 0;
+		vw.flags = 30;
+
+		PDEBUG (4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
+
+		if (copy_to_user(arg, &vw, sizeof(vw)))
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf vm;
+
+		memset(&vm, 0, sizeof(vm));
+		vm.size = OV511_NUMFRAMES * MAX_DATA_SIZE;
+		vm.frames = OV511_NUMFRAMES;
+		vm.offsets[0] = 0;
+		vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval);
+
+		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCMCAPTURE:
+	{
+		struct video_mmap vm;
+		int ret;
+
+		if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm)))
+			return -EFAULT;
+
+		PDEBUG(4, "CMCAPTURE");
+		PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
+			vm.frame, vm.width, vm.height, vm.format);
+
+		if (vm.format != VIDEO_PALETTE_RGB24 &&
+		    vm.format != VIDEO_PALETTE_YUV422 &&
+		    vm.format != VIDEO_PALETTE_YUYV &&
+		    vm.format != VIDEO_PALETTE_YUV420 &&
+		    vm.format != VIDEO_PALETTE_YUV422P &&
+		    vm.format != VIDEO_PALETTE_GREY)
+			return -EINVAL;
+
+		if ((vm.frame != 0) && (vm.frame != 1))
+			return -EINVAL;
+				
+		if (vm.width > ov511->maxwidth || vm.height > ov511->maxheight)
+			return -EINVAL;
+
+		if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING)
+			return -EBUSY;
+
+		/* Don't compress if the size changed */
+		if ((ov511->frame[vm.frame].width != vm.width) ||
+		    (ov511->frame[vm.frame].height != vm.height) ||
+		    (ov511->frame[vm.frame].format != vm.format) ||
+		    (ov511->frame[vm.frame].sub_flag !=
+		     ov511->sub_flag)) {
+			/* If we're collecting previous frame wait
+			   before changing modes */
+			interruptible_sleep_on(&ov511->wq);
+			if (signal_pending(current)) return -EINTR;
+			ret = ov511_mode_init_regs(ov511, vm.width, vm.height,
+				vm.format, ov511->sub_flag);
+#if 0
+			if (ret < 0)
+				return ret;
+#endif
+		}
+
+		ov511->frame[vm.frame].width = vm.width;
+		ov511->frame[vm.frame].height = vm.height;
+		ov511->frame[vm.frame].format = vm.format;
+		ov511->frame[vm.frame].sub_flag = ov511->sub_flag;
+		ov511->frame[vm.frame].segsize = GET_SEGSIZE(vm.format);
+		ov511->frame[vm.frame].depth = GET_DEPTH(vm.format);
+
+		/* Mark it as ready */
+		ov511->frame[vm.frame].grabstate = FRAME_READY;
+
+		return ov511_new_frame(ov511, vm.frame);
+	}
+	case VIDIOCSYNC:
+	{
+		int frame;
+
+		if (copy_from_user((void *)&frame, arg, sizeof(int)))
+			return -EFAULT;
+
+		PDEBUG(4, "syncing to frame %d, grabstate = %d", frame,
+		       ov511->frame[frame].grabstate);
+
+		switch (ov511->frame[frame].grabstate) {
+		case FRAME_UNUSED:
+			return -EINVAL;
+		case FRAME_READY:
+		case FRAME_GRABBING:
+		case FRAME_ERROR:
+redo:
+			if (!ov511->dev)
+				return -EIO;
+
+			do {
+#if 0
+				init_waitqueue_head(&ov511->frame[frame].wq);
+#endif
+				interruptible_sleep_on(&ov511->frame[frame].wq);
+				if (signal_pending(current)) {
+					if (retry_sync) {
+						PDEBUG(3, "***retry sync***");
+
+						/* Polling apps will destroy frames with that! */
+						ov511_new_frame(ov511, frame);
+						ov511->curframe = -1;
+
+						/* This will request another frame. */
+						if (waitqueue_active(&ov511->frame[frame].wq))
+							wake_up_interruptible(&ov511->frame[frame].wq);
+
+						return 0;
+ 					} else {
+						return -EINTR;
+					}
+				}
+			} while (ov511->frame[frame].grabstate == FRAME_GRABBING);
+
+			if (ov511->frame[frame].grabstate == FRAME_ERROR) {
+				int ret;
+
+				if ((ret = ov511_new_frame(ov511, frame)) < 0)
+					return ret;
+				goto redo;
+			}			
+		case FRAME_DONE:
+			ov511->frame[frame].grabstate = FRAME_UNUSED;
+
+			/* Reset the hardware snapshot button */
+			/* FIXME - Is this the best place for this? */
+			if ((ov511->snap_enabled) &&
+			    (ov511->frame[frame].snapshot)) {
+				ov511->frame[frame].snapshot = 0;
+				ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
+				ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03);
+				ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
+			}
+			break;
+		} /* end switch */
+
+		return 0;
+	}
+	case VIDIOCGFBUF:
+	{
+		struct video_buffer vb;
+
+		memset(&vb, 0, sizeof(vb));
+		vb.base = NULL;	/* frame buffer not supported, not used */
+
+		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCKEY:
+		return 0;
+	case VIDIOCCAPTURE:
+		return -EINVAL;
+	case VIDIOCSFBUF:
+		return -EINVAL;
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+		return -EINVAL;
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		return -EINVAL;
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		return -EINVAL;
+	default:
+		return -ENOIOCTLCMD;
+	} /* end switch */
+
+	return 0;
+}
+
+static long ov511_read(struct video_device *dev, char *buf, unsigned long count, int noblock)
+{
+	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+	int i;
+	int frmx = -1;
+	volatile struct ov511_frame *frame;
+
+	PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
+
+	if (!dev || !buf)
+		return -EFAULT;
+
+	if (!ov511->dev)
+		return -EIO;
+
+	/* See if a frame is completed, then use it. */
+	if (ov511->frame[0].grabstate >= FRAME_DONE)	/* _DONE or _ERROR */
+		frmx = 0;
+	else if (ov511->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
+		frmx = 1;
+
+	/* If nonblocking we return immediately */
+	if (noblock && (frmx == -1))
+		return -EAGAIN;
+
+	/* If no FRAME_DONE, look for a FRAME_GRABBING state. */
+	/* See if a frame is in process (grabbing), then use it. */
+	if (frmx == -1) {
+		if (ov511->frame[0].grabstate == FRAME_GRABBING)
+			frmx = 0;
+		else if (ov511->frame[1].grabstate == FRAME_GRABBING)
+			frmx = 1;
+	}
+
+	/* If no frame is active, start one. */
+	if (frmx == -1)
+		ov511_new_frame(ov511, frmx = 0);
+
+	frame = &ov511->frame[frmx];
+
+restart:
+	if (!ov511->dev)
+		return -EIO;
+
+	/* Wait while we're grabbing the image */
+	PDEBUG(4, "Waiting image grabbing");
+	while (frame->grabstate == FRAME_GRABBING) {
+		interruptible_sleep_on(&ov511->frame[frmx].wq);
+		if (signal_pending(current))
+			return -EINTR;
+	}
+	PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
+
+	if (frame->grabstate == FRAME_ERROR) {
+		frame->bytes_read = 0;
+		err("** ick! ** Errored frame %d", ov511->curframe);
+		if (ov511_new_frame(ov511, frmx))
+			err("read: ov511_new_frame error");
+		goto restart;
+	}
+
+
+	/* Repeat until we get a snapshot frame */
+	if (ov511->snap_enabled)
+		PDEBUG (4, "Waiting snapshot frame");
+	if (ov511->snap_enabled && !frame->snapshot) {
+		frame->bytes_read = 0;
+		if (ov511_new_frame(ov511, frmx))
+			err("ov511_new_frame error");
+		goto restart;
+	}
+
+	/* Clear the snapshot */
+	if (ov511->snap_enabled && frame->snapshot) {
+		frame->snapshot = 0;
+		ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
+		ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x03);
+		ov511_reg_write(ov511->dev, OV511_REG_SYSTEM_SNAPSHOT, 0x01);
+	}
+
+	PDEBUG(4, "frmx=%d, bytes_read=%ld, scanlength=%ld", frmx,
+		frame->bytes_read, frame->scanlength);
+
+	/* copy bytes to user space; we allow for partials reads */
+//	if ((count + frame->bytes_read) > frame->scanlength)
+//		count = frame->scanlength - frame->bytes_read;
+
+	/* FIXME - count hardwired to be one frame... */
+	count = frame->width * frame->height * (frame->depth >> 3);
+
+	PDEBUG(4, "Copy to user space: %ld bytes", count);
+	if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
+		PDEBUG(4, "Copy failed! %d bytes not copied", i);
+		return -EFAULT;
+	}
+
+	frame->bytes_read += count;
+	PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
+		count, frame->bytes_read);
+
+	if (frame->bytes_read >= frame->scanlength) { /* All data has been read */
+		frame->bytes_read = 0;
+
+		/* Mark it as available to be used again. */
+		ov511->frame[frmx].grabstate = FRAME_UNUSED;
+		if (ov511_new_frame(ov511, !frmx))
+			err("ov511_new_frame returned error");
+	}
+
+	PDEBUG(4, "read finished, returning %ld (sweet)", count);
+
+	return count;
+}
+
+static int ov511_mmap(struct video_device *dev, const char *adr,
+	unsigned long size)
+{
+	struct usb_ov511 *ov511 = (struct usb_ov511 *)dev;
+	unsigned long start = (unsigned long)adr;
+	unsigned long page, pos;
+
+	if (ov511->dev == NULL)
+		return -EIO;
+
+	PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
+
+	if (size > (((2 * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+		return -EINVAL;
+
+	pos = (unsigned long)ov511->fbuf;
+	while (size > 0) {
+		page = kvirt_to_pa(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	return 0;
+}
+
+static struct video_device ov511_template = {
+	name:		"OV511 USB Camera",
+	type:		VID_TYPE_CAPTURE,
+	hardware:	VID_HARDWARE_OV511,
+	open:		ov511_open,
+	close:		ov511_close,
+	read:		ov511_read,
+	write:		ov511_write,
+	ioctl:		ov511_ioctl,
+	mmap:		ov511_mmap,
+	initialize:	ov511_init_done,
+};
+
+/****************************************************************************
+ *
+ * OV511/OV7610 configuration
+ *
+ ***************************************************************************/
+
+static int ov76xx_configure(struct usb_ov511 *ov511)
+{
+	struct usb_device *dev = ov511->dev;
+	int i, success;
+	int rc;
+
+	/* Lawrence Glaister <lg@jfm.bc.ca> reports:
+	 *
+	 * Register 0x0f in the 7610 has the following effects:
+	 *
+	 * 0x85 (AEC method 1): Best overall, good contrast range
+	 * 0x45 (AEC method 2): Very overexposed
+	 * 0xa5 (spec sheet default): Ok, but the black level is
+	 *	shifted resulting in loss of contrast
+	 * 0x05 (old driver setting): very overexposed, too much
+	 *	contrast
+	 */
+	static struct ov511_regvals aRegvalsNorm7610[] = {
+		{ OV511_I2C_BUS, 0x10, 0xff },
+		{ OV511_I2C_BUS, 0x16, 0x06 },
+		{ OV511_I2C_BUS, 0x28, 0x24 },
+		{ OV511_I2C_BUS, 0x2b, 0xac },
+		{ OV511_I2C_BUS, 0x12, 0x00 },
+		{ OV511_I2C_BUS, 0x38, 0x81 },
+		{ OV511_I2C_BUS, 0x28, 0x24 },	/* 0c */
+		{ OV511_I2C_BUS, 0x0f, 0x85 },	/* lg's setting */
+		{ OV511_I2C_BUS, 0x15, 0x01 },
+		{ OV511_I2C_BUS, 0x20, 0x1c },
+		{ OV511_I2C_BUS, 0x23, 0x2a },
+		{ OV511_I2C_BUS, 0x24, 0x10 },
+		{ OV511_I2C_BUS, 0x25, 0x8a },
+		{ OV511_I2C_BUS, 0x27, 0xc2 },
+		{ OV511_I2C_BUS, 0x2a, 0x04 },
+		{ OV511_I2C_BUS, 0x2c, 0xfe },
+		{ OV511_I2C_BUS, 0x30, 0x71 },
+		{ OV511_I2C_BUS, 0x31, 0x60 },
+		{ OV511_I2C_BUS, 0x32, 0x26 },
+		{ OV511_I2C_BUS, 0x33, 0x20 },
+		{ OV511_I2C_BUS, 0x34, 0x48 },
+		{ OV511_I2C_BUS, 0x12, 0x24 },
+		{ OV511_I2C_BUS, 0x11, 0x01 },
+		{ OV511_I2C_BUS, 0x0c, 0x24 },
+		{ OV511_I2C_BUS, 0x0d, 0x24 },
+		{ OV511_DONE_BUS, 0x0, 0x00 },
+	};
+
+	static struct ov511_regvals aRegvalsNorm7620[] = {
+		{ OV511_I2C_BUS, 0x10, 0xff },
+		{ OV511_I2C_BUS, 0x16, 0x06 },
+		{ OV511_I2C_BUS, 0x28, 0x24 },
+		{ OV511_I2C_BUS, 0x2b, 0xac },
+		{ OV511_I2C_BUS, 0x12, 0x00 },
+		{ OV511_I2C_BUS, 0x28, 0x24 },
+		{ OV511_I2C_BUS, 0x0f, 0x85 },	/* lg's setting */
+		{ OV511_I2C_BUS, 0x15, 0x01 },
+		{ OV511_I2C_BUS, 0x23, 0x00 },
+		{ OV511_I2C_BUS, 0x24, 0x10 },
+		{ OV511_I2C_BUS, 0x25, 0x8a },
+		{ OV511_I2C_BUS, 0x27, 0xe2 },
+		{ OV511_I2C_BUS, 0x2a, 0x00 },
+		{ OV511_I2C_BUS, 0x2c, 0xfe },
+		{ OV511_I2C_BUS, 0x30, 0x71 },
+		{ OV511_I2C_BUS, 0x31, 0x60 },
+		{ OV511_I2C_BUS, 0x32, 0x26 },
+		{ OV511_I2C_BUS, 0x33, 0x20 },
+		{ OV511_I2C_BUS, 0x34, 0x48 },
+		{ OV511_I2C_BUS, 0x12, 0x24 },
+		{ OV511_I2C_BUS, 0x11, 0x01 },
+		{ OV511_I2C_BUS, 0x0c, 0x24 },
+		{ OV511_I2C_BUS, 0x0d, 0x24 },
+		{ OV511_DONE_BUS, 0x0, 0x00 },
+	};
+
+	PDEBUG (4, "starting configuration");
+
+	/* This looks redundant, but is necessary for WebCam 3 */
+	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
+	                    OV7610_I2C_WRITE_ID) < 0)
+		return -1;
+
+	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
+	                    OV7610_I2C_READ_ID) < 0)
+		return -1;
+
+	if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
+		return -1;
+
+	/* Reset the 76xx */ 
+	if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1;
+
+	/* Wait for it to initialize */ 
+	schedule_timeout (1 + 150 * HZ / 1000);
+
+	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+		if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) &&
+		    (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2)) {
+			success = 1;
+			continue;
+		}
+
+		/* Reset the 76xx */ 
+		if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1;
+		/* Wait for it to initialize */ 
+		schedule_timeout (1 + 150 * HZ / 1000);
+		/* Dummy read to sync I2C */
+		if (ov511_i2c_read(dev, 0x00) < 0) return -1;
+	}
+
+	if (success) {
+		PDEBUG(1, "I2C synced in %d attempt(s) (method 1)", i);
+	} else {
+		/* Reset the 76xx */
+		if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1;
+
+		/* Wait for it to initialize */
+		schedule_timeout (1 + 150 * HZ / 1000);
+
+		i = 0;
+		success = 0;
+		while (i <= i2c_detect_tries) {
+			if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) &&
+			    (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2)) {
+				success = 1;
+				break;
+			} else {
+				i++;
+			}
+		}
+
+		if ((i == i2c_detect_tries) && (success == 0)) {
+			err("Failed to read sensor ID. You might not have an OV7610/20,");
+			err("or it may be not responding. Report this to");
+			err("mwm@i.am");
+			return -1;
+		} else {
+			PDEBUG(1, "I2C synced in %d attempt(s) (method 2)", i+1);
+		}
+	}
+
+	/* Detect sensor if user didn't use override param */
+	if (sensor == 0) {
+		rc = ov511_i2c_read(dev, OV7610_REG_COM_I);
+
+		if (rc < 0) {
+			err("Error detecting sensor type");
+			return -1;
+		} else if((rc & 3) == 3) {
+			info("Sensor is an OV7610");
+			ov511->sensor = SEN_OV7610;
+		} else if((rc & 3) == 1) {
+			info("Sensor is an OV7620AE");
+			ov511->sensor = SEN_OV7620AE;
+		} else if((rc & 3) == 0) {
+			info("Sensor is an OV7620");
+			ov511->sensor = SEN_OV7620;
+		} else {
+			err("Unknown image sensor version: %d", rc & 3);
+			return -1;
+		}
+	} else {	/* sensor != 0; user overrode detection */
+		ov511->sensor = sensor;
+		info("Sensor set to type %d", ov511->sensor);
+	}
+
+	if (ov511->sensor == SEN_OV7620) {
+		PDEBUG(4, "Writing 7620 registers");
+		if (ov511_write_regvals(dev, aRegvalsNorm7620))
+			return -1;
+	} else {
+		PDEBUG(4, "Writing 7610 registers");
+		if (ov511_write_regvals(dev, aRegvalsNorm7610))
+			return -1;
+	}
+
+	/* Set sensor-specific vars */
+	ov511->maxwidth = 640;
+	ov511->maxheight = 480;
+
+	if (aperture < 0) {          /* go with the default */
+		if (ov511_i2c_write(dev, 0x26, 0xa2) < 0) return -1;
+	} else if (aperture <= 0xf) {  /* user overrode default */
+		if (ov511_i2c_write(dev, 0x26, (aperture << 4) + 2) < 0)
+			return -1;
+	} else {
+		err("Invalid setting for aperture; legal value: 0 - 15");
+		return -1;
+	}
+
+	if (autoadjust) {
+		if (ov511_i2c_write(dev, 0x13, 0x01) < 0) return -1;
+		if (ov511_i2c_write(dev, 0x2d, 
+		     ov511->sensor==SEN_OV7620?0x91:0x93) < 0) return -1;
+	} else {
+		if (ov511_i2c_write(dev, 0x13, 0x00) < 0) return -1;
+		if (ov511_i2c_write(dev, 0x2d, 
+		     ov511->sensor==SEN_OV7620?0x81:0x83) < 0) return -1;
+		ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8);
+	}
+
+	return 0;
+}
+
+static int ov6xx0_configure(struct usb_ov511 *ov511)
+{
+	struct usb_device *dev = ov511->dev;
+	int i, success, rc;
+
+	static struct ov511_regvals aRegvalsNorm6x20[] = {
+		{ OV511_I2C_BUS, 0x12, 0x80 },  /* reset */
+		{ OV511_I2C_BUS, 0x11, 0x01 },
+		{ OV511_I2C_BUS, 0x03, 0xd0 },
+		{ OV511_I2C_BUS, 0x05, 0x7f },
+		{ OV511_I2C_BUS, 0x07, 0xa8 },
+		{ OV511_I2C_BUS, 0x0c, 0x24 },
+		{ OV511_I2C_BUS, 0x0d, 0x24 },
+		{ OV511_I2C_BUS, 0x10, 0xff },  /* ? */
+		{ OV511_I2C_BUS, 0x14, 0x04 },
+		{ OV511_I2C_BUS, 0x16, 0x06 },  /* ? */
+		{ OV511_I2C_BUS, 0x19, 0x04 },
+		{ OV511_I2C_BUS, 0x1a, 0x93 },
+		{ OV511_I2C_BUS, 0x20, 0x28 },
+		{ OV511_I2C_BUS, 0x27, 0xa2 },
+		{ OV511_I2C_BUS, 0x28, 0x24 },
+		{ OV511_I2C_BUS, 0x2a, 0x04 },  /* 84? */
+		{ OV511_I2C_BUS, 0x2b, 0xac },  /* a8? */
+		{ OV511_I2C_BUS, 0x2d, 0x95 },
+		{ OV511_I2C_BUS, 0x33, 0x28 },
+		{ OV511_I2C_BUS, 0x34, 0xc7 },
+		{ OV511_I2C_BUS, 0x38, 0x8b },
+		{ OV511_I2C_BUS, 0x3c, 0x5c },
+		{ OV511_I2C_BUS, 0x3d, 0x80 },
+		{ OV511_I2C_BUS, 0x3f, 0x00 },
+		{ OV511_I2C_BUS, 0x4a, 0x80 }, /* undocumented */
+		{ OV511_I2C_BUS, 0x4b, 0x80 }, /* undocumented */
+		{ OV511_I2C_BUS, 0x4d, 0xd2 },
+		{ OV511_I2C_BUS, 0x4e, 0xc1 },
+		{ OV511_I2C_BUS, 0x4f, 0x04 },
+		{ OV511_DONE_BUS, 0x0, 0x00 },
+	};
+
+	PDEBUG (4, "starting sensor configuration");
+	
+	/* Reset the 6xx0 */ 
+	if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1;
+
+	/* Wait for it to initialize */ 
+	schedule_timeout (1 + 150 * HZ / 1000);
+
+	for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
+		if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) &&
+		    (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2)) {
+			success = 1;
+			continue;
+		}
+
+		/* Reset the 6xx0 */ 
+		if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1;
+		/* Wait for it to initialize */ 
+		schedule_timeout (1 + 150 * HZ / 1000);
+		/* Dummy read to sync I2C */
+		if (ov511_i2c_read(dev, 0x00) < 0) return -1;
+	}
+
+	if (success) {
+		PDEBUG(1, "I2C synced in %d attempt(s)", i);
+	} else {
+		err("Failed to read sensor ID. You might not have an OV6xx0,");
+		err("or it may be not responding. Report this to");
+		err("mwm@i.am");
+		return -1;
+	}
+
+	/* Detect sensor if user didn't use override param */
+	if (sensor == 0) {
+		rc = ov511_i2c_read(dev, OV7610_REG_COM_I);
+
+		if (rc < 0) {
+			err("Error detecting sensor type");
+			return -1;
+		} else {
+			info("Sensor is an OV6xx0 (version %d)", rc & 3);
+			ov511->sensor = SEN_OV6620;
+		}
+	} else {	/* sensor != 0; user overrode detection */
+		ov511->sensor = sensor;
+		info("Sensor set to type %d", ov511->sensor);
+	}
+
+	/* Set sensor-specific vars */
+	ov511->maxwidth = 352;
+	ov511->maxheight = 288;
+
+	PDEBUG(4, "Writing 6x20 registers");
+	if (ov511_write_regvals(dev, aRegvalsNorm6x20))
+		return -1;
+
+	if (aperture < 0) {          /* go with the default */
+		if (ov511_i2c_write(dev, 0x26, 0xa2) < 0) return -1;
+	} else if (aperture <= 0xf) {  /* user overrode default */
+		if (ov511_i2c_write(dev, 0x26, (aperture << 4) + 2) < 0)
+			return -1;
+	} else {
+		err("Invalid setting for aperture; legal value: 0 - 15");
+		return -1;
+	}
+
+	if (autoadjust) {
+		if (ov511_i2c_write(dev, 0x13, 0x01) < 0) return -1;
+		if (ov511_i2c_write(dev, 0x2d, 
+		     ov511->sensor==SEN_OV7620?0x91:0x93) < 0) return -1;
+	} else {
+		if (ov511_i2c_write(dev, 0x13, 0x00) < 0) return -1;
+		if (ov511_i2c_write(dev, 0x2d, 
+		     ov511->sensor==SEN_OV7620?0x81:0x83) < 0) return -1;
+		ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8);
+	}
+
+	return 0;
+}
+
+
+static int ov511_configure(struct usb_ov511 *ov511)
+{
+	struct usb_device *dev = ov511->dev;
+	int i;
+
+	static struct ov511_regvals aRegvalsInit[] = {
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f },
+	 	{ OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
+	 	{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x7f },
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3f },
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_INIT, 0x01 },
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_RESET, 0x3d },
+		{ OV511_DONE_BUS, 0x0, 0x00},
+	};
+
+	static struct ov511_regvals aRegvalsNorm511[] = {
+		{ OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 },
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x02 },
+		{ OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x00 },
+		{ OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f },
+		{ OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_Y, 0x08 },
+		{ OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_UV, 0x01 },
+		{ OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_Y, 0x08 },
+		{ OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_UV, 0x01 },
+		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_Y, 0x01 },
+		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_UV, 0x01 },
+		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_Y, 0x01 },
+		{ OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_VERT_UV, 0x01 },
+		{ OV511_REG_BUS, OV511_OMNICE_ENABLE, 0x06 },
+		{ OV511_REG_BUS, OV511_OMNICE_LUT_ENABLE, 0x03 },
+		{ OV511_DONE_BUS, 0x0, 0x00 },
+	};
+
+	memcpy(&ov511->vdev, &ov511_template, sizeof(ov511_template));
+
+	for (i = 0; i < OV511_NUMFRAMES; i++)
+		init_waitqueue_head(&ov511->frame[i].wq);
+
+	init_waitqueue_head(&ov511->wq);
+
+	if (video_register_device(&ov511->vdev, VFL_TYPE_GRABBER) == -1) {
+		err("video_register_device failed");
+		return -EBUSY;
+	}
+
+	if (ov511_write_regvals(dev, aRegvalsInit)) goto error;
+	if (ov511_write_regvals(dev, aRegvalsNorm511)) goto error;
+
+	ov511_set_packet_size(ov511, 0);
+
+	ov511->snap_enabled = snapshot;	
+
+	/* Test for 76xx */
+	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
+	                   OV7610_I2C_WRITE_ID) < 0)
+		goto error;
+
+	if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
+	                   OV7610_I2C_READ_ID) < 0)
+		goto error;
+
+	if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
+		goto error;
+
+	if (ov511_i2c_write(dev, 0x12, 0x80) < 0) {
+		/* Test for 6xx0 */
+		if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE,
+		                    OV6xx0_I2C_WRITE_ID) < 0)
+			goto error;
+
+		if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ,
+		                    OV6xx0_I2C_READ_ID) < 0)
+			goto error;
+
+		if (ov511_reset(dev, OV511_RESET_NOREGS) < 0)
+			goto error;
+
+		if (ov511_i2c_write(dev, 0x12, 0x80) < 0) {
+			err("Can't determine sensor slave IDs");
+			goto error;
+		}
+		
+		if(ov6xx0_configure(ov511) < 0) {
+			err("failed to configure OV6xx0");
+ 			goto error;
+		}
+	} else {
+		if(ov76xx_configure(ov511) < 0) {
+			err("failed to configure OV76xx");
+	 		goto error;
+		}
+	}
+	
+	/* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
+	 * (using read() instead). */
+	for (i = 0; i < OV511_NUMFRAMES; i++) {
+		ov511->frame[i].width = ov511->maxwidth;
+		ov511->frame[i].height = ov511->maxheight;
+		ov511->frame[i].depth = 24;
+		ov511->frame[i].bytes_read = 0;
+		ov511->frame[i].segment = 0;
+		ov511->frame[i].format = VIDEO_PALETTE_RGB24;
+		ov511->frame[i].segsize = GET_SEGSIZE(ov511->frame[i].format);
+	}
+
+	/* Initialize to max width/height, RGB24 */
+	if (ov511_mode_init_regs(ov511, ov511->maxwidth, ov511->maxheight,
+				 VIDEO_PALETTE_RGB24, 0) < 0)
+		goto error;
+
+	return 0;
+	
+error:
+	video_unregister_device(&ov511->vdev);
+	usb_driver_release_interface(&ov511_driver,
+		&dev->actconfig->interface[ov511->iface]);
+
+	return -EBUSY;	
+}
+
+
+/****************************************************************************
+ *
+ *  USB routines
+ *
+ ***************************************************************************/
+
+static void* ov511_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_ov511 *ov511;
+	int i;
+
+	PDEBUG(1, "probing for device...");
+
+	/* We don't handle multi-config cameras */
+	if (dev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+
+	/* Is it an OV511/OV511+? */
+	if (dev->descriptor.idVendor != 0x05a9 
+	 && dev->descriptor.idVendor != 0x0813)
+		return NULL;
+	if (dev->descriptor.idProduct != 0x0511
+	 && dev->descriptor.idProduct != 0xA511
+	 && dev->descriptor.idProduct != 0x0002)
+		return NULL;
+
+	/* Checking vendor/product should be enough, but what the hell */
+	if (interface->bInterfaceClass != 0xFF) 
+		return NULL;
+	if (interface->bInterfaceSubClass != 0x00)
+		return NULL;
+
+	/* Since code below may sleep, we use this as a lock */
+	MOD_INC_USE_COUNT;
+
+	if ((ov511 = kmalloc(sizeof(*ov511), GFP_KERNEL)) == NULL) {
+		err("couldn't kmalloc ov511 struct");
+		goto error;
+	}
+
+	memset(ov511, 0, sizeof(*ov511));
+
+	ov511->dev = dev;
+	ov511->iface = interface->bInterfaceNumber;
+
+	switch (dev->descriptor.idProduct) {
+	case 0x0511:
+		info("USB OV511 camera found");
+		ov511->bridge = BRG_OV511;
+		break;
+	case 0xA511:
+		info("USB OV511+ camera found");
+		ov511->bridge = BRG_OV511PLUS;
+		break;
+	case 0x0002:
+		if (dev->descriptor.idVendor != 0x0813)
+			goto error;
+		info("Intel Play Me2Cam (OV511+) found");
+		ov511->bridge = BRG_OV511PLUS;
+		break;
+	default:
+		err("Unknown product ID");
+		goto error;
+	}
+
+	ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID);
+	if (ov511->customid < 0) {
+		err("Unable to read camera bridge registers");
+		goto error;
+	}
+
+	ov511->desc = -1;
+	PDEBUG (4, "CustomID = %d", ov511->customid);
+	for (i = 0; clist[i].id >= 0; i++) {
+		if (ov511->customid == clist[i].id) {
+			info("camera: %s", clist[i].description);
+			ov511->desc = i;
+			break;
+		}
+	}
+
+	/* Lifeview USB Life TV not supported */
+	if (clist[i].id == 38) {
+		err("This device is not supported yet.");
+		goto error;
+	}
+
+	if (clist[i].id == -1) {
+		err("Camera type (%d) not recognized", ov511->customid);
+		err("Please contact mwm@i.am to request");
+		err("support for your camera.");
+	}
+
+	/* Workaround for some applications that want data in RGB
+	 * instead of BGR */
+	if (force_rgb)
+		info("data format set to RGB");
+
+	if (!ov511_configure(ov511)) {
+		ov511->user = 0;
+		init_MUTEX(&ov511->lock);	/* to 1 == available */
+		init_MUTEX(&ov511->buf_lock);
+		ov511->buf_state = BUF_NOT_ALLOCATED;
+	} else {
+		err("Failed to configure camera");
+		goto error;
+	}
+
+	MOD_DEC_USE_COUNT;
+     	return ov511;
+
+error:
+	if (ov511) {
+		kfree(ov511);
+		ov511 = NULL;
+	}
+
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+
+static void ov511_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_ov511 *ov511 = (struct usb_ov511 *) ptr;
+	int n;
+
+	MOD_INC_USE_COUNT;
+
+	PDEBUG(3, "");
+
+	/* We don't want people trying to open up the device */
+	if (!ov511->user)
+		video_unregister_device(&ov511->vdev);
+	else
+		PDEBUG(3, "Device open...deferring video_unregister_device");
+
+	for (n = 0; n < OV511_NUMFRAMES; n++)
+		ov511->frame[n].grabstate = FRAME_ERROR;
+
+	ov511->curframe = -1;
+
+	/* This will cause the process to request another frame */
+	for (n = 0; n < OV511_NUMFRAMES; n++)
+		if (waitqueue_active(&ov511->frame[n].wq))
+			wake_up_interruptible(&ov511->frame[n].wq);
+	if (waitqueue_active(&ov511->wq))
+		wake_up_interruptible(&ov511->wq);
+
+	ov511->streaming = 0;
+
+	/* Unschedule all of the iso td's */
+	for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
+		if (ov511->sbuf[n].urb) {
+			ov511->sbuf[n].urb->next = NULL;
+			usb_unlink_urb(ov511->sbuf[n].urb);
+			usb_free_urb(ov511->sbuf[n].urb);
+			ov511->sbuf[n].urb = NULL;
+		}
+	}
+
+	usb_driver_release_interface(&ov511_driver,
+		&ov511->dev->actconfig->interface[ov511->iface]);
+	ov511->dev = NULL;
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+        destroy_proc_ov511_cam(ov511);
+#endif
+
+	/* Free the memory */
+	if (ov511 && !ov511->user) {
+		ov511_dealloc(ov511, 1);
+		kfree(ov511);
+		ov511 = NULL;
+	}
+
+	MOD_DEC_USE_COUNT;
+}
+
+static struct usb_driver ov511_driver = {
+	"ov511",
+	ov511_probe,
+	ov511_disconnect,
+	{ NULL, NULL }
+};
+
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
+static int __init usb_ov511_init(void)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+        proc_ov511_create();
+#endif
+
+	if (usb_register(&ov511_driver) < 0)
+		return -1;
+
+	info("ov511 driver version %s registered", version);
+
+	return 0;
+}
+
+static void __exit usb_ov511_exit(void)
+{
+	usb_deregister(&ov511_driver);
+	info("driver deregistered");
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+        proc_ov511_destroy();
+#endif 
+}
+
+module_init(usb_ov511_init);
+module_exit(usb_ov511_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/ov511.h linux.18p8/drivers/usb/ov511.h
--- linux.vanilla/drivers/usb/ov511.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/ov511.h	Fri Sep 15 15:13:04 2000
@@ -0,0 +1,371 @@
+
+#ifndef __LINUX_OV511_H
+#define __LINUX_OV511_H
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+
+#define OV511_DEBUG	/* Turn on debug messages */
+
+#ifdef OV511_DEBUG
+#  define PDEBUG(level, fmt, args...) \
+if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+#else
+#  define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* Camera interface register numbers */
+#define OV511_REG_CAMERA_DELAY_MODE		0x10
+#define OV511_REG_CAMERA_EDGE_MODE		0x11
+#define OV511_REG_CAMERA_CLAMPED_PIXEL_NUM	0x12
+#define OV511_REG_CAMERA_CLAMPED_LINE_NUM	0x13
+#define OV511_REG_CAMERA_PIXEL_DIVISOR		0x14
+#define OV511_REG_CAMERA_LINE_DIVISOR		0x15
+#define OV511_REG_CAMERA_DATA_INPUT_SELECT	0x16
+#define OV511_REG_CAMERA_RESERVED_LINE_MODE	0x17
+#define OV511_REG_CAMERA_BITMASK		0x18
+
+/* Snapshot mode camera interface register numbers */
+#define OV511_REG_SNAP_CAPTURED_FRAME		0x19
+#define OV511_REG_SNAP_CLAMPED_PIXEL_NUM	0x1A
+#define OV511_REG_SNAP_CLAMPED_LINE_NUM		0x1B
+#define OV511_REG_SNAP_PIXEL_DIVISOR		0x1C
+#define OV511_REG_SNAP_LINE_DIVISOR		0x1D
+#define OV511_REG_SNAP_DATA_INPUT_SELECT	0x1E
+#define OV511_REG_SNAP_BITMASK			0x1F
+
+/* DRAM register numbers */
+#define OV511_REG_DRAM_ENABLE_FLOW_CONTROL	0x20
+#define OV511_REG_DRAM_READ_CYCLE_PREDICT	0x21
+#define OV511_REG_DRAM_MANUAL_READ_CYCLE	0x22
+#define OV511_REG_DRAM_REFRESH_COUNTER		0x23
+
+/* ISO FIFO register numbers */
+#define OV511_REG_FIFO_PACKET_SIZE		0x30
+#define OV511_REG_FIFO_BITMASK			0x31
+
+/* PIO register numbers */
+#define OV511_REG_PIO_BITMASK			0x38
+#define OV511_REG_PIO_DATA_PORT			0x39
+#define OV511_REG_PIO_BIST			0x3E
+
+/* I2C register numbers */
+#define OV511_REG_I2C_CONTROL			0x40
+#define OV511_REG_I2C_SLAVE_ID_WRITE		0x41
+#define OV511_REG_I2C_SUB_ADDRESS_3_BYTE	0x42
+#define OV511_REG_I2C_SUB_ADDRESS_2_BYTE	0x43
+#define OV511_REG_I2C_SLAVE_ID_READ		0x44
+#define OV511_REG_I2C_DATA_PORT			0x45
+#define OV511_REG_I2C_CLOCK_PRESCALER		0x46
+#define OV511_REG_I2C_TIME_OUT_COUNTER		0x47
+
+/* I2C snapshot register numbers */
+#define OV511_REG_I2C_SNAP_SUB_ADDRESS		0x48
+#define OV511_REG_I2C_SNAP_DATA_PORT		0x49
+
+/* System control register numbers */
+#define OV511_REG_SYSTEM_RESET			0x50
+#define 	OV511_RESET_UDC			0x01
+#define 	OV511_RESET_I2C			0x02
+#define 	OV511_RESET_FIFO		0x04
+#define 	OV511_RESET_OMNICE		0x08
+#define 	OV511_RESET_DRAM_INTF		0x10
+#define 	OV511_RESET_CAMERA_INTF		0x20
+#define 	OV511_RESET_OV511		0x40
+#define 	OV511_RESET_NOREGS		0x3F /* All but OV511 & regs */
+#define 	OV511_RESET_ALL			0x7F
+#define OV511_REG_SYSTEM_CLOCK_DIVISOR		0x51
+#define OV511_REG_SYSTEM_SNAPSHOT		0x52
+#define OV511_REG_SYSTEM_INIT         		0x53
+#define OV511_REG_SYSTEM_PWR_CLK		0x54	/* OV511+ only */
+#define OV511_REG_SYSTEM_LED_CTL		0x55	/* OV511+ only */
+#define OV511_REG_SYSTEM_USER_DEFINED		0x5E
+#define OV511_REG_SYSTEM_CUSTOM_ID		0x5F
+
+/* OmniCE register numbers */
+#define OV511_OMNICE_PREDICTION_HORIZ_Y		0x70
+#define OV511_OMNICE_PREDICTION_HORIZ_UV	0x71
+#define OV511_OMNICE_PREDICTION_VERT_Y		0x72
+#define OV511_OMNICE_PREDICTION_VERT_UV		0x73
+#define OV511_OMNICE_QUANTIZATION_HORIZ_Y	0x74
+#define OV511_OMNICE_QUANTIZATION_HORIZ_UV	0x75
+#define OV511_OMNICE_QUANTIZATION_VERT_Y	0x76
+#define OV511_OMNICE_QUANTIZATION_VERT_UV	0x77
+#define OV511_OMNICE_ENABLE			0x78
+#define OV511_OMNICE_LUT_ENABLE			0x79		
+#define OV511_OMNICE_Y_LUT_BEGIN		0x80
+#define OV511_OMNICE_Y_LUT_END			0x9F
+#define OV511_OMNICE_UV_LUT_BEGIN		0xA0
+#define OV511_OMNICE_UV_LUT_END			0xBF
+
+/* Alternate numbers for various max packet sizes (OV511 only) */
+#define OV511_ALT_SIZE_992	0
+#define OV511_ALT_SIZE_993	1
+#define OV511_ALT_SIZE_768	2
+#define OV511_ALT_SIZE_769	3
+#define OV511_ALT_SIZE_512	4
+#define OV511_ALT_SIZE_513	5
+#define OV511_ALT_SIZE_257	6
+#define OV511_ALT_SIZE_0	7
+
+/* Alternate numbers for various max packet sizes (OV511+ only) */
+#define OV511PLUS_ALT_SIZE_0	0
+#define OV511PLUS_ALT_SIZE_33	1
+#define OV511PLUS_ALT_SIZE_129	2
+#define OV511PLUS_ALT_SIZE_257	3
+#define OV511PLUS_ALT_SIZE_385	4
+#define OV511PLUS_ALT_SIZE_513	5
+#define OV511PLUS_ALT_SIZE_769	6
+#define OV511PLUS_ALT_SIZE_961	7
+
+/* OV7610 registers */
+#define OV7610_REG_GAIN          0x00	/* gain setting (5:0) */
+#define OV7610_REG_BLUE          0x01	/* blue channel balance */
+#define OV7610_REG_RED           0x02	/* red channel balance */
+#define OV7610_REG_SAT           0x03	/* saturation */
+					/* 04 reserved */
+#define OV7610_REG_CNT           0x05	/* Y contrast */
+#define OV7610_REG_BRT           0x06	/* Y brightness */
+					/* 08-0b reserved */
+#define OV7610_REG_BLUE_BIAS     0x0C	/* blue channel bias (5:0) */
+#define OV7610_REG_RED_BIAS      0x0D	/* read channel bias (5:0) */
+#define OV7610_REG_GAMMA_COEFF   0x0E	/* gamma settings */
+#define OV7610_REG_WB_RANGE      0x0F	/* AEC/ALC/S-AWB settings */
+#define OV7610_REG_EXP           0x10	/* manual exposure setting */
+#define OV7610_REG_CLOCK         0x11	/* polarity/clock prescaler */
+#define OV7610_REG_COM_A         0x12	/* misc common regs */
+#define OV7610_REG_COM_B         0x13	/* misc common regs */
+#define OV7610_REG_COM_C         0x14	/* misc common regs */
+#define OV7610_REG_COM_D         0x15	/* misc common regs */
+#define OV7610_REG_FIELD_DIVIDE  0x16	/* field interval/mode settings */
+#define OV7610_REG_HWIN_START    0x17	/* horizontal window start */
+#define OV7610_REG_HWIN_END      0x18	/* horizontal window end */
+#define OV7610_REG_VWIN_START    0x19	/* vertical window start */
+#define OV7610_REG_VWIN_END      0x1A	/* vertical window end */
+#define OV7610_REG_PIXEL_SHIFT   0x1B	/* pixel shift */
+#define OV7610_REG_ID_HIGH       0x1C	/* manufacturer ID MSB */
+#define OV7610_REG_ID_LOW        0x1D	/* manufacturer ID LSB */
+					/* 0e-0f reserved */
+#define OV7610_REG_COM_E         0x20	/* misc common regs */
+#define OV7610_REG_YOFFSET       0x21	/* Y channel offset */
+#define OV7610_REG_UOFFSET       0x22	/* U channel offset */
+					/* 23 reserved */
+#define OV7610_REG_ECW           0x24	/* Exposure white level for AEC */
+#define OV7610_REG_ECB           0x25	/* Exposure black level for AEC */
+#define OV7610_REG_COM_F         0x26	/* misc settings */
+#define OV7610_REG_COM_G         0x27	/* misc settings */
+#define OV7610_REG_COM_H         0x28	/* misc settings */
+#define OV7610_REG_COM_I         0x29	/* misc settings */
+#define OV7610_REG_FRAMERATE_H   0x2A	/* frame rate MSB + misc */
+#define OV7610_REG_FRAMERATE_L   0x2B	/* frame rate LSB */
+#define OV7610_REG_ALC           0x2C	/* Auto Level Control settings */
+#define OV7610_REG_COM_J         0x2D	/* misc settings */
+#define OV7610_REG_VOFFSET       0x2E	/* V channel offset adjustment */
+#define OV7610_REG_ARRAY_BIAS	 0x2F	/* Array bias -- don't change */
+					/* 30-32 reserved */
+#define OV7610_REG_YGAMMA        0x33	/* misc gamma settings (7:6) */
+#define OV7610_REG_BIAS_ADJUST   0x34	/* misc bias settings */
+#define OV7610_REG_COM_L         0x35	/* misc settings */
+					/* 36-37 reserved */
+#define OV7610_REG_COM_K         0x38	/* misc registers */
+
+
+#define SCRATCH_BUF_SIZE 512
+
+#define FRAMES_PER_DESC		10	/* FIXME - What should this be? */
+#define FRAME_SIZE_PER_DESC	993	/* FIXME - Deprecated */
+#define MAX_FRAME_SIZE_PER_DESC	993	/* For statically allocated stuff */
+
+#define OV511_ENDPOINT_ADDRESS 1	/* Isoc endpoint number */
+
+// CAMERA SPECIFIC
+// FIXME - these can vary between specific models
+#define OV7610_I2C_WRITE_ID 0x42
+#define OV7610_I2C_READ_ID  0x43
+#define OV6xx0_I2C_WRITE_ID 0xC0
+#define OV6xx0_I2C_READ_ID  0xC1
+
+#define OV511_I2C_CLOCK_PRESCALER 0x03
+
+/* Prototypes */
+int usb_ov511_reg_read(struct usb_device *dev, unsigned char reg);
+int usb_ov511_reg_write(struct usb_device *dev,
+                        unsigned char reg,
+                        unsigned char value);
+
+/* Bridge types */
+enum {
+	BRG_OV511,
+	BRG_OV511PLUS,
+};
+
+/* Sensor types */
+enum {
+	SEN_UNKNOWN,
+	SEN_OV7610,
+	SEN_OV7620,
+	SEN_OV7620AE,
+	SEN_OV6620,
+};
+
+enum {
+	STATE_SCANNING,		/* Scanning for start */
+	STATE_HEADER,		/* Parsing header */
+	STATE_LINES,		/* Parsing lines */
+};
+
+/* Buffer states */
+enum {
+	BUF_NOT_ALLOCATED,
+	BUF_ALLOCATED,
+	BUF_PEND_DEALLOC,	/* ov511->buf_timer is set */
+};
+
+struct usb_device;
+
+struct ov511_sbuf {
+	char *data;
+	urb_t *urb;
+};
+
+enum {
+	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
+	FRAME_READY,		/* Ready to start grabbing */
+	FRAME_GRABBING,		/* In the process of being grabbed into */
+	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
+	FRAME_ERROR,		/* Something bad happened while processing */
+};
+
+struct ov511_regvals {
+	enum {
+		OV511_DONE_BUS,
+		OV511_REG_BUS,
+		OV511_I2C_BUS,
+	} bus;
+	unsigned char reg;
+	unsigned char val;
+};
+
+struct ov511_frame {
+	char *data;		/* Frame buffer */
+
+	int depth;		/* Bytes per pixel */
+	int width;		/* Width application is expecting */
+	int height;		/* Height */
+
+	int hdrwidth;		/* Width the frame actually is */
+	int hdrheight;		/* Height */
+
+	int sub_flag;		/* Sub-capture mode for this frame? */
+	unsigned int format;	/* Format for this frame */
+	int segsize;		/* How big is each segment from the camera? */
+
+	volatile int grabstate;	/* State of grabbing */
+	int scanstate;		/* State of scanning */
+
+	int curline;		/* Line of frame we're working on */
+	int curpix;
+	int segment;		/* Segment from the incoming data */
+
+	long scanlength;	/* uncompressed, raw data length of frame */
+	long bytes_read;	/* amount of scanlength that has been read from *data */
+
+	wait_queue_head_t wq;	/* Processes waiting */
+
+	int snapshot;		/* True if frame was a snapshot */
+};
+
+#define OV511_NUMFRAMES	2
+#define OV511_NUMSBUF	2
+
+struct usb_ov511 {
+	struct video_device vdev;
+
+	/* Device structure */
+	struct usb_device *dev;
+
+	int customid;
+	int desc;
+	unsigned char iface;
+
+	/* Determined by sensor type */
+	int maxwidth;
+	int maxheight;
+
+	int brightness;
+	int colour;
+	int contrast;
+	int hue;
+	int whiteness;
+
+	struct semaphore lock;
+	int user;		/* user count for exclusive use */
+
+	int streaming;		/* Are we streaming Isochronous? */
+	int grabbing;		/* Are we grabbing? */
+
+	int compress;		/* Should the next frame be compressed? */
+
+	char *fbuf;		/* Videodev buffer area */
+
+	int sub_flag;		/* Pix Array subcapture on flag */
+	int subx;		/* Pix Array subcapture x offset */
+	int suby;		/* Pix Array subcapture y offset */
+	int subw;		/* Pix Array subcapture width */
+	int subh;		/* Pix Array subcapture height */
+
+	int curframe;		/* Current receiving sbuf */
+	struct ov511_frame frame[OV511_NUMFRAMES];	
+
+	int cursbuf;		/* Current receiving sbuf */
+	struct ov511_sbuf sbuf[OV511_NUMSBUF];
+
+	/* Scratch space from the Isochronous pipe */
+	unsigned char scratch[SCRATCH_BUF_SIZE];
+	int scratchlen;
+
+	wait_queue_head_t wq;	/* Processes waiting */
+
+	int snap_enabled;	/* Snapshot mode enabled */
+	
+	int bridge;		/* Type of bridge (OV511 or OV511+) */
+	int sensor;		/* Type of image sensor chip */
+
+	int packet_size;	/* Frame size per isoc desc */
+
+				/* proc interface */
+	struct semaphore param_lock;	/* params lock for this camera */
+	struct proc_dir_entry *proc_entry;	/* /proc/ov511/videoX */
+	
+	/* Framebuffer/sbuf management */
+	int buf_state;
+	struct semaphore buf_lock;
+	struct timer_list buf_timer;
+};
+
+struct cam_list {
+	int id;
+	char *description;
+};
+
+struct palette_list {
+	int num;
+	char *name;
+};
+
+struct mode_list {
+	int width;
+	int height;
+	int color;		/* 0=grayscale, 1=color */
+	u8 pxcnt;		/* pixel counter */
+	u8 lncnt;		/* line counter */
+	u8 pxdv;		/* pixel divisor */
+	u8 lndv;		/* line divisor */
+	u8 m420;
+	u8 common_A;
+	u8 common_L;
+};
+
+#endif
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/pegasus.c linux.18p8/drivers/usb/pegasus.c
--- linux.vanilla/drivers/usb/pegasus.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/pegasus.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,564 @@
+/*
+**	Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
+**
+**	Copyright (R) 1999,2000 Petko Manolov - Petkan (petkan@spct.net)
+**
+**	Distribute under GPL version 2 or later.
+*/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+
+
+static const char *version = __FILE__ ": v0.3.14 2000/06/09 (C) 1999-2000 Petko Manolov (petkan@spct.net)\n";
+
+
+#define	PEGASUS_MTU		1500
+#define	PEGASUS_MAX_MTU		1536
+#define	SROM_WRITE		0x01
+#define	SROM_READ		0x02
+#define	PEGASUS_TX_TIMEOUT	(HZ*5)
+#define	PEGASUS_RESET		1
+#define	ALIGN(x)		x __attribute__((aligned(L1_CACHE_BYTES)))
+
+
+struct pegasus {
+	struct usb_device	*usb;
+	struct net_device	*net;
+	struct net_device_stats	stats;
+	int			flags;
+	spinlock_t		pegasus_lock;
+	struct urb		rx_urb, tx_urb, intr_urb;
+	unsigned char		ALIGN(rx_buff[PEGASUS_MAX_MTU]); 
+	unsigned char		ALIGN(tx_buff[PEGASUS_MAX_MTU]); 
+	unsigned char		ALIGN(intr_buff[8]);
+};
+
+struct usb_eth_dev {
+	char	*name;
+	__u16	vendor;
+	__u16	device;
+	void	*private;
+};
+
+
+static int loopback = 0;
+static int multicast_filter_limit = 32;
+
+
+MODULE_AUTHOR("Petko Manolov <petkan@spct.net>");
+MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
+MODULE_PARM(loopback, "i");
+
+
+static struct usb_eth_dev usb_dev_id[] = {
+	{"Billionton USB-100", 0x08dd, 0x0986, NULL},
+	{"Corega FEter USB-TX", 0x7aa, 0x0004, NULL},
+	{"MELCO/BUFFALO LUA-TX", 0x0411, 0x0001, NULL},
+	{"D-Link DSB-650TX", 0x2001, 0x4001, NULL},
+	{"D-Link DSB-650TX", 0x2001, 0x4002, NULL},
+	{"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL},
+	{"D-Link DU-10", 0x07b8, 0xabc1, NULL},
+	{"D-Link DU-E100", 0x07b8, 0x4002, NULL},
+	{"Linksys USB100TX", 0x066b, 0x2203, NULL},
+	{"Linksys USB100TX", 0x066b, 0x2204, NULL},
+	{"Linksys USB Ethernet Adapter", 0x066b, 0x2206, NULL},
+	{"SMC 202 USB Ethernet", 0x0707, 0x0200, NULL},
+	{"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986, NULL},
+	{"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL},
+	{"IO DATA USB ET/TX", 0x04bb, 0x0904, NULL},
+	{"LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002, NULL},
+	{NULL, 0, 0, NULL}
+};
+
+
+#define pegasus_get_registers(dev, indx, size, data)\
+	usb_control_msg(dev, usb_rcvctrlpipe(dev,0), 0xf0, 0xc0, 0, indx, data, size, HZ);
+#define pegasus_set_registers(dev, indx, size, data)\
+	usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, 0, indx, data, size, HZ);
+#define pegasus_set_register(dev, indx, value)	\
+	{ __u8	__data = value;			\
+	usb_control_msg(dev, usb_sndctrlpipe(dev,0), 0xf1, 0x40, __data, indx, &__data, 1, HZ);}
+
+
+static int pegasus_read_phy_word(struct usb_device *dev, __u8 index, __u16 *regdata)
+{
+	int i;
+	__u8 data[4] = { 1, 0, 0, 0x40 + index };
+
+	pegasus_set_registers(dev, 0x25, 4, data);
+	for (i = 0; i < 100; i++) {
+		pegasus_get_registers(dev, 0x26, 3, data);
+		if (data[2] & 0x80) {
+			*regdata = *(__u16 *)(data);
+			return 0;
+		}
+		udelay(100);
+	}
+
+	warn("read_phy_word() failed");
+	return 1;
+}
+
+
+static int pegasus_write_phy_word(struct usb_device *dev, __u8 index, __u16 regdata)
+{
+	int i;
+	__u8 data[4] = { 1, regdata, regdata >> 8, 0x20 + index };
+
+	pegasus_set_registers(dev, 0x25, 4, data);
+	for (i = 0; i < 100; i++) {
+		pegasus_get_registers(dev, 0x28, 1, data);
+		if (data[0] & 0x80)
+			return 0;
+		udelay(100);
+	}
+
+	warn("write_phy_word() failed");
+	return 1;
+}
+
+
+static int pegasus_rw_srom_word(struct usb_device *dev, __u8 index, __u16 *retdata, __u8 direction)
+{
+	int i;
+	__u8 data[4] = { index, 0, 0, direction };
+
+	pegasus_set_registers(dev, 0x20, 4, data);
+	for (i = 0; i < 100; i++) {
+		pegasus_get_registers(dev, 0x23, 1, data);
+		if (data[0] & 4) {
+			pegasus_get_registers(dev, 0x21, 2, data);
+			*retdata = *(__u16 *)data;
+			return 0;
+		}
+	}
+
+	warn("pegasus_rw_srom_word() failed");
+	return 1;
+}
+
+
+static int pegasus_get_node_id(struct usb_device *dev, __u8 *id)
+{
+	int i;
+	for (i = 0; i < 3; i++)
+		if (pegasus_rw_srom_word(dev,i,(__u16 *)&id[i * 2],SROM_READ))
+			return 1;
+	return 0;
+}
+
+
+static int pegasus_reset_mac(struct usb_device *dev)
+{
+	__u8 data = 0x8;
+	int i;
+
+	pegasus_set_register(dev, 1, data);
+	for (i = 0; i < 100; i++) {
+		pegasus_get_registers(dev, 1, 1, &data);
+		if (~data & 0x08) {
+			if (loopback & 1) 
+				return 0;
+			if (loopback & 2) 
+				pegasus_write_phy_word(dev, 0, 0x4000);
+			pegasus_set_register(dev, 0x7e, 0x24);
+			pegasus_set_register(dev, 0x7e, 0x27);
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+
+static int pegasus_start_net(struct net_device *dev, struct usb_device *usb)
+{
+	__u16 partmedia, temp;
+	__u8 node_id[6];
+	__u8 data[4];
+
+	if (pegasus_get_node_id(usb, node_id)) 
+		return 1;
+
+	pegasus_set_registers(usb, 0x10, 6, node_id);
+	memcpy(dev->dev_addr, node_id, 6);
+	if (pegasus_read_phy_word(usb, 1, &temp)) 
+		return 2;
+
+	if ((~temp & 4) && !loopback) {
+		warn("%s: link NOT established (0x%x), check the cable.",
+			dev->name, temp);
+		/* return 3; FIXME */
+	}
+
+	if (pegasus_read_phy_word(usb, 5, &partmedia))
+		return 4;
+
+	if ((partmedia & 0x1f) != 1) {
+		warn("party FAIL %x", partmedia);
+		/* return 5;	FIXME */ 
+	}
+
+	data[0] = 0xc9;
+	data[1] = (partmedia & 0x100) ? 0x30 : ((partmedia & 0x80) ? 0x10 : 0);
+	data[2] = (loopback & 1) ? 0x09 : 0x01;
+
+	pegasus_set_registers(usb, 0, 3, data);
+
+	return 0;
+}
+
+
+static void pegasus_read_bulk(struct urb *urb)
+{
+	struct pegasus *pegasus = urb->context;
+	struct net_device *net = pegasus->net;
+	int count = urb->actual_length, res;
+	int rx_status = *(int *)(pegasus->rx_buff + count - 4);
+	struct sk_buff	*skb;
+	__u16 pkt_len;
+
+	if (urb->status) {
+		dbg("%s: RX status %d", net->name, urb->status);
+		goto goon;
+	}
+
+	if (!count)
+		goto goon;
+#if 0
+	if (rx_status & 0x00010000)
+		goto goon;
+#endif
+	if (rx_status & 0x000e0000) {
+
+		dbg("%s: error receiving packet %x", net->name, rx_status & 0xe0000);
+		pegasus->stats.rx_errors++;
+		if(rx_status & 0x060000) pegasus->stats.rx_length_errors++;
+		if(rx_status & 0x080000) pegasus->stats.rx_crc_errors++;
+		if(rx_status & 0x100000) pegasus->stats.rx_frame_errors++;
+
+		goto goon;
+	}
+
+	pkt_len = (rx_status & 0xfff) - 8;
+
+	if(!(skb = dev_alloc_skb(pkt_len+2)))
+		goto goon;
+
+	skb->dev = net;
+	skb_reserve(skb, 2);
+	eth_copy_and_sum(skb, pegasus->rx_buff, pkt_len, 0);
+	skb_put(skb, pkt_len);
+
+	skb->protocol = eth_type_trans(skb, net);
+	netif_rx(skb);
+	pegasus->stats.rx_packets++;
+	pegasus->stats.rx_bytes += pkt_len;
+
+goon:
+	if ((res = usb_submit_urb(&pegasus->rx_urb)))
+		warn("(prb)failed rx_urb %d", res);
+}
+
+
+static void pegasus_irq(urb_t *urb)
+{
+	__u8	*d = urb->transfer_buffer;
+	
+	if ( d[0] )
+		dbg("txst0=0x%2x", d[0]);
+}
+
+
+static void pegasus_write_bulk(struct urb *urb)
+{
+	struct pegasus *pegasus = urb->context;
+
+	spin_lock(&pegasus->pegasus_lock);
+
+	if (urb->status)
+		info("%s: TX status %d", pegasus->net->name, urb->status);
+	netif_wake_queue(pegasus->net);
+
+	spin_unlock(&pegasus->pegasus_lock);
+}
+
+#if 0
+static void pegasus_tx_timeout(struct net_device *net)
+{
+	struct pegasus *pegasus = net->priv;
+
+	warn("%s: Tx timed out. Reseting...", net->name);
+	usb_unlink_urb(&pegasus->tx_urb);
+	pegasus->stats.tx_errors++;
+	net->trans_start = jiffies;
+	pegasus->flags |= PEGASUS_RESET;
+
+	netif_wake_queue(net);
+}
+#endif
+
+
+static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
+{
+	struct pegasus	*pegasus = net->priv;
+	int count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3;
+	int res;
+
+	if (net->tbusy) {
+	  int tickssofar = jiffies - net->trans_start;
+	  if (tickssofar < PEGASUS_TX_TIMEOUT)
+	    return 1;
+	  warn("%s: Tx timed out. Reseting...", net->name);
+	  pegasus->stats.tx_errors++;
+	  net->trans_start = jiffies;
+	  net->tbusy = 0;
+	  netif_wake_queue(net);
+	  dev_kfree_skb(skb);
+	  return 0;
+	}
+	spin_lock(&pegasus->pegasus_lock);
+
+	netif_stop_queue(net);
+
+	((__u16 *)pegasus->tx_buff)[0] = skb->len;
+	memcpy(pegasus->tx_buff+2, skb->data, skb->len);
+	(&pegasus->tx_urb)->transfer_buffer_length = count;
+
+	if ((res = usb_submit_urb(&pegasus->tx_urb))) {
+		warn("failed tx_urb %d", res);
+		pegasus->stats.tx_errors++;
+		netif_start_queue(net);
+	} else {
+		pegasus->stats.tx_packets++;
+		pegasus->stats.tx_bytes += skb->len;
+		net->trans_start = jiffies;
+	}
+
+	dev_kfree_skb(skb);
+
+	spin_unlock(&pegasus->pegasus_lock);
+
+	return 0;
+}
+
+
+static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
+{
+	return &((struct pegasus *)dev->priv)->stats;
+}
+
+
+static int pegasus_open(struct net_device *net)
+{
+	struct pegasus *pegasus = (struct pegasus *)net->priv;
+	int res;
+
+	if ((res = pegasus_start_net(net, pegasus->usb))) {
+		err("can't start_net() - %d", res);
+		return -EIO;
+	}
+
+	if ((res = usb_submit_urb(&pegasus->rx_urb)))
+		warn("(open)failed rx_urb %d", res);
+		
+	if ((res = usb_submit_urb(&pegasus->intr_urb)))
+		warn("(open)failed intr_urb %d", res);
+		
+	netif_start_queue(net);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+
+static int pegasus_close(struct net_device *net)
+{
+	struct pegasus	*pegasus = net->priv;
+
+	netif_stop_queue(net);
+
+	if ( pegasus->rx_urb.status == -EINPROGRESS )
+		usb_unlink_urb(&pegasus->rx_urb);
+	if ( pegasus->tx_urb.status == -EINPROGRESS )	
+		usb_unlink_urb(&pegasus->tx_urb);
+	if ( pegasus->intr_urb.status == -EINPROGRESS )
+		usb_unlink_urb(&pegasus->intr_urb);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	__u16 *data = (__u16 *)&rq->ifr_data;
+	struct pegasus	*pegasus = net->priv;
+
+	switch(cmd) {
+		case SIOCDEVPRIVATE:
+			data[0] = 1;
+		case SIOCDEVPRIVATE+1:
+			pegasus_read_phy_word(pegasus->usb, data[1] & 0x1f, &data[3]);
+			return 0;
+		case SIOCDEVPRIVATE+2:
+			if (!capable(CAP_NET_ADMIN))
+				return -EPERM;
+			pegasus_write_phy_word(pegasus->usb, data[1] & 0x1f, data[2]);
+			return 0;
+		default:
+			return -EOPNOTSUPP;
+	}
+}
+
+
+static void pegasus_set_rx_mode(struct net_device *net)
+{
+	struct pegasus *pegasus = net->priv;
+
+	netif_stop_queue(net);
+
+	if (net->flags & IFF_PROMISC) {
+		info("%s: Promiscuous mode enabled", net->name);
+/*		pegasus_set_register(pegasus->usb, 2, 0x04); FIXME */
+	} else if ((net->mc_count > multicast_filter_limit) ||
+			(net->flags & IFF_ALLMULTI)) {
+		pegasus_set_register(pegasus->usb, 0, 0xfa);
+		pegasus_set_register(pegasus->usb, 2, 0);
+		info("%s set allmulti", net->name);
+	} else {
+		info("%s: set Rx mode", net->name);
+	}
+
+	netif_wake_queue(net);
+}
+
+
+static int check_device_ids( __u16 vendor, __u16 product )
+{
+	int i=0;
+	
+	while ( usb_dev_id[i].name ) {
+		if ( (usb_dev_id[i].vendor == vendor) && 
+			(usb_dev_id[i].device == product) )
+			return i;
+		i++;
+	}
+	return	-1;
+}
+
+
+static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct net_device *net;
+	struct pegasus *pegasus;
+	int	dev_indx;
+
+	if ( (dev_indx = check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct)) == -1 ) {
+		return NULL;
+	}
+
+	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+		err("usb_set_configuration() failed");
+		return NULL;
+	}
+
+	if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
+		err("out of memory allocating device structure");
+		return NULL;
+	}
+	memset(pegasus, 0, sizeof(struct pegasus));
+
+	if (pegasus_reset_mac(dev)) {
+		err("can't reset MAC");
+		kfree(pegasus);
+		return NULL;
+	}
+	
+	net = init_etherdev(0, 0);
+	net->priv = pegasus;
+	net->open = pegasus_open;
+	net->stop = pegasus_close;
+#if 0
+	net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
+	net->tx_timeout = pegasus_tx_timeout;
+#endif
+	net->do_ioctl = pegasus_ioctl;
+	net->hard_start_xmit = pegasus_start_xmit;
+	net->set_multicast_list = pegasus_set_rx_mode;
+	net->get_stats = pegasus_netdev_stats;
+	net->mtu = PEGASUS_MTU;
+
+	pegasus->usb = dev;
+	pegasus->net = net;
+	pegasus->pegasus_lock = SPIN_LOCK_UNLOCKED;
+
+	FILL_BULK_URB(&pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1),
+			pegasus->rx_buff, PEGASUS_MAX_MTU, pegasus_read_bulk, 
+			pegasus);
+	FILL_BULK_URB(&pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2),
+			pegasus->tx_buff, PEGASUS_MAX_MTU, pegasus_write_bulk,
+			pegasus);
+	FILL_INT_URB(&pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3),
+			pegasus->intr_buff, 8, pegasus_irq, pegasus, 500);
+
+
+	printk(KERN_INFO "%s: %s\n", net->name, usb_dev_id[dev_indx].name);
+
+	return pegasus;
+}
+
+
+static void pegasus_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct pegasus *pegasus = ptr;
+
+	if (!pegasus) {
+		warn("unregistering non-existant device");
+		return;
+	}
+
+	if (pegasus->net->flags & IFF_UP)
+		dev_close(pegasus->net);
+
+	unregister_netdev(pegasus->net);
+
+	if ( pegasus->rx_urb.status == -EINPROGRESS )
+		usb_unlink_urb(&pegasus->rx_urb);
+	if ( pegasus->tx_urb.status == -EINPROGRESS )
+		usb_unlink_urb(&pegasus->tx_urb);
+	if ( pegasus->intr_urb.status == -EINPROGRESS )
+		usb_unlink_urb(&pegasus->intr_urb);
+
+	kfree(pegasus);
+}
+
+
+static struct usb_driver pegasus_driver = {
+	name:		"pegasus",
+	probe:		pegasus_probe,
+	disconnect:	pegasus_disconnect,
+};
+
+int __init pegasus_init(void)
+{
+	printk( version );
+	return usb_register(&pegasus_driver);
+}
+
+void __exit pegasus_exit(void)
+{
+	usb_deregister(&pegasus_driver);
+}
+
+module_init(pegasus_init);
+module_exit(pegasus_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/plusb.c linux.18p8/drivers/usb/plusb.c
--- linux.vanilla/drivers/usb/plusb.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/plusb.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,621 @@
+/*****************************************************************************/
+
+/*
+ *      plusb.c  --  prolific pl-2302 driver.
+ *
+ *      Copyright (C) 2000  Deti Fliegl (deti@fliegl.de)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ *  $Id: plusb.c,v 1.18 2000/02/14 10:38:58 fliegl Exp $
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+//#define DEBUG
+#include <linux/usb.h>
+
+#include "plusb.h"
+
+/* --------------------------------------------------------------------- */
+
+#define NRPLUSB 4
+
+/*-------------------------------------------------------------------*/
+
+static plusb_t plusb[NRPLUSB];
+
+/* --------------------------------------------------------------------- */
+static int plusb_add_buf_tail (plusb_t *s, struct list_head *dst, struct list_head *src)
+{
+	unsigned long flags;
+	struct list_head *tmp;
+	int ret = 0;
+
+	spin_lock_irqsave (&s->lock, flags);
+
+	if (list_empty (src)) {
+		// no elements in source buffer
+		ret = -1;
+		goto err;
+	}
+	tmp = src->next;
+	list_del (tmp);
+	list_add_tail (tmp, dst);
+
+  err:	spin_unlock_irqrestore (&s->lock, flags);
+	return ret;
+}
+/*-------------------------------------------------------------------*/
+
+static int plusb_my_bulk(plusb_t *s, int pipe, void *data, int size, int *actual_length)
+{
+	int ret;
+
+	dbg("plusb_my_bulk: len:%d",size);
+
+	ret=usb_bulk_msg(s->usbdev, pipe, data, size, actual_length, 500);
+	if(ret<0) {
+		err("plusb: usb_bulk_msg failed(%d)",ret);
+	}
+	
+	if( ret == -EPIPE ) {
+		warn("CLEAR_FEATURE request to remove STALL condition.");
+		if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
+			err("request failed");
+		}
+
+	dbg("plusb_my_bulk: finished act: %d", *actual_length);		
+	return ret;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_bh(void *context)
+{
+	plusb_t *s=context;
+	struct net_device_stats *stats=&s->net_stats;
+	int ret=0;
+	int actual_length;
+	skb_list_t *skb_list;
+	struct sk_buff *skb;
+
+	dbg("plusb_bh: i:%d",in_interrupt());
+
+	while(!list_empty(&s->tx_skb_list)) {
+
+		if(!(s->status&_PLUSB_TXOK))
+			break; 
+		
+		skb_list = list_entry (s->tx_skb_list.next, skb_list_t, skb_list);
+		if(!skb_list->state) {
+			dbg("plusb_bh: not yet ready");
+			schedule();
+			continue;
+		}
+
+		skb=skb_list->skb;
+		ret=plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
+		                  skb->data, skb->len, &actual_length);
+	
+		if(ret || skb->len != actual_length ||!(skb->len%64)) {
+			plusb_my_bulk(s, usb_sndbulkpipe (s->usbdev, _PLUSB_BULKOUTPIPE),
+		              NULL, 0, &actual_length);
+		}
+
+		if(!ret) {
+			stats->tx_packets++;
+			stats->tx_bytes+=skb->len;
+                }
+		else {
+			stats->tx_errors++;
+			stats->tx_aborted_errors++;
+		}
+
+		dbg("plusb_bh: dev_kfree_skb");
+
+		dev_kfree_skb(skb);
+		skb_list->state=0;
+		plusb_add_buf_tail (s, &s->free_skb_list, &s->tx_skb_list);	
+	}
+
+	dbg("plusb_bh: finished");
+	s->in_bh=0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int plusb_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	plusb_t *s=dev->priv;
+	skb_list_t *skb_list;
+	int ret=NET_XMIT_SUCCESS;
+
+	dbg("plusb_net_xmit: len:%d i:%d",skb->len,in_interrupt());
+
+        if(!s->connected || list_empty(&s->free_skb_list)) {
+		ret=NET_XMIT_CN;
+		goto lab;
+	}	
+
+	plusb_add_buf_tail (s, &s->tx_skb_list, &s->free_skb_list);
+	skb_list = list_entry (s->tx_skb_list.prev, skb_list_t, skb_list);
+	skb_list->skb=skb;
+	skb_list->state=1;
+
+lab:
+	if(s->in_bh)
+		return ret;
+
+	dbg("plusb_net_xmit: queue_task");
+
+	s->in_bh=1;
+	queue_task(&s->bh, &tq_scheduler);
+
+	dbg("plusb_net_xmit: finished");
+	return ret;
+
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_bulk_complete(urb_t *purb)
+{
+	plusb_t *s=purb->context;
+
+	dbg("plusb_bulk_complete: status:%d length:%d",purb->status,purb->actual_length);
+	if(!s->connected)
+		return;
+
+	if( !purb->status) {
+		struct sk_buff *skb;
+		unsigned char *dst;
+		int len=purb->transfer_buffer_length;
+		struct net_device_stats *stats=&s->net_stats;
+
+		skb=dev_alloc_skb(len);
+
+		if(!skb) {
+			err("plusb_bulk_complete: dev_alloc_skb(%d)=NULL, dropping frame",len);
+			stats->rx_dropped++;
+			return;
+		}
+
+		dst=(char *)skb_put(skb, len);
+		memcpy( dst, purb->transfer_buffer, len);
+
+		skb->dev=&s->net_dev;
+		skb->protocol=eth_type_trans(skb, skb->dev);
+		stats->rx_packets++;
+		stats->rx_bytes+=len;
+		netif_rx(skb);
+	}
+	else
+		purb->status=0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_int_complete(urb_t *purb)
+{
+	plusb_t *s=purb->context;
+	s->status=((unsigned char*)purb->transfer_buffer)[0]&255;
+#if 0
+	if((s->status&0x3f)!=0x20) {
+		warn("invalid device status %02X", s->status);
+		return;
+	}
+#endif	
+	if(!s->connected)
+		return;
+
+	if(s->status&_PLUSB_RXD) {
+		int ret;
+		
+		if(s->bulkurb->status) {
+			err("plusb_int_complete: URB still in use");
+			return;
+		}
+		
+		ret=usb_submit_urb(s->bulkurb);
+		if(ret && ret!=-EBUSY) {
+			err("plusb_int_complete: usb_submit_urb failed");
+		}
+	}
+		
+	if(purb->status || s->status!=160)
+		dbg("status: %p %d buf: %02X", purb->dev, purb->status, s->status);
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_free_all(plusb_t *s)
+{
+	struct list_head *skb;
+	skb_list_t *skb_list;
+	
+	dbg("plusb_free_all");
+	run_task_queue(&tq_immediate);	
+
+	if(s->inturb) {
+		dbg("unlink inturb");
+		usb_unlink_urb(s->inturb);
+	}
+
+	if(s->inturb && s->inturb->transfer_buffer) {
+		dbg("kfree inturb->transfer_buffer");
+		kfree(s->inturb->transfer_buffer);
+		s->inturb->transfer_buffer=NULL;
+	}
+	
+	if(s->inturb) {
+		dbg("free_urb inturb");
+		usb_free_urb(s->inturb);
+		s->inturb=NULL;
+	}
+
+	if(s->bulkurb) {
+		dbg("unlink bulkurb");
+		usb_unlink_urb(s->bulkurb);
+	}
+	
+	if(s->bulkurb && s->bulkurb->transfer_buffer) {
+		dbg("kfree bulkurb->transfer_buffer");
+		kfree(s->bulkurb->transfer_buffer);
+		s->bulkurb->transfer_buffer=NULL;
+	}
+	if(s->bulkurb) {
+		dbg("free_urb bulkurb");
+		usb_free_urb(s->bulkurb);
+		s->bulkurb=NULL;
+	}
+	
+	while(!list_empty(&s->free_skb_list)) {
+		skb=s->free_skb_list.next;
+		list_del(skb);
+		skb_list = list_entry (skb, skb_list_t, skb_list);
+		kfree(skb_list);
+	}
+
+	while(!list_empty(&s->tx_skb_list)) {
+		skb=s->tx_skb_list.next;
+		list_del(skb);
+		skb_list = list_entry (skb, skb_list_t, skb_list);
+		kfree(skb_list);	
+	}
+	dbg("plusb_free_all: finished");	
+}
+
+/*-------------------------------------------------------------------*/
+
+static int plusb_alloc(plusb_t *s)
+{
+	int i;
+	skb_list_t *skb;
+
+	dbg("plusb_alloc");
+	
+	for(i=0 ; i < _SKB_NUM ; i++) {
+		skb=kmalloc(sizeof(skb_list_t), GFP_KERNEL);
+		if(!skb) {
+			err("kmalloc for skb_list failed");
+			goto reject;
+		}
+		memset(skb, 0, sizeof(skb_list_t));
+		list_add(&skb->skb_list, &s->free_skb_list);
+	}
+
+	dbg("inturb allocation:");
+	s->inturb=usb_alloc_urb(0);
+	if(!s->inturb) {
+		err("alloc_urb failed");
+		goto reject;
+	}
+
+	dbg("bulkurb allocation:");	
+	s->bulkurb=usb_alloc_urb(0);
+	if(!s->bulkurb) {
+		err("alloc_urb failed");
+		goto reject;
+	}
+	
+	dbg("bulkurb/inturb init:");
+	s->inturb->dev=s->usbdev;
+	s->inturb->pipe=usb_rcvintpipe (s->usbdev, _PLUSB_INTPIPE);
+	s->inturb->transfer_buffer=kmalloc(64, GFP_KERNEL);
+	if(!s->inturb->transfer_buffer) {
+		err("kmalloc failed");
+		goto reject;
+	}
+	
+	s->inturb->transfer_buffer_length=1;
+	s->inturb->complete=plusb_int_complete;
+	s->inturb->context=s;
+	s->inturb->interval=10;
+
+	dbg("inturb submission:");
+	if(usb_submit_urb(s->inturb)<0) {
+		err("usb_submit_urb failed");
+		goto reject;
+	}
+
+	dbg("bulkurb init:");
+	s->bulkurb->dev=s->usbdev;
+	s->bulkurb->pipe=usb_rcvbulkpipe (s->usbdev, _PLUSB_BULKINPIPE);
+	s->bulkurb->transfer_buffer=kmalloc(_BULK_DATA_LEN, GFP_KERNEL);
+	if(!s->bulkurb->transfer_buffer) {
+		err("kmalloc failed");
+		goto reject;
+	}
+	
+	s->bulkurb->transfer_buffer_length=_BULK_DATA_LEN;
+	s->bulkurb->complete=plusb_bulk_complete;
+	s->bulkurb->context=s;
+	
+	dbg("plusb_alloc: finished");
+	
+	return 0;
+
+  reject:
+  	dbg("plusb_alloc: failed");
+	
+	plusb_free_all(s);
+	return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------*/
+
+static int plusb_net_open(struct net_device *dev)
+{
+	plusb_t *s=dev->priv;
+	
+	dbg("plusb_net_open");
+	
+	if(plusb_alloc(s))
+		return -ENOMEM;
+
+	s->opened=1;
+	MOD_INC_USE_COUNT;
+	
+	dbg("plusb_net_open: success");
+	
+	return 0;
+	
+}
+
+/* --------------------------------------------------------------------- */
+
+static int plusb_net_stop(struct net_device *dev)
+{
+	plusb_t *s=dev->priv;
+	
+	dbg("plusb_net_stop");	
+	
+	plusb_free_all(s);
+	s->opened=0;
+	MOD_DEC_USE_COUNT;
+	dbg("plusb_net_stop:finished");
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct net_device_stats *plusb_net_get_stats(struct net_device *dev)
+{
+	plusb_t *s=dev->priv;
+	
+	dbg("net_device_stats");
+	
+	return &s->net_stats;
+}
+
+/* --------------------------------------------------------------------- */
+
+static plusb_t *plusb_find_struct (void)
+{
+	int u;
+
+	for (u = 0; u < NRPLUSB; u++) {
+		plusb_t *s = &plusb[u];
+		if (!s->connected)
+			return s;
+	}
+	return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void plusb_disconnect (struct usb_device *usbdev, void *ptr)
+{
+	plusb_t *s = ptr;
+
+	dbg("plusb_disconnect");
+	s->connected = 0;
+	
+	plusb_free_all(s);
+
+	if(!s->opened && s->net_dev.name) {
+		dbg("unregistering netdev: %s",s->net_dev.name);
+		unregister_netdev(&s->net_dev);
+		s->net_dev.name[0] = '\0';
+	}
+	
+	dbg("plusb_disconnect: finished");
+	MOD_DEC_USE_COUNT;
+}
+
+/* --------------------------------------------------------------------- */
+
+int plusb_net_init(struct net_device *dev)
+{
+	dbg("plusb_net_init");
+	
+	dev->open=plusb_net_open;
+	dev->stop=plusb_net_stop;
+	dev->hard_start_xmit=plusb_net_xmit;
+	dev->get_stats	= plusb_net_get_stats;
+	ether_setup(dev);
+	dev->tx_queue_len = 0;
+	dev->flags = IFF_POINTOPOINT|IFF_NOARP;
+
+	
+	dbg("plusb_net_init: finished");
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void *plusb_probe (struct usb_device *usbdev, unsigned int ifnum)
+{
+	plusb_t *s;
+
+	dbg("plusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
+	  usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum);
+
+	if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct > 0x1)
+		return NULL;
+
+	/* We don't handle multiple configurations */
+	if (usbdev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	s = plusb_find_struct ();
+	if (!s)
+		return NULL;
+
+	s->usbdev = usbdev;
+
+	if (usb_set_configuration (s->usbdev, usbdev->config[0].bConfigurationValue) < 0) {
+		err("set_configuration failed");
+		return NULL;
+	}
+
+	if (usb_set_interface (s->usbdev, 0, 0) < 0) {
+		err("set_interface failed");
+		return NULL;
+	}
+
+	if(!s->net_dev.name[0]) {
+		strcpy(s->net_dev.name, "plusb%d");
+		s->net_dev.init=plusb_net_init;
+		s->net_dev.priv=s;
+		if(!register_netdev(&s->net_dev))
+			info("registered: %s", s->net_dev.name);
+		else {
+			err("register_netdev failed");
+			s->net_dev.name[0] = '\0';
+		}
+	}
+		
+	s->connected = 1;
+
+	if(s->opened) {
+		dbg("net device already allocated, restarting USB transfers");
+		plusb_alloc(s);
+	}
+
+	info("bound to interface: %d dev: %p", ifnum, usbdev);
+	MOD_INC_USE_COUNT;
+	return s;
+}
+/* --------------------------------------------------------------------- */
+
+static struct usb_driver plusb_driver =
+{
+	name: "plusb",
+	probe: plusb_probe,
+	disconnect: plusb_disconnect,
+};
+
+/* --------------------------------------------------------------------- */
+
+int __init plusb_init (void)
+{
+	unsigned u;
+	dbg("plusb_init");
+	
+	/* initialize struct */
+	for (u = 0; u < NRPLUSB; u++) {
+		plusb_t *s = &plusb[u];
+		memset (s, 0, sizeof (plusb_t));
+		s->bh.routine = (void (*)(void *))plusb_bh;
+		s->bh.data = s;
+		INIT_LIST_HEAD (&s->tx_skb_list);
+		INIT_LIST_HEAD (&s->free_skb_list);
+		spin_lock_init (&s->lock);
+	}
+
+	/* register misc device */
+	usb_register (&plusb_driver);
+
+	dbg("plusb_init: driver registered");
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+void __exit plusb_cleanup (void)
+{
+	unsigned u;
+
+	dbg("plusb_cleanup");
+	for (u = 0; u < NRPLUSB; u++) {
+		plusb_t *s = &plusb[u];
+		if(s->net_dev.name[0]) {
+			dbg("unregistering netdev: %s",s->net_dev.name);
+			unregister_netdev(&s->net_dev);
+		}
+	}
+	usb_deregister (&plusb_driver);
+	dbg("plusb_cleanup: finished");
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de");
+MODULE_DESCRIPTION ("PL-2302 USB Interface Driver for Linux (c)2000");
+
+/* --------------------------------------------------------------------- */
+int __init init_module (void)
+{
+	return plusb_init ();
+}
+/* --------------------------------------------------------------------- */
+void __exit cleanup_module (void)
+{
+	plusb_cleanup ();
+}
+
+#endif
+
+/* --------------------------------------------------------------------- */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/plusb.h linux.18p8/drivers/usb/plusb.h
--- linux.vanilla/drivers/usb/plusb.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/plusb.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,48 @@
+#define _PLUSB_INTPIPE		0x1
+#define _PLUSB_BULKOUTPIPE	0x2
+#define _PLUSB_BULKINPIPE	0x3
+
+#define _SKB_NUM		1000
+//  7  6  5  4  3  2  1  0
+//  tx rx 1  0
+// 1110 0000 rxdata
+// 1010 0000 idle
+// 0010 0000 tx over
+// 0110      tx over + rxd
+
+#define _PLUSB_RXD		0x40
+#define _PLUSB_TXOK		0x80
+
+#ifdef __KERNEL__
+#define _BULK_DATA_LEN		16384
+
+typedef struct
+{
+	struct list_head skb_list;
+	struct sk_buff *skb;
+	int state;
+} skb_list_t,*pskb_list_t;
+
+typedef struct
+{
+	struct usb_device *usbdev;
+
+	int status;
+	int connected;
+	int in_bh;
+	int opened;
+
+	spinlock_t lock;
+
+	urb_t *inturb;
+	urb_t *bulkurb;	
+
+	struct list_head tx_skb_list;
+	struct list_head free_skb_list;
+	struct tq_struct bh;
+
+	struct net_device net_dev;
+	struct net_device_stats net_stats;
+} plusb_t,*pplusb_t;
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/printer.c linux.18p8/drivers/usb/printer.c
--- linux.vanilla/drivers/usb/printer.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/printer.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,526 @@
+/*
+ * printer.c  Version 0.5
+ *
+ * Copyright (c) 1999 Michael Gee	<michael@linuxspecific.com>
+ * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
+ * Copyright (c) 2000 Vojtech Pavlik	<vojtech@suse.cz>
+ * Copyright (c) 2000 Randy Dunlap	<randy.dunlap@intel.com>
+ *
+ * USB Printer Device Class driver for USB printers and printer cables
+ *
+ * Sponsored by SuSE
+ *
+ * ChangeLog:
+ *	v0.1 - thorough cleaning, URBification, almost a rewrite
+ *	v0.2 - some more cleanups
+ *	v0.3 - cleaner again, waitqueue fixes
+ *	v0.4 - fixes in unidirectional mode
+ *	v0.5 - add DEVICE_ID string support
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/lp.h>
+//#define DEBUG
+#include <linux/usb.h>
+
+#define USBLP_BUF_SIZE		8192
+#define DEVICE_ID_SIZE		1024
+
+#define IOCNR_GET_DEVICE_ID	1
+#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)	/* get device_id string */
+
+/*
+ * A DEVICE_ID string may include the printer's serial number.
+ * It should end with a semi-colon (';').
+ * An example from an HP 970C DeskJet printer is (this is one long string,
+ * with the serial number changed):
+MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:Hewlett-Packard DeskJet 970C;SERN:US970CSEPROF;VSTATUS:$HB0$NC0,ff,DN,IDLE,CUT,K1,C0,DP,NR,KP000,CP027;VP:0800,FL,B0;VJ:                    ;
+ */
+
+/*
+ * USB Printer Requests
+ */
+
+#define USBLP_REQ_GET_ID	0x00
+#define USBLP_REQ_GET_STATUS	0x01
+#define USBLP_REQ_RESET		0x02
+
+#define USBLP_MINORS		16
+#define USBLP_MINOR_BASE	0
+
+#define USBLP_WRITE_TIMEOUT	(60*HZ)			/* 60 seconds */
+
+struct usblp {
+	struct usb_device 	*dev;			/* USB device */
+	struct urb		readurb, writeurb;	/* The urbs */
+	wait_queue_head_t	wait;			/* Zzzzz ... */
+	int			readcount;		/* Counter for reads */
+	int			ifnum;			/* Interface number */
+	int			minor;			/* minor number of device */
+	unsigned char		used;			/* True if open */
+	unsigned char		bidir;			/* interface is bidirectional */
+	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
+					/* first 2 bytes are (big-endian) length */
+};
+
+static struct usblp *usblp_table[USBLP_MINORS] = { NULL, /* ... */ };
+
+/*
+ * Functions for usblp control messages.
+ */
+
+static int usblp_ctrl_msg(struct usblp *usblp, int request, int dir, int recip, int value, void *buf, int len)
+{
+	int retval = usb_control_msg(usblp->dev,
+		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
+		request, USB_TYPE_CLASS | dir | recip, value, usblp->ifnum, buf, len, HZ * 5);
+	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d len: %#x result: %d",
+		request, !!dir, recip, value, len, retval);
+	return retval < 0 ? retval : 0;
+}
+
+#define usblp_read_status(usblp, status)\
+	usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1)
+#define usblp_get_id(usblp, config, id, maxlen)\
+	usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen)
+#define usblp_reset(usblp)\
+	usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0)
+
+/*
+ * URB callback.
+ */
+
+static void usblp_bulk(struct urb *urb)
+{
+	struct usblp *usblp = urb->context;
+
+	if (!usblp || !usblp->dev || !usblp->used)
+		return;
+
+	if (urb->status)
+		warn("nonzero read/write bulk status received: %d", urb->status);
+
+	wake_up_interruptible(&usblp->wait);
+}
+
+/*
+ * Get and print printer errors.
+ */
+
+static int usblp_check_status(struct usblp *usblp)
+{
+	unsigned char status;
+
+	if (usblp_read_status(usblp, &status)) {
+		err("failed reading usblp status");
+		return -EIO;
+	}
+
+	if (~status & LP_PERRORP) {
+		if (status & LP_POUTPA) {
+			info("usblp%d: out of paper", usblp->minor);
+			return -ENOSPC;
+		}
+		if (~status & LP_PSELECD) {
+			info("usblp%d: off-line", usblp->minor);
+			return -EIO;
+		}
+		if (~status & LP_PERRORP) {
+			info("usblp%d: on fire", usblp->minor);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * File op functions.
+ */
+
+static int usblp_open(struct inode *inode, struct file *file)
+{
+	int minor = MINOR(inode->i_rdev) - USBLP_MINOR_BASE;
+	struct usblp *usblp;
+	int retval;
+
+	if (minor < 0 || minor >= USBLP_MINORS)
+		return -ENODEV;
+
+	usblp  = usblp_table[minor];
+
+	if (!usblp || !usblp->dev)
+		return -ENODEV;
+
+	if (usblp->used)
+		return -EBUSY;
+
+	if ((retval = usblp_check_status(usblp))) {
+		return retval;
+	}
+
+	usblp->used = 1;
+	file->private_data = usblp;
+
+	usblp->writeurb.transfer_buffer_length = 0;
+	usblp->writeurb.status = 0;
+
+	if (usblp->bidir) {
+		usblp->readcount = 0;
+		usb_submit_urb(&usblp->readurb);
+	}
+
+	return 0;
+}
+
+static int usblp_release(struct inode *inode, struct file *file)
+{
+	struct usblp *usblp = file->private_data;
+
+	usblp->used = 0;
+
+	if (usblp->dev) {
+		if (usblp->bidir)
+			usb_unlink_urb(&usblp->readurb);
+		usb_unlink_urb(&usblp->writeurb);
+		return 0;
+	}
+
+	usblp_table[usblp->minor] = NULL;
+	kfree(usblp->device_id_string);
+	kfree(usblp);
+
+	return 0;
+}
+
+/* No kernel lock - fine */
+static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct usblp *usblp = file->private_data;
+	poll_wait(file, &usblp->wait, wait);
+	return ((usblp->bidir || usblp->readurb.status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
+	     		      | (usblp->writeurb.status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
+}
+
+static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int	length;
+	struct usblp *usblp = file->private_data;
+
+	if ((_IOC_TYPE(cmd) != 'P') || (_IOC_DIR(cmd) != _IOC_READ))
+		return -EINVAL;
+
+	switch (_IOC_NR(cmd)) {
+	case IOCNR_GET_DEVICE_ID:		/* get the DEVICE_ID string */
+		length =  (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
+#if 0
+		dbg ("usblp_ioctl GET_DEVICE_ID: actlen=%d, user size=%d, string='%s'",
+			length, _IOC_SIZE(cmd), &usblp->device_id_string[2]);
+#endif
+		if (length > _IOC_SIZE(cmd))
+			length = _IOC_SIZE(cmd);	/* truncate */
+		if (copy_to_user ((unsigned char *)arg, usblp->device_id_string, (unsigned long) length))
+		    	return -EFAULT;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct usblp *usblp = file->private_data;
+	int retval, timeout, writecount = 0;
+
+	while (writecount < count) {
+
+		if (usblp->writeurb.status == -EINPROGRESS) {
+
+			if (file->f_flags & O_NONBLOCK)
+				return -EAGAIN;
+
+			timeout = USBLP_WRITE_TIMEOUT;
+			while (timeout && usblp->writeurb.status == -EINPROGRESS) {
+
+				if (signal_pending(current))
+					return writecount ? writecount : -EINTR;
+
+				timeout = interruptible_sleep_on_timeout(&usblp->wait, timeout);
+			}
+		}
+
+		if (usblp->writeurb.status == -EINPROGRESS) {
+			usb_unlink_urb(&usblp->writeurb);
+			err("usblp%d: timed out", usblp->minor);
+			return -EIO;
+		}
+
+		if (!usblp->dev)
+			return -ENODEV;
+
+		if (!usblp->writeurb.status) {
+			writecount += usblp->writeurb.transfer_buffer_length;
+			usblp->writeurb.transfer_buffer_length = 0;
+		} else {
+			if (!(retval = usblp_check_status(usblp))) {
+				err("usblp%d: error %d writing to printer (retval=%d)",
+					usblp->minor, usblp->writeurb.status, retval);
+				return -EIO;
+			}
+
+			return retval;
+		}
+
+		if (writecount == count)
+			continue;
+
+		usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
+							 (count - writecount) : USBLP_BUF_SIZE;
+
+		if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
+				usblp->writeurb.transfer_buffer_length)) return -EFAULT;
+
+		usb_submit_urb(&usblp->writeurb);
+	}
+
+	return count;
+}
+
+static ssize_t usblp_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct usblp *usblp = file->private_data;
+
+	if (!usblp->bidir)
+		return -EINVAL;
+
+	if (usblp->readurb.status == -EINPROGRESS) {
+
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		while (usblp->readurb.status == -EINPROGRESS) {
+			if (signal_pending(current))
+				return -EINTR;
+			interruptible_sleep_on(&usblp->wait);
+		}
+	}
+
+	if (!usblp->dev)
+		return -ENODEV;
+
+	if (usblp->readurb.status) {
+		err("usblp%d: error %d reading from printer",
+			usblp->minor, usblp->readurb.status);
+		usb_submit_urb(&usblp->readurb);
+		return -EIO;
+	}
+
+	count = count < usblp->readurb.actual_length - usblp->readcount ?
+		count :	usblp->readurb.actual_length - usblp->readcount;
+
+	if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count))
+		return -EFAULT;
+
+	if ((usblp->readcount += count) == usblp->readurb.actual_length)
+		usb_submit_urb(&usblp->readurb);
+
+	return count;
+}
+
+static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *epread, *epwrite;
+	struct usblp *usblp;
+	int minor, i, alts = -1, bidir = 0;
+	int length, err;
+	char *buf;
+
+	for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
+
+		interface = &dev->actconfig->interface[ifnum].altsetting[i];
+
+		if (interface->bInterfaceClass != 7 || interface->bInterfaceSubClass != 1 ||
+		   (interface->bInterfaceProtocol != 1 && interface->bInterfaceProtocol != 2) ||
+		   (interface->bInterfaceProtocol > interface->bNumEndpoints))
+			continue;
+
+		if (alts == -1)
+			alts = i;
+
+		if (!bidir && interface->bInterfaceProtocol == 2) {
+			bidir = 1;
+			alts = i;
+		}
+	}
+
+	if (alts == -1)
+		return NULL;
+
+	interface = &dev->actconfig->interface[ifnum].altsetting[alts];
+	if (usb_set_interface(dev, ifnum, alts))
+		err("can't set desired altsetting %d on interface %d", alts, ifnum);
+
+	epwrite = interface->endpoint + 0;
+	epread = bidir ? interface->endpoint + 1 : NULL;
+
+	if ((epwrite->bEndpointAddress & 0x80) == 0x80) {
+		if (interface->bNumEndpoints == 1)
+			return NULL;
+		epwrite = interface->endpoint + 1;
+		epread = bidir ? interface->endpoint + 0 : NULL;
+	}
+
+	if ((epwrite->bEndpointAddress & 0x80) == 0x80)
+		return NULL;
+
+	if (bidir && (epread->bEndpointAddress & 0x80) != 0x80)
+		return NULL;
+
+	for (minor = 0; minor < USBLP_MINORS && usblp_table[minor]; minor++);
+	if (usblp_table[minor]) {
+		err("no more free usblp devices");
+		return NULL;
+	}
+
+	if (!(usblp = kmalloc(sizeof(struct usblp), GFP_KERNEL))) {
+		err("out of memory");
+		return NULL;
+	}
+	memset(usblp, 0, sizeof(struct usblp));
+
+	usblp->dev = dev;
+	usblp->ifnum = ifnum;
+	usblp->minor = minor;
+	usblp->bidir = bidir;
+
+	init_waitqueue_head(&usblp->wait);
+
+	if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
+		err("out of memory");
+		kfree(usblp);
+		return NULL;
+	}
+
+	if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
+		err("out of memory");
+		kfree(usblp);
+		kfree(buf);
+		return NULL;
+	}
+
+	FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+		buf, 0, usblp_bulk, usblp);
+
+	if (bidir)
+		FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+			buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk, usblp);
+
+	/* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
+	err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
+	if (err >= 0) {
+		length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
+		if (length < DEVICE_ID_SIZE)
+			usblp->device_id_string[length] = '\0';
+		else
+			usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';
+		dbg ("usblp%d Device ID string [%d]=%s",
+			minor, length, &usblp->device_id_string[2]);
+	}
+	else {
+		err ("usblp%d: error = %d reading IEEE-1284 Device ID string",
+			minor, err);
+		usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
+	}
+
+#ifdef DEBUG
+	usblp_check_status(usblp);
+#endif
+
+	info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
+		minor, bidir ? "Bi" : "Uni", dev->devnum, ifnum, alts);
+
+	return usblp_table[minor] = usblp;
+}
+
+static void usblp_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usblp *usblp = ptr;
+
+	if (!usblp || !usblp->dev) {
+		err("disconnect on nonexisting interface");
+		return;
+	}
+
+	usblp->dev = NULL;
+
+	usb_unlink_urb(&usblp->writeurb);
+	if (usblp->bidir)
+		usb_unlink_urb(&usblp->readurb);
+
+	kfree(usblp->writeurb.transfer_buffer);
+
+	if (usblp->used) return;
+
+	kfree(usblp->device_id_string);
+
+	usblp_table[usblp->minor] = NULL;
+	kfree(usblp);
+}
+
+static struct file_operations usblp_fops = {
+	read:		usblp_read,
+	write:		usblp_write,
+	poll:		usblp_poll,
+	ioctl:		usblp_ioctl,
+	open:		usblp_open,
+	release:	usblp_release,
+};
+
+static struct usb_driver usblp_driver = {
+	name:		"usblp",
+	probe:		usblp_probe,
+	disconnect:	usblp_disconnect,
+	fops:		&usblp_fops,
+	minor:		USBLP_MINOR_BASE
+};
+
+static int __init usblp_init(void)
+{
+	if (usb_register(&usblp_driver))
+		return -1;
+	return 0;
+}
+
+static void __exit usblp_exit(void)
+{
+	usb_deregister(&usblp_driver);
+}
+
+module_init(usblp_init);
+module_exit(usblp_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/restart linux.18p8/drivers/usb/restart
--- linux.vanilla/drivers/usb/restart	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/restart	Thu Jan  1 01:00:00 1970
@@ -1,38 +0,0 @@
-#!/bin/sh
-
-ME=`basename $0`
-
-#UMOD=`lsmod | grep '^bp-mouse' | grep -v grep`
-#if test "$UMOD"; then
-#  echo "$ME: removing bp-mouse.o"
-#  if ! rmmod bp-mouse; then
-#    echo "$ME: cannot remove bp-mouse.o"
-#    exit 1
-#  fi
-#fi
-
-UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'`
-if test "$UPID"; then
-  echo "$ME: killing $UPID"
-  kill $UPID
-fi
-
-UMOD=`lsmod | grep '^usb-ohci' | grep -v grep`
-if test "$UMOD"; then
-  echo "$ME: removing usb-ohci.o"
-  sleep 1
-  if ! rmmod usb-ohci; then
-    echo "$ME: cannot remove usb-ohci.o"
-    exit 1
-  fi
-fi
-
-dmesg -c > /dev/null
-
-echo "$ME: starting usb-ohci.o"
-insmod -m usb-ohci.o > usb-ohci.map
-
-sleep 1
-UPID=`ps aux | grep ohci-control | grep -v grep | awk '{print $2}'`
-if test "$UPID"; then echo "$ME: ohci-control is pid $UPID" ; fi
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/rio500.c linux.18p8/drivers/usb/rio500.c
--- linux.vanilla/drivers/usb/rio500.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/rio500.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,447 @@
+/* -*- linux-c -*- */
+
+/* 
+ * Driver for USB Rio 500
+ *
+ * Cesar Miquel (miquel@df.uba.ar)
+ * 
+ * based on hp_scanner.c by David E. Nelson (dnelson@jump.net)
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
+ *
+ * */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#include "rio500_usb.h"
+
+#define RIO_MINOR   64
+
+/* stall/wait timeout for rio */
+#define NAK_TIMEOUT (HZ)
+
+#define IBUF_SIZE 0x1000
+
+/* Size of the rio buffer */
+#define OBUF_SIZE 0x10000
+
+struct rio_usb_data {
+        struct usb_device *rio_dev;     /* init: probe_rio */
+        unsigned int ifnum;             /* Interface number of the USB device */
+        int isopen;                     /* nz if open */
+        int present;                    /* Device is present on the bus */
+        char *obuf, *ibuf;              /* transfer buffers */
+        char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
+        wait_queue_head_t wait_q;       /* for timeouts */
+};
+
+static struct rio_usb_data rio_instance;
+
+static int open_rio(struct inode *inode, struct file *file)
+{
+	struct rio_usb_data *rio = &rio_instance;
+
+	if (rio->isopen || !rio->present) {
+		return -EBUSY;
+	}
+	rio->isopen = 1;
+
+	init_waitqueue_head(&rio->wait_q);
+
+	MOD_INC_USE_COUNT;
+
+	info("Rio opened.");
+
+	return 0;
+}
+
+static int close_rio(struct inode *inode, struct file *file)
+{
+	struct rio_usb_data *rio = &rio_instance;
+
+	rio->isopen = 0;
+
+	MOD_DEC_USE_COUNT;
+
+	info("Rio closed.");
+	return 0;
+}
+
+static int
+ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg)
+{
+	struct RioCommand rio_cmd;
+	struct rio_usb_data *rio = &rio_instance;
+	void *data;
+	unsigned char *buffer;
+	int result, requesttype;
+	int retries;
+
+        /* Sanity check to make sure rio is connected, powered, etc */
+        if ( rio == NULL ||
+             rio->present == 0 ||
+             rio->rio_dev == NULL )
+          return -1;
+
+	switch (cmd) {
+	case RIO_RECV_COMMAND:
+		data = (void *) arg;
+		if (data == NULL)
+			break;
+		copy_from_user_ret(&rio_cmd, data, sizeof(struct RioCommand),
+				   -EFAULT);
+		if (rio_cmd.length > PAGE_SIZE)
+			return -EINVAL;
+		buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
+		if (buffer == NULL)
+			return -ENOMEM;
+		copy_from_user_ret(buffer, rio_cmd.buffer, rio_cmd.length,
+				   -EFAULT);
+
+		requesttype = rio_cmd.requesttype | USB_DIR_IN |
+		    USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+		dbg
+		    ("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
+		     requesttype, rio_cmd.request, rio_cmd.value,
+		     rio_cmd.index, rio_cmd.length);
+		/* Send rio control message */
+		retries = 3;
+		while (retries) {
+			result = usb_control_msg(rio->rio_dev,
+						 usb_rcvctrlpipe(rio-> rio_dev, 0),
+						 rio_cmd.request,
+						 requesttype,
+						 rio_cmd.value,
+						 rio_cmd.index, buffer,
+						 rio_cmd.length,
+						 rio_cmd.timeout);
+			if (result == -ETIMEDOUT)
+				retries--;
+			else if (result < 0) {
+				err("Error executing ioctrl. code = %d",
+				     le32_to_cpu(result));
+				retries = 0;
+			} else {
+				dbg("Executed ioctl. Result = %d (data=%04x)",
+				     le32_to_cpu(result),
+				     le32_to_cpu(*((long *) buffer)));
+				copy_to_user_ret(rio_cmd.buffer, buffer,
+						 rio_cmd.length, -EFAULT);
+				retries = 0;
+			}
+
+			/* rio_cmd.buffer contains a raw stream of single byte
+			   data which has been returned from rio.  Data is
+			   interpreted at application level.  For data that
+			   will be cast to data types longer than 1 byte, data
+			   will be little_endian and will potentially need to
+			   be swapped at the app level */
+
+		}
+		free_page((unsigned long) buffer);
+		break;
+
+	case RIO_SEND_COMMAND:
+		data = (void *) arg;
+		if (data == NULL)
+			break;
+		copy_from_user_ret(&rio_cmd, data, sizeof(struct RioCommand),
+				   -EFAULT);
+		if (rio_cmd.length > PAGE_SIZE)
+			return -EINVAL;
+		buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
+		if (buffer == NULL)
+			return -ENOMEM;
+		copy_from_user_ret(buffer, rio_cmd.buffer, rio_cmd.length,
+				   -EFAULT);
+
+		requesttype = rio_cmd.requesttype | USB_DIR_OUT |
+		    USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+		dbg("sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
+		     requesttype, rio_cmd.request, rio_cmd.value,
+		     rio_cmd.index, rio_cmd.length);
+		/* Send rio control message */
+		retries = 3;
+		while (retries) {
+			result = usb_control_msg(rio->rio_dev,
+						 usb_sndctrlpipe(rio-> rio_dev, 0),
+						 rio_cmd.request,
+						 requesttype,
+						 rio_cmd.value,
+						 rio_cmd.index, buffer,
+						 rio_cmd.length,
+						 rio_cmd.timeout);
+			if (result == -ETIMEDOUT)
+				retries--;
+			else if (result < 0) {
+				err("Error executing ioctrl. code = %d",
+				     le32_to_cpu(result));
+				retries = 0;
+			} else {
+				dbg("Executed ioctl. Result = %d",
+				       le32_to_cpu(result));
+				retries = 0;
+
+			}
+
+		}
+		free_page((unsigned long) buffer);
+		break;
+
+	default:
+		return -ENOIOCTLCMD;
+		break;
+	}
+
+	return 0;
+}
+
+static ssize_t
+write_rio(struct file *file, const char *buffer,
+	  size_t count, loff_t * ppos)
+{
+	struct rio_usb_data *rio = &rio_instance;
+
+	unsigned long copy_size;
+	unsigned long bytes_written = 0;
+	unsigned int partial;
+
+	int result = 0;
+	int maxretry;
+
+        /* Sanity check to make sure rio is connected, powered, etc */
+        if ( rio == NULL ||
+             rio->present == 0 ||
+             rio->rio_dev == NULL )
+          return -1;
+
+	do {
+		unsigned long thistime;
+		char *obuf = rio->obuf;
+
+		thistime = copy_size =
+		    (count >= OBUF_SIZE) ? OBUF_SIZE : count;
+		if (copy_from_user(rio->obuf, buffer, copy_size))
+			return -EFAULT;
+		maxretry = 5;
+		while (thistime) {
+			if (!rio->rio_dev)
+				return -ENODEV;
+			if (signal_pending(current)) {
+				return bytes_written ? bytes_written : -EINTR;
+			}
+
+			result = usb_bulk_msg(rio->rio_dev,
+					 usb_sndbulkpipe(rio->rio_dev, 2),
+					 obuf, thistime, &partial, 5 * HZ);
+
+			dbg("write stats: result:%d thistime:%lu partial:%u",
+			     result, thistime, partial);
+
+			if (result == USB_ST_TIMEOUT) {	/* NAK - so hold for a while */
+				if (!maxretry--) {
+					return -ETIME;
+				}
+				interruptible_sleep_on_timeout(&rio-> wait_q, NAK_TIMEOUT);
+				continue;
+			} else if (!result & partial) {
+				obuf += partial;
+				thistime -= partial;
+			} else
+				break;
+		};
+		if (result) {
+			err("Write Whoops - %x", result);
+			return -EIO;
+		}
+		bytes_written += copy_size;
+		count -= copy_size;
+		buffer += copy_size;
+	} while (count > 0);
+
+	return bytes_written ? bytes_written : -EIO;
+}
+
+static ssize_t
+read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos)
+{
+	struct rio_usb_data *rio = &rio_instance;
+	ssize_t read_count;
+	unsigned int partial;
+	int this_read;
+	int result;
+	int maxretry = 10;
+	char *ibuf = rio->ibuf;
+
+        /* Sanity check to make sure rio is connected, powered, etc */
+        if ( rio == NULL ||
+             rio->present == 0 ||
+             rio->rio_dev == NULL )
+          return -1;
+
+	read_count = 0;
+
+	while (count > 0) {
+		if (signal_pending(current)) {
+			return read_count ? read_count : -EINTR;
+		}
+		if (!rio->rio_dev)
+			return -ENODEV;
+		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
+
+		result = usb_bulk_msg(rio->rio_dev,
+				      usb_rcvbulkpipe(rio->rio_dev, 1),
+				      ibuf, this_read, &partial,
+				      (int) (HZ * 8));
+
+		dbg(KERN_DEBUG "read stats: result:%d this_read:%u partial:%u",
+		       result, this_read, partial);
+
+		if (partial) {
+			count = this_read = partial;
+		} else if (result == USB_ST_TIMEOUT || result == 15) {	/* FIXME: 15 ??? */
+			if (!maxretry--) {
+				err("read_rio: maxretry timeout");
+				return -ETIME;
+			}
+			interruptible_sleep_on_timeout(&rio->wait_q,
+						       NAK_TIMEOUT);
+			continue;
+		} else if (result != USB_ST_DATAUNDERRUN) {
+			err("Read Whoops - result:%u partial:%u this_read:%u",
+			     result, partial, this_read);
+			return -EIO;
+		} else {
+			return (0);
+		}
+
+		if (this_read) {
+			if (copy_to_user(buffer, ibuf, this_read))
+				return -EFAULT;
+			count -= this_read;
+			read_count += this_read;
+			buffer += this_read;
+		}
+	}
+	return read_count;
+}
+
+static void *probe_rio(struct usb_device *dev, unsigned int ifnum)
+{
+	struct rio_usb_data *rio = &rio_instance;
+
+	if (dev->descriptor.idVendor != 0x841) {
+		return NULL;
+	}
+
+	if (dev->descriptor.idProduct != 0x1 /* RIO 500 */ ) {
+		warn(KERN_INFO "Rio player model not supported/tested.");
+		return NULL;
+	}
+
+	info("USB Rio found at address %d", dev->devnum);
+
+	rio->present = 1;
+	rio->rio_dev = dev;
+
+	if (!(rio->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) {
+		err("probe_rio: Not enough memory for the output buffer");
+		return NULL;
+	}
+	dbg("probe_rio: obuf address:%p", rio->obuf);
+
+	if (!(rio->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) {
+		err("probe_rio: Not enough memory for the input buffer");
+		kfree(rio->obuf);
+		return NULL;
+	}
+	dbg("probe_rio: ibuf address:%p", rio->ibuf);
+
+	return rio;
+}
+
+static void disconnect_rio(struct usb_device *dev, void *ptr)
+{
+	struct rio_usb_data *rio = (struct rio_usb_data *) ptr;
+
+	if (rio->isopen) {
+		rio->isopen = 0;
+		/* better let it finish - the release will do whats needed */
+		rio->rio_dev = NULL;
+		return;
+	}
+	kfree(rio->ibuf);
+	kfree(rio->obuf);
+
+	info("USB Rio disconnected.");
+
+	rio->present = 0;
+}
+
+static struct
+file_operations usb_rio_fops = {
+	read:		read_rio,
+	write:		write_rio,
+	ioctl:		ioctl_rio,
+	open:		open_rio,
+	release:	close_rio,
+};
+
+static struct
+usb_driver rio_driver = {
+	"rio500",
+	probe_rio,
+	disconnect_rio,
+	{NULL, NULL},
+	&usb_rio_fops,
+	RIO_MINOR
+};
+
+int usb_rio_init(void)
+{
+	if (usb_register(&rio_driver) < 0)
+		return -1;
+
+	info("USB Rio support registered.");
+	return 0;
+}
+
+
+void usb_rio_cleanup(void)
+{
+	struct rio_usb_data *rio = &rio_instance;
+
+	rio->present = 0;
+	usb_deregister(&rio_driver);
+
+
+}
+
+module_init(usb_rio_init);
+module_exit(usb_rio_cleanup);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/rio500_usb.h linux.18p8/drivers/usb/rio500_usb.h
--- linux.vanilla/drivers/usb/rio500_usb.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/rio500_usb.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,37 @@
+/*  ----------------------------------------------------------------------
+
+    Copyright (C) 2000  Cesar Miquel  (miquel@df.uba.ar)
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    ---------------------------------------------------------------------- */
+
+
+
+#define RIO_SEND_COMMAND			0x1
+#define RIO_RECV_COMMAND			0x2
+
+#define RIO_DIR_OUT               	        0x0
+#define RIO_DIR_IN				0x1
+
+struct RioCommand {
+	short length;
+	int request;
+	int requesttype;
+	int value;
+	int index;
+	void *buffer;
+	int timeout;
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/scanner.c linux.18p8/drivers/usb/scanner.c
--- linux.vanilla/drivers/usb/scanner.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/scanner.c	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,876 @@
+/* -*- linux-c -*- */
+
+/* 
+ * Driver for USB Scanners (linux-2.4.0test1-ac7)
+ *
+ * Copyright (C) 1999, 2000 David E. Nelson
+ *
+ * Portions may be copyright Brad Keryan and Michael Gee.
+ *
+ * David E. Nelson (dnelson@jump.net)
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Originally based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
+ *
+ * History
+ *
+ *  0.1  8/31/1999
+ *
+ *    Developed/tested using linux-2.3.15 with minor ohci.c changes to
+ *    support short packes during bulk xfer mode.  Some testing was
+ *    done with ohci-hcd but the performace was low.  Very limited
+ *    testing was performed with uhci but I was unable to get it to
+ *    work.  Initial relase to the linux-usb development effort.
+ *
+ *
+ *  0.2  10/16/1999
+ *
+ *    - Device can't be opened unless a scanner is plugged into the USB.
+ *    - Finally settled on a reasonable value for the I/O buffer's.
+ *    - Cleaned up write_scanner()
+ *    - Disabled read/write stats
+ *    - A little more code cleanup
+ *
+ *
+ *  0.3  10/18/1999
+ *
+ *    - Device registration changed to reflect new device
+ *      allocation/registration for linux-2.3.22+.
+ *    - Adopted David Brownell's <david-b@pacbell.net> technique for 
+ *      assigning bulk endpoints.
+ *    - Removed unnessesary #include's
+ *    - Scanner model now reported via syslog INFO after being detected 
+ *      *and* configured.
+ *    - Added user specified vendor:product USB ID's which can be passed 
+ *      as module parameters.
+ *
+ *
+ *  0.3.1
+ *
+ *    - Applied patches for linux-2.3.25.
+ *    - Error number reporting changed to reflect negative return codes.
+ *
+ *
+ *  0.3.2
+ *
+ *    - Applied patches for linux-2.3.26 to scanner_init().
+ *    - Debug read/write stats now report values as signed decimal.
+ *
+ *
+ *  0.3.3
+ *
+ *    - Updated the bulk_msg() calls to usb usb_bulk_msg().
+ *    - Added a small delay in the write_scanner() method to aid in
+ *      avoiding NULL data reads on HP scanners.  We'll see how this works.
+ *    - Return values from usb_bulk_msg() now ignore positive values for
+ *      use with the ohci driver.
+ *    - Added conditional debugging instead of commenting/uncommenting
+ *      all over the place.
+ *    - kfree()'d the pointer after using usb_string() as documented in
+ *      linux-usb-api.txt.
+ *    - Added usb_set_configuration().  It got lost in version 0.3 -- ack!
+ *    - Added the HP 5200C USB Vendor/Product ID's.
+ *
+ *
+ *  0.3.4  1/23/2000
+ *
+ *    - Added Greg K-H's <greg@kroah.com> patch for better handling of 
+ *      Product/Vendor detection.
+ *    - The driver now autoconfigures its endpoints including interrupt
+ *      endpoints if one is detected.  The concept was originally based
+ *      upon David Brownell's method.
+ *    - Added some Seiko/Epson ID's. Thanks to Karl Heinz 
+ *      Kremer <khk@khk.net>.
+ *    - Added some preliminary ioctl() calls for the PV8630 which is used
+ *      by the HP4200. The ioctl()'s still have to be registered. Thanks 
+ *      to Adrian Perez Jorge <adrianpj@easynews.com>.
+ *    - Moved/migrated stuff to scanner.h
+ *    - Removed the usb_set_configuration() since this is handled by
+ *      the usb_new_device() routine in usb.c.
+ *    - Added the HP 3300C.  Thanks to Bruce Tenison.
+ *    - Changed user specified vendor/product id so that root hub doesn't
+ *      get falsely attached to. Thanks to Greg K-H.
+ *    - Added some Mustek ID's. Thanks to Gernot Hoyler 
+ *      <Dr.Hoyler@t-online.de>.
+ *    - Modified the usb_string() reporting.  See kfree() comment above.
+ *    - Added Umax Astra 2000U. Thanks to Doug Alcorn <doug@lathi.net>.
+ *    - Updated the printk()'s to use the info/warn/dbg macros.
+ *    - Updated usb_bulk_msg() argument types to fix gcc warnings.
+ *
+ *
+ *  0.4  2/4/2000
+ *
+ *    - Removed usb_string() from probe_scanner since the core now does a
+ *      good job of reporting what was connnected.  
+ *    - Finally, simultaneous multiple device attachment!
+ *    - Fixed some potential memory freeing issues should memory allocation
+ *      fail in probe_scanner();
+ *    - Some fixes to disconnect_scanner().
+ *    - Added interrupt endpoint support.
+ *    - Added Agfa SnapScan Touch. Thanks to Jan Van den Bergh
+ *      <jan.vandenbergh@cs.kuleuven.ac.be>.
+ *    - Added Umax 1220U ID's. Thanks to Maciek Klimkowski
+ *      <mac@nexus.carleton.ca>.
+ *    - Fixed bug in write_scanner(). The buffer was not being properly
+ *      updated for writes larger than OBUF_SIZE. Thanks to Henrik 
+ *      Johansson <henrikjo@post.utfors.se> for identifying it.
+ *    - Added Microtek X6 ID's. Thanks to Oliver Neukum
+ *      <Oliver.Neukum@lrz.uni-muenchen.de>.
+ *
+ * 
+ *  0.4.1  2/15/2000
+ *  
+ *    - Fixed 'count' bug in read_scanner(). Thanks to Henrik
+ *      Johansson <henrikjo@post.utfors.se> for identifying it.  Amazing
+ *      it has worked this long.
+ *    - Fixed '>=' bug in both read/write_scanner methods.
+ *    - Cleaned up both read/write_scanner() methods so that they are 
+ *      a little more readable.
+ *    - Added a lot of Microtek ID's.  Thanks to Adrian Perez Jorge.
+ *    - Adopted the __initcall().
+ *    - Added #include <linux/init.h> to scanner.h for __initcall().
+ *    - Added one liner in irq_scanner() to keep gcc from complaining 
+ *      about an unused variable (data) if debugging was disabled
+ *      in scanner.c.
+ *    - Increased the timeout parameter in read_scanner() to 120 Secs.
+ *
+ *
+ *  0.4.2  3/23/2000
+ *
+ *    - Added Umax 1236U ID.  Thanks to Philipp Baer <ph_baer@npw.net>.
+ *    - Added Primax, ReadyScan, Visioneer, Colorado, and Genius ID's.
+ *      Thanks to Adrian Perez Jorge <adrianpj@easynews.com>.
+ *    - Fixed error number reported for non-existant devices.  Thanks to
+ *      Spyridon Papadimitriou <Spyridon_Papadimitriou@gs91.sp.cs.cmu.edu>.
+ *    - Added Acer Prisascan 620U ID's.  Thanks to Joao <joey@knoware.nl>.
+ *    - Replaced __initcall() with module_init()/module_exit(). Updates
+ *      from patch-2.3.48.
+ *    - Replaced file_operations structure with new syntax.  Updates
+ *      from patch-2.3.49.
+ *    - Changed #include "usb.h" to #include <linux/usb.h>
+ *    - Added #define SCN_IOCTL to exclude development areas 
+ *      since 2.4.x is about to be released. This mainly affects the 
+ *      ioctl() stuff.  See scanner.h for more details.
+ *    - Changed the return value for signal_pending() from -ERESTARTSYS to
+ *      -EINTR.
+ *
+ *
+ * 0.4.3  4/30/2000
+ *
+ *    - Added Umax Astra 2200 ID.  Thanks to Flynn Marquardt 
+ *      <flynn@isr.uni-stuttgart.de>.
+ *    - Added iVina 1200U ID. Thanks to Dyson Lin <dyson@avision.com.tw>.
+ *    - Added access time update for the device file courtesy of Paul
+ *      Mackerras <paulus@linuxcare.com>.  This allows a user space daemon
+ *      to turn the lamp off for a Umax 1220U scanner after a prescribed
+ *      time.
+ *    - Fixed HP S20 ID's.  Thanks to Ruud Linders <rlinders@xs4all.nl>.
+ *    - Added Acer ScanPrisa 620U ID. Thanks to Oliver
+ *      Schwartz <Oliver.Schwartz@gmx.de> via sane-devel mail list.
+ *    - Fixed bug in read_scanner for copy_to_user() function.  The returned
+ *      value should be 'partial' not 'this_read'.
+ *    - Fixed bug in read_scanner. 'count' should be decremented 
+ *      by 'this_read' and not by 'partial'.  This resulted in twice as many
+ *      calls to read_scanner() for small amounts of data and possibly
+ *      unexpected returns of '0'.  Thanks to Karl Heinz 
+ *      Kremer <khk@khk.net> and Alain Knaff <Alain.Knaff@ltnb.lu>
+ *      for discovering this.
+ *    - Integrated Randy Dunlap's <randy.dunlap@intel.com> patch for a
+ *      scanner lookup/ident table. Thanks Randy.
+ *    - Documentation updates.
+ *    - Added wait queues to read_scanner().
+ *
+ *
+ * 0.4.3.1
+ *
+ *    - Fixed HP S20 ID's...again..sigh.  Thanks to Ruud
+ *      Linders <rlinders@xs4all.nl>.
+ *
+ *
+ *  TODO
+ *
+ *    - Performance
+ *    - Select/poll methods
+ *    - More testing
+ *    - Proper registry/assignment for LM9830 ioctl's
+ *
+ *
+ *  Thanks to:
+ *
+ *    - All the folks on the linux-usb list who put up with me. :)  This 
+ *      has been a great learning experience for me.
+ *    - To Linus Torvalds for this great OS.
+ *    - The GNU folks.
+ *    - The folks that forwarded Vendor:Product ID's to me.
+ *    - Johannes Erdfelt for the loaning of a USB analyzer for tracking an
+ *      issue with HP-4100 and uhci.
+ *    - Adolfo Montero for his assistance.
+ *    - All the folks who chimed in with reports and suggestions.
+ *    - All the developers that are working on USB SANE backends or other
+ *      applications to use USB scanners.
+ *
+ *  Performance:
+ *
+ *    System: Pentium 120, 80 MB RAM, OHCI, Linux 2.3.23, HP 4100C USB Scanner
+ *            300 dpi scan of the entire bed
+ *      24 Bit Color ~ 70 secs - 3.6 Mbit/sec
+ *       8 Bit Gray  ~ 17 secs - 4.2 Mbit/sec
+ */
+
+/* 
+ * Scanner definitions, macros, module info, 
+ * debug/ioctl/data_dump enable, and other constants.
+ */ 
+#include "scanner.h"
+
+static void
+irq_scanner(struct urb *urb)
+{
+
+/*
+ * For the meantime, this is just a placeholder until I figure out what
+ * all I want to do with it -- or somebody else for that matter.
+ */
+
+	struct scn_usb_data *scn = urb->context;
+	unsigned char *data = &scn->button;
+	data += 0;		/* Keep gcc from complaining about unused var */
+
+	if (urb->status) {
+		return;
+	}
+
+	dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
+	return;
+}
+
+
+static int
+open_scanner(struct inode * inode, struct file * file)
+{
+	struct scn_usb_data *scn;
+	struct usb_device *dev;
+
+	kdev_t scn_minor;
+
+	scn_minor = USB_SCN_MINOR(inode);
+
+	dbg("open_scanner: scn_minor:%d", scn_minor);
+
+	if (!p_scn_table[scn_minor]) {
+		err("open_scanner(%d): Unable to access minor data", scn_minor);
+		return -ENODEV;
+	}
+
+	scn = p_scn_table[scn_minor];
+
+	dev = scn->scn_dev;
+
+	if (!dev) {
+		err("open_scanner(%d): Scanner device not present", scn_minor);
+		return -ENODEV;
+	}
+
+	if (!scn->present) {
+		err("open_scanner(%d): Scanner is not present", scn_minor);
+		return -ENODEV;
+	}
+
+	if (scn->isopen) {
+		err("open_scanner(%d): Scanner device is already open", scn_minor);
+		return -EBUSY;
+	}
+
+	init_waitqueue_head(&scn->rd_wait_q);
+
+	scn->isopen = 1;
+
+	file->private_data = scn; /* Used by the read and write metheds */
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int
+close_scanner(struct inode * inode, struct file * file)
+{
+	struct scn_usb_data *scn;
+
+	kdev_t scn_minor;
+
+	scn_minor = USB_SCN_MINOR (inode);
+
+	dbg("close_scanner: scn_minor:%d", scn_minor);
+
+	if (!p_scn_table[scn_minor]) {
+		err("close_scanner(%d): invalid scn_minor", scn_minor);
+		return -ENODEV;
+	}
+
+	scn = p_scn_table[scn_minor];
+
+	scn->isopen = 0;
+
+	file->private_data = NULL;
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static ssize_t
+write_scanner(struct file * file, const char * buffer,
+              size_t count, loff_t *ppos)
+{
+	struct scn_usb_data *scn;
+	struct usb_device *dev;
+	
+	ssize_t bytes_written = 0; /* Overall count of bytes written */
+	ssize_t ret = 0;
+
+	kdev_t scn_minor;
+
+	int this_write;		/* Number of bytes to write */
+	int partial;		/* Number of bytes successfully written */
+	int result = 0;
+	
+	char *obuf;
+
+	scn = file->private_data;
+
+	scn_minor = scn->scn_minor;
+
+	obuf = scn->obuf;
+
+	dev = scn->scn_dev;
+
+	file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+
+	while (count > 0) {
+
+		if (signal_pending(current)) {
+			ret = -EINTR;
+			break;
+		}
+
+		this_write = (count >= OBUF_SIZE) ? OBUF_SIZE : count;
+		
+		if (copy_from_user(scn->obuf, buffer, this_write)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		result = usb_bulk_msg(dev,usb_sndbulkpipe(dev, scn->bulk_out_ep), obuf, this_write, &partial, 60*HZ);
+		dbg("write stats(%d): result:%d this_write:%d partial:%d", scn_minor, result, this_write, partial);
+
+		if (result == USB_ST_TIMEOUT) {	/* NAK -- shouldn't happen */
+			warn("write_scanner: NAK recieved.");
+			ret = -ETIME;
+			break;
+		} else if (result < 0) { /* We should not get any I/O errors */
+			warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn_minor, result);
+			ret = -EIO;
+			break;
+		} 
+
+#ifdef WR_DATA_DUMP
+		if (partial) {
+			unsigned char cnt, cnt_max;
+			cnt_max = (partial > 24) ? 24 : partial;
+			printk(KERN_DEBUG "dump(%d): ", scn_minor);
+			for (cnt=0; cnt < cnt_max; cnt++) {
+				printk("%X ", obuf[cnt]);
+			}
+			printk("\n");
+		}
+#endif
+		if (partial != this_write) { /* Unable to write all contents of obuf */
+			ret = -EIO;
+			break;
+		}
+
+		if (partial) { /* Data written */
+			buffer += partial;
+			count -= partial;
+			bytes_written += partial;
+		} else { /* No data written */
+			ret = 0;
+			break;
+		}
+	}
+	mdelay(5);		/* This seems to help with SANE queries */
+	return ret ? ret : bytes_written;
+}
+
+static ssize_t
+read_scanner(struct file * file, char * buffer,
+             size_t count, loff_t *ppos)
+{
+	struct scn_usb_data *scn;
+	struct usb_device *dev;
+
+	ssize_t bytes_read;	/* Overall count of bytes_read */
+	ssize_t ret;
+
+	kdev_t scn_minor;
+
+	int partial;		/* Number of bytes successfully read */
+	int this_read;		/* Max number of bytes to read */
+	int result;
+	int rd_expire = RD_EXPIRE;
+
+	char *ibuf;
+
+	scn = file->private_data;
+
+	scn_minor = scn->scn_minor;
+
+	ibuf = scn->ibuf;
+
+	dev = scn->scn_dev;
+
+	bytes_read = 0;
+	ret = 0;
+
+	file->f_dentry->d_inode->i_atime = CURRENT_TIME; /* Update the
+                                                            atime of
+                                                            the device
+                                                            node */
+
+	while (count > 0) {
+		if (signal_pending(current)) {
+			ret = -EINTR;
+			break;
+		}
+
+		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
+		
+		result = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, scn->bulk_in_ep), ibuf, this_read, &partial, RD_NAK_TIMEOUT);
+		dbg("read stats(%d): result:%d this_read:%d partial:%d count:%d", scn_minor, result, this_read, partial, count);
+
+/* 
+ * Scanners are sometimes inheriently slow since they are mechanical
+ * in nature.  USB bulk reads tend to timeout while the scanner is
+ * positioning, resetting, warming up the lamp, etc if the timeout is
+ * set too low.  A very long timeout parameter for bulk reads was used
+ * to overcome this limitation, but this sometimes resulted in folks
+ * having to wait for the timeout to expire after pressing Ctrl-C from
+ * an application. The user was sometimes left with the impression
+ * that something had hung or crashed when in fact the USB read was
+ * just waiting on data.  So, the below code retains the same long
+ * timeout period, but splits it up into smaller parts so that
+ * Ctrl-C's are acted upon in a reasonable amount of time. 
+ */
+
+		if (result == USB_ST_TIMEOUT && !partial) { /* Timeout
+                                                               and no
+                                                               data */
+			if (--rd_expire <= 0) {
+				warn("read_scanner(%d): excessive NAK's received", scn_minor);
+				ret = -ETIME;
+				break;
+			} else {
+				interruptible_sleep_on_timeout(&scn->rd_wait_q, RD_NAK_TIMEOUT);
+				continue;
+			}
+		} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
+			warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result);
+			ret = -EIO;
+			break;
+		}
+
+#ifdef RD_DATA_DUMP
+		if (partial) {
+			unsigned char cnt, cnt_max;
+			cnt_max = (partial > 24) ? 24 : partial;
+			printk(KERN_DEBUG "dump(%d): ", scn_minor);
+			for (cnt=0; cnt < cnt_max; cnt++) {
+				printk("%X ", ibuf[cnt]);
+			}
+			printk("\n");
+		}
+#endif
+
+		if (partial) { /* Data returned */
+			if (copy_to_user(buffer, ibuf, partial)) {
+				ret = -EFAULT;
+				break;
+			}
+			count -= this_read; /* Compensate for short reads */
+			bytes_read += partial; /* Keep tally of what actually was read */
+			buffer += partial;
+		} else {
+			ret = 0;
+			break;
+		}
+	}
+	
+	return ret ? ret : bytes_read;
+}
+
+static void *
+probe_scanner(struct usb_device *dev, unsigned int ifnum)
+{
+	struct scn_usb_data *scn;
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	
+	int ep_cnt;
+	int ix;
+
+	kdev_t scn_minor;
+
+	char valid_device = 0;
+	char have_bulk_in, have_bulk_out, have_intr;
+
+	if (vendor != -1 && product != -1) {
+		info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
+	}
+
+	dbg("probe_scanner: USB dev address:%p", dev);
+	dbg("probe_scanner: ifnum:%u", ifnum);
+
+/*
+ * 1. Check Vendor/Product
+ * 2. Determine/Assign Bulk Endpoints
+ * 3. Determine/Assign Intr Endpoint
+ */
+
+/* 
+ * There doesn't seem to be an imaging class defined in the USB
+ * Spec. (yet).  If there is, HP isn't following it and it doesn't
+ * look like anybody else is either.  Therefore, we have to test the
+ * Vendor and Product ID's to see what we have.  Also, other scanners
+ * may be able to use this driver by specifying both vendor and
+ * product ID's as options to the scanner module in conf.modules.
+ *
+ * NOTE: Just because a product is supported here does not mean that
+ * applications exist that support the product.  It's in the hopes
+ * that this will allow developers a means to produce applications
+ * that will support USB products.
+ *
+ * Until we detect a device which is pleasing, we silently punt.
+ */
+
+	for (ix = 0; ix < sizeof (scanner_device_ids) / sizeof (struct scanner_device); ix++) {
+		if ((dev->descriptor.idVendor == scanner_device_ids [ix].idVendor) &&
+		    (dev->descriptor.idProduct == scanner_device_ids [ix].idProduct)) {
+			valid_device = 1;
+			break;
+                }
+	}
+	if (dev->descriptor.idVendor == vendor &&   /* User specified */
+	    dev->descriptor.idProduct == product) { /* User specified */
+		valid_device = 1;
+	}
+	
+        if (!valid_device)
+                return NULL;    /* We didn't find anything pleasing */
+
+/*
+ * After this point we can be a little noisy about what we are trying to
+ *  configure.
+ */
+
+	if (dev->descriptor.bNumConfigurations != 1) {
+		info("probe_scanner: Only one device configuration is supported.");
+		return NULL;
+	}
+
+	if (dev->config[0].bNumInterfaces != 1) {
+		info("probe_scanner: Only one device interface is supported.");
+		return NULL;
+	}
+
+	interface = dev->config[0].interface[ifnum].altsetting;
+	endpoint = interface[ifnum].endpoint;
+
+/* 
+ * Start checking for two bulk endpoints OR two bulk endpoints *and* one
+ * interrupt endpoint. If we have an interrupt endpoint go ahead and
+ * setup the handler. FIXME: This is a future enhancement...
+ */
+
+	dbg("probe_scanner: Number of Endpoints:%d", (int) interface->bNumEndpoints);
+
+	if ((interface->bNumEndpoints != 2) && (interface->bNumEndpoints != 3)) {
+		info("probe_scanner: Only two or three endpoints supported.");
+		return NULL;
+	}
+
+	ep_cnt = have_bulk_in = have_bulk_out = have_intr = 0;
+
+	while (ep_cnt < interface->bNumEndpoints) {
+
+		if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) {
+			ep_cnt++;
+			have_bulk_in = ep_cnt;
+			dbg("probe_scanner: bulk_in_ep:%d", have_bulk_in);
+			continue;
+		}
+		
+		if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) {
+			ep_cnt++;
+			have_bulk_out = ep_cnt;
+			dbg("probe_scanner: bulk_out_ep:%d", have_bulk_out);
+			continue;
+		}
+
+		if (!have_intr && IS_EP_INTR(endpoint[ep_cnt])) {
+			ep_cnt++;
+			have_intr = ep_cnt;
+			dbg("probe_scanner: intr_ep:%d", have_intr);
+			continue;
+		}
+		info("probe_scanner: Undetected endpoint. Notify the maintainer.");
+		return NULL;	/* Shouldn't ever get here unless we have something weird */
+	}
+
+
+/*
+ * Perform a quick check to make sure that everything worked as it
+ * should have.
+ */
+
+	switch(interface->bNumEndpoints) {
+	case 2:
+		if (!have_bulk_in || !have_bulk_out) {
+			info("probe_scanner: Two bulk endpoints required.");
+			return NULL;
+		}
+		break;
+	case 3:
+		if (!have_bulk_in || !have_bulk_out || !have_intr) {
+			info("probe_scanner: Two bulk endpoints and one interrupt endpoint required.");
+			return NULL;
+		}
+		break;
+	default:
+		info("probe_scanner: Endpoint determination failed.  Notify the maintainer.");
+		return NULL;
+	}
+
+
+/* 
+ * Determine a minor number and initialize the structure associated
+ * with it.  The problem with this is that we are counting on the fact
+ * that the user will sequentially add device nodes for the scanner
+ * devices.  */
+
+	for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
+		if (!p_scn_table[scn_minor])
+			break;
+	}
+
+/* Check to make sure that the last slot isn't already taken */
+	if (p_scn_table[scn_minor]) {
+		err("probe_scanner: No more minor devices remaining.");
+		return NULL;
+	}
+
+	dbg("probe_scanner: Allocated minor:%d", scn_minor);
+
+	if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
+		err("probe_scanner: Out of memory.");
+		return NULL;
+	}
+	memset (scn, 0, sizeof(struct scn_usb_data));
+	dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
+
+
+/* Ok, if we detected an interrupt EP, setup a handler for it */
+	if (have_intr) {
+		dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
+		FILL_INT_URB(&scn->scn_irq, dev, 
+			     usb_rcvintpipe(dev, have_intr),
+			     &scn->button, 1, irq_scanner, scn,
+			     // endpoint[(int)have_intr].bInterval);
+			     250);
+
+	        if (usb_submit_urb(&scn->scn_irq)) {
+			err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
+                	kfree(scn);
+                	return NULL;
+        	}
+	}
+
+
+/* Ok, now initialize all the relevant values */
+	if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
+		err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);
+		kfree(scn);
+		return NULL;
+	}
+	dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf);
+
+	if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
+		err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);
+		kfree(scn->obuf);
+		kfree(scn);
+		return NULL;
+	}
+	dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
+
+	scn->bulk_in_ep = have_bulk_in;
+	scn->bulk_out_ep = have_bulk_out;
+	scn->intr_ep = have_intr;
+	scn->present = 1;
+	scn->scn_dev = dev;
+	scn->scn_minor = scn_minor;
+	scn->isopen = 0;
+
+	return p_scn_table[scn_minor] = scn;
+}
+
+static void
+disconnect_scanner(struct usb_device *dev, void *ptr)
+{
+	struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
+	
+	if(scn->intr_ep) {
+		dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
+		usb_unlink_urb(&scn->scn_irq);
+	}
+        usb_driver_release_interface(&scanner_driver,
+                &scn->scn_dev->actconfig->interface[scn->ifnum]);
+
+	kfree(scn->ibuf);
+	kfree(scn->obuf);
+
+	dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
+	p_scn_table[scn->scn_minor] = NULL;
+	kfree (scn);
+}
+
+#ifdef SCN_IOCTL
+static int
+ioctl_scanner(struct inode *inode, struct file *file,
+	      unsigned int cmd, unsigned long arg)
+{
+	struct usb_device *dev;
+	
+	int result;
+
+	kdev_t scn_minor;
+	
+	scn_minor = USB_SCN_MINOR(inode);
+
+	if (!p_scn_table[scn_minor]) {
+		err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
+		return -ENODEV;
+	}
+
+	dev = p_scn_table[scn_minor]->scn_dev;
+	
+	switch (cmd)
+	{
+	case PV8630_IOCTL_INREQUEST :
+	{
+		struct {
+			__u8  data;
+			__u8  request;
+			__u16 value;
+			__u16 index;
+		} args;
+		
+		if (copy_from_user(&args, (void *)arg, sizeof(args)))
+			return -EFAULT;
+		
+		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+					 args.request, USB_TYPE_VENDOR|
+					 USB_RECIP_DEVICE|USB_DIR_IN,
+					 args.value, args.index, &args.data,
+					 1, HZ*5);
+
+		dbg("ioctl_scanner(%d): inreq: args.data:%x args.value:%x args.index:%x args.request:%x\n", scn_minor, args.data, args.value, args.index, args.request);
+
+		if (copy_to_user((void *)arg, &args, sizeof(args)))
+			return -EFAULT;
+
+		dbg("ioctl_scanner(%d): inreq: result:%d\n", scn_minor, result);
+		
+		return result;
+	}
+	case PV8630_IOCTL_OUTREQUEST :
+	{
+		struct {
+			__u8  request;
+			__u16 value;
+			__u16 index;
+		} args;
+		
+		if (copy_from_user(&args, (void *)arg, sizeof(args)))
+			return -EFAULT;
+		
+		dbg("ioctl_scanner(%d): outreq: args.value:%x args.index:%x args.request:%x\n", scn_minor, args.value, args.index, args.request);
+
+		result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+					 args.request, USB_TYPE_VENDOR|
+					 USB_RECIP_DEVICE|USB_DIR_OUT,
+					 args.value, args.index, NULL,
+					 0, HZ*5);
+
+		dbg("ioctl_scanner(%d): outreq: result:%d\n", scn_minor, result);
+		
+		return result;
+	}
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+#endif /* SCN_IOCTL */
+
+static struct
+file_operations usb_scanner_fops = {
+	read:		read_scanner,
+	write:		write_scanner,
+#ifdef SCN_IOCTL
+	ioctl:		ioctl_scanner,
+#endif /* SCN_IOCTL */
+	open:		open_scanner,
+	release:	close_scanner,
+};
+
+static struct
+usb_driver scanner_driver = {
+       "usbscanner",
+       probe_scanner,
+       disconnect_scanner,
+       { NULL, NULL },
+       &usb_scanner_fops,
+       SCN_BASE_MNR
+};
+
+void __exit
+usb_scanner_exit(void)
+{
+	usb_deregister(&scanner_driver);
+}
+
+int __init
+usb_scanner_init (void)
+{
+        if (usb_register(&scanner_driver) < 0)
+                return -1;
+
+	info("USB Scanner support registered.");
+	return 0;
+}
+
+module_init(usb_scanner_init);
+module_exit(usb_scanner_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/scanner.h linux.18p8/drivers/usb/scanner.h
--- linux.vanilla/drivers/usb/scanner.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/scanner.h	Fri Sep 15 15:13:10 2000
@@ -0,0 +1,166 @@
+/*
+ * Driver for USB Scanners (linux-2.4.0test1-ac7)
+ *
+ * Copyright (C) 1999, 2000 David E. Nelson
+ *
+ * David E. Nelson (dnelson@jump.net)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */ 
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/ioctl.h>
+#include <linux/sched.h>
+
+// #define DEBUG
+
+#include <linux/usb.h>
+
+static __s32 vendor=-1, product=-1;
+
+MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
+MODULE_DESCRIPTION("USB Scanner Driver");
+
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+
+/* Enable to activate the ioctl interface.  This is mainly meant for */
+/* development purposes until an ioctl number is officially registered */
+// #define SCN_IOCTL
+
+/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
+// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
+// #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
+
+#define IS_EP_BULK(ep)  ((ep).bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
+#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
+#define IS_EP_INTR(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
+
+#define USB_SCN_MINOR(X) MINOR((X)->i_rdev) - SCN_BASE_MNR
+
+#ifdef DEBUG
+#define SCN_DEBUG(X) X
+#else
+#define SCN_DEBUG(X)
+#endif
+
+#define IBUF_SIZE 32768
+#define OBUF_SIZE 4096
+
+/* read_scanner timeouts -- RD_NAK_TIMEOUT * RD_EXPIRE = Number of seconds */
+#define RD_NAK_TIMEOUT (10*HZ)	/* Number of X seconds to wait */
+#define RD_EXPIRE 12		/* Number of attempts to wait X seconds */
+
+
+/* FIXME: These are NOT registered ioctls()'s */
+#define PV8630_IOCTL_INREQUEST 69
+#define PV8630_IOCTL_OUTREQUEST 70
+
+#define SCN_MAX_MNR 16		/* We're allocated 16 minors */
+#define SCN_BASE_MNR 48		/* USB Scanners start at minor 48 */
+
+struct scn_usb_data {
+	struct usb_device *scn_dev;
+	struct urb scn_irq;
+	unsigned int ifnum;	/* Interface number of the USB device */
+	kdev_t scn_minor;	/* Scanner minor - used in disconnect() */
+	unsigned char button;	/* Front panel buffer */
+        char isopen;		/* Not zero if the device is open */
+	char present;		/* Not zero if device is present */
+	char *obuf, *ibuf;	/* transfer buffers */
+	char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */
+	wait_queue_head_t rd_wait_q; /* read timeouts */
+};
+
+static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
+
+/* table of scanners that may work with this driver */
+static const struct scanner_device {
+	__u16		idVendor;
+	__u16		idProduct;
+} scanner_device_ids [] = {
+	/* Acer */
+		{ 0x04a5, 0x2060 },	/* Prisa Acerscan 620U & 640U (!) */
+		{ 0x04a5, 0x2040 },	/* Prisa AcerScan 620U (!) */
+	/* Agfa */
+		{ 0x06bd, 0x0001 },	/* SnapScan 1212U */
+		{ 0x06bd, 0x2061 },	/* Another SnapScan 1212U (?) */
+		{ 0x06bd, 0x0100 },	/* SnapScan Touch */
+	/* Colorado -- See Primax/Colorado below */
+	/* Epson -- See Seiko/Epson below */
+	/* Genius */
+		{ 0x0458, 0x2001 },	/* ColorPage-Vivid Pro */
+	/* Hewlett Packard */
+		{ 0x03f0, 0x0205 },	/* 3300C */
+		{ 0x03f0, 0x0101 },	/* 4100C */
+		{ 0x03f0, 0x0105 },	/* 4200C */
+		{ 0x03f0, 0x0102 },	/* PhotoSmart S20 */
+		{ 0x03f0, 0x0401 },	/* 5200C */
+		{ 0x03f0, 0x0201 },	/* 6200C */
+		{ 0x03f0, 0x0601 },	/* 6300C */
+	/* iVina */
+		{ 0x0638, 0x0268 },     /* 1200U */
+	/* Microtek */
+		{ 0x05da, 0x0099 },	/* ScanMaker X6 - X6U */
+		{ 0x05da, 0x0094 },	/* Phantom 336CX - C3 */
+		{ 0x05da, 0x00a0 },	/* Phantom 336CX - C3 #2 */
+		{ 0x05da, 0x009a },	/* Phantom C6 */
+		{ 0x05da, 0x00a3 },	/* ScanMaker V6USL */
+		{ 0x05da, 0x80a3 },	/* ScanMaker V6USL #2 */
+		{ 0x05da, 0x80ac },	/* ScanMaker V6UL - SpicyU */
+	/* Mustek */
+		{ 0x055f, 0x0001 },	/* 1200 CU */
+	/* Primax/Colorado */
+		{ 0x0461, 0x0300 },	/* G2-300 #1 */
+		{ 0x0461, 0x0380 },	/* G2-600 #1 */
+		{ 0x0461, 0x0301 },	/* G2E-300 #1 */
+		{ 0x0461, 0x0381 },	/* ReadyScan 636i */
+		{ 0x0461, 0x0302 },	/* G2-300 #2 */
+		{ 0x0461, 0x0382 },	/* G2-600 #2 */
+		{ 0x0461, 0x0303 },	/* G2E-300 #2 */
+		{ 0x0461, 0x0383 },	/* G2E-600 */
+		{ 0x0461, 0x0340 },	/* Colorado USB 9600 */
+		{ 0x0461, 0x0360 },	/* Colorado USB 19200 */
+		{ 0x0461, 0x0341 },	/* Colorado 600u */
+		{ 0x0461, 0x0361 },	/* Colorado 1200u */
+	/* Seiko/Epson Corp. */
+		{ 0x04b8, 0x0101 },	/* Perfection 636U and 636Photo */
+		{ 0x04b8, 0x0103 },	/* Perfection 610 */
+		{ 0x04b8, 0x0104 },	/* Perfection 1200U and 1200Photo */
+	/* Umax */
+		{ 0x1606, 0x0010 },	/* Astra 1220U */
+		{ 0x1606, 0x0002 },	/* Astra 1236U */
+		{ 0x1606, 0x0030 },	/* Astra 2000U */
+		{ 0x1606, 0x0230 },	/* Astra 2200U */
+	/* Visioneer */
+		{ 0x04a7, 0x0221 },	/* OneTouch 5300 */
+		{ 0x04a7, 0x0221 },	/* OneTouch 7600 duplicate ID (!) */
+		{ 0x04a7, 0x0231 },	/* 6100 */
+};
+
+/* Forward declarations */
+static struct usb_driver scanner_driver;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/Makefile linux.18p8/drivers/usb/serial/Makefile
--- linux.vanilla/drivers/usb/serial/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/Makefile	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,37 @@
+#
+# Makefile for the USB serial device drivers.
+#
+
+O_TARGET	:= usb-serial.o
+M_OBJS		:=
+O_OBJS		:=
+MOD_LIST_NAME	:= USB_SERIAL_MODULES
+
+# Object file lists.
+
+obj-y	:=
+obj-m	:=
+obj-n	:=
+obj-	:=
+
+obj-$(CONFIG_USB_SERIAL)			+= usbserial.o
+obj-$(CONFIG_USB_SERIAL_VISOR)			+= visor.o
+obj-$(CONFIG_USB_SERIAL_WHITEHEAT)		+= whiteheat.o
+obj-$(CONFIG_USB_SERIAL_FTDI_SIO)		+= ftdi_sio.o
+obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)		+= keyspan_pda.o
+obj-$(CONFIG_USB_SERIAL_KEYSPAN)		+= keyspan.o
+obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
+obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT)	+= digi_acceleport.o
+ 
+# Objects that export symbols.
+export-objs	:= usbserial.o
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-y)))
+OX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-y)))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+
+include $(TOPDIR)/Rules.make
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/Makefile-keyspan_pda_fw linux.18p8/drivers/usb/serial/Makefile-keyspan_pda_fw
--- linux.vanilla/drivers/usb/serial/Makefile-keyspan_pda_fw	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/Makefile-keyspan_pda_fw	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,16 @@
+
+# some rules to handle the quirks of the 'as31' assembler, like
+# insisting upon fixed suffixes for the input and output files,
+# and its lack of preprocessor support
+
+all: keyspan_pda_fw.h
+
+%.asm: %.S
+	gcc -x assembler-with-cpp -P -E -o $@ $<
+
+%.hex: %.asm
+	as31 -l $<
+	mv $*.obj $@
+
+%_fw.h: %.hex ezusb_convert.pl
+	perl ezusb_convert.pl $* < $< > $@
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/digi_acceleport.c linux.18p8/drivers/usb/serial/digi_acceleport.c
--- linux.vanilla/drivers/usb/serial/digi_acceleport.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/digi_acceleport.c	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,2038 @@
+/*
+*  Digi AccelePort USB-4 Serial Converter
+*
+*  Copyright 2000 by Digi International
+*
+*  This program is free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  Shamelessly based on Brian Warner's keyspan_pda.c and Greg Kroah-Hartman's
+*  usb-serial driver.
+*
+*  Peter Berger (pberger@brimson.com)
+*  Al Borchers (borchers@steinerpoint.com)
+*
+*  (8/8/2000) pberger and borchers
+*    -- Fixed close so that 
+*       - it can timeout while waiting for transmit idle, if needed;
+*       - it ignores interrupts when flushing the port, turning
+*         of modem signalling, and so on;
+*       - it waits for the flush to really complete before returning.
+*    -- Read_bulk_callback and write_bulk_callback check for a closed
+*       port before using the tty struct or writing to the port.
+*    -- The two changes above fix the oops caused by interrupted closes.
+*    -- Added interruptible args to write_oob_command and set_modem_signals
+*       and added a timeout arg to transmit_idle; needed for fixes to
+*       close.
+*    -- Added code for rx_throttle and rx_unthrottle so that input flow
+*       control works.
+*    -- Added code to set overrun, parity, framing, and break errors
+*       (untested).
+*    -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length
+*       bulk writes are done.  These hung the Digi USB device.  The
+*       0 length bulk writes were a new feature of usb-uhci added in
+*       the 2.4.0-test6 kernels.
+*    -- Fixed mod inc race in open; do mod inc before sleeping to wait
+*       for a close to finish.
+*
+*  (7/31/2000) pberger
+*    -- Fixed bugs with hardware handshaking:
+*       - Added code to set/clear tty->hw_stopped in digi_read_oob_callback()
+*         and digi_set_termios()
+*    -- Added code in digi_set_termios() to
+*       - add conditional in code handling transition from B0 to only
+*         set RTS if RTS/CTS flow control is either not in use or if
+*         the port is not currently throttled.
+*       - handle turning off CRTSCTS.
+*
+*  (7/30/2000) borchers
+*    -- Added support for more than one Digi USB device by moving
+*       globals to a private structure in the pointed to from the
+*       usb_serial structure.
+*    -- Moved the modem change and transmit idle wait queues into
+*       the port private structure, so each port has its own queue
+*       rather than sharing global queues.
+*    -- Added support for break signals.
+*
+*  (7/25/2000) pberger
+*    -- Added USB-2 support.  Note: the USB-2 supports 3 devices: two
+*       serial and a parallel port.  The parallel port is implemented
+*       as a serial-to-parallel converter.  That is, the driver actually
+*       presents all three USB-2 interfaces as serial ports, but the third
+*       one physically connects to a parallel device.  Thus, for example,
+*       one could plug a parallel printer into the USB-2's third port,
+*       but from the kernel's (and userland's) point of view what's
+*       actually out there is a serial device.
+*
+*  (7/15/2000) borchers
+*    -- Fixed race in open when a close is in progress.
+*    -- Keep count of opens and dec the module use count for each
+*       outstanding open when shutdown is called (on disconnect).
+*    -- Fixed sanity checks in read_bulk_callback and write_bulk_callback
+*       so pointers are checked before use.
+*    -- Split read bulk callback into in band and out of band
+*       callbacks, and no longer restart read chains if there is
+*       a status error or a sanity error.  This fixed the seg
+*       faults and other errors we used to get on disconnect.
+*    -- Port->active is once again a flag as usb-serial intended it
+*       to be, not a count.  Since it was only a char it would
+*       have been limited to 256 simultaneous opens.  Now the open
+*       count is kept in the port private structure in dp_open_count.
+*    -- Added code for modularization of the digi_acceleport driver.
+*
+*  (6/27/2000) pberger and borchers
+*    -- Zeroed out sync field in the wakeup_task before first use;
+*       otherwise the uninitialized value might prevent the task from
+*       being scheduled.
+*    -- Initialized ret value to 0 in write_bulk_callback, otherwise
+*       the uninitialized value could cause a spurious debugging message.
+*
+*  (6/22/2000) pberger and borchers
+*    -- Made cond_wait_... inline--apparently on SPARC the flags arg
+*       to spin_lock_irqsave cannot be passed to another function
+*       to call spin_unlock_irqrestore.  Thanks to Pauline Middelink.
+*    -- In digi_set_modem_signals the inner nested spin locks use just
+*       spin_lock() rather than spin_lock_irqsave().  The old code
+*       mistakenly left interrupts off.  Thanks to Pauline Middelink.
+*    -- copy_from_user (which can sleep) is no longer called while a
+*       spinlock is held.  We copy to a local buffer before getting
+*       the spinlock--don't like the extra copy but the code is simpler.
+*    -- Printk and dbg are no longer called while a spin lock is held.
+*
+*  (6/4/2000) pberger and borchers
+*    -- Replaced separate calls to spin_unlock_irqrestore and
+*       interruptible_sleep_on_timeout with a new function
+*       cond_wait_interruptible_timeout_irqrestore.  This eliminates
+*       the race condition where the wake up could happen after
+*       the unlock and before the sleep.
+*    -- Close now waits for output to drain.
+*    -- Open waits until any close in progress is finished.
+*    -- All out of band responses are now processed, not just the
+*       first in a USB packet.
+*    -- Fixed a bug that prevented the driver from working when the
+*       first Digi port was not the first USB serial port--the driver
+*       was mistakenly using the external USB serial port number to
+*       try to index into its internal ports.
+*    -- Fixed an SMP bug -- write_bulk_callback is called directly from
+*       an interrupt, so spin_lock_irqsave/spin_unlock_irqrestore are
+*       needed for locks outside write_bulk_callback that are also
+*       acquired by write_bulk_callback to prevent deadlocks.
+*    -- Fixed support for select() by making digi_chars_in_buffer()
+*       return 256 when -EINPROGRESS is set, as the line discipline
+*       code in n_tty.c expects.
+*    -- Fixed an include file ordering problem that prevented debugging
+*       messages from working.
+*    -- Fixed an intermittent timeout problem that caused writes to
+*       sometimes get stuck on some machines on some kernels.  It turns
+*       out in these circumstances write_chan() (in n_tty.c) was
+*       asleep waiting for our wakeup call.  Even though we call
+*       wake_up_interruptible() in digi_write_bulk_callback(), there is
+*       a race condition that could cause the wakeup to fail: if our
+*       wake_up_interruptible() call occurs between the time that our
+*       driver write routine finishes and write_chan() sets current->state
+*       to TASK_INTERRUPTIBLE, the effect of our wakeup setting the state
+*       to TASK_RUNNING will be lost and write_chan's subsequent call to
+*       schedule() will never return (unless it catches a signal).
+*       This race condition occurs because write_bulk_callback() (and thus
+*       the wakeup) are called asynchonously from an interrupt, rather than
+*       from the scheduler.  We can avoid the race by calling the wakeup
+*       from the scheduler queue and that's our fix:  Now, at the end of
+*       write_bulk_callback() we queue up a wakeup call on the scheduler
+*       task queue.  We still also invoke the wakeup directly since that
+*       squeezes a bit more performance out of the driver, and any lost
+*       race conditions will get cleaned up at the next scheduler run.
+*
+*       NOTE:  The problem also goes away if you comment out
+*       the two code lines in write_chan() where current->state
+*       is set to TASK_RUNNING just before calling driver.write() and to
+*       TASK_INTERRUPTIBLE immediately afterwards.  This is why the
+*       problem did not show up with the 2.2 kernels -- they do not
+*       include that code.
+*
+*  (5/16/2000) pberger and borchers
+*    -- Added timeouts to sleeps, to defend against lost wake ups.
+*    -- Handle transition to/from B0 baud rate in digi_set_termios.
+*
+*  (5/13/2000) pberger and borchers
+*    -- All commands now sent on out of band port, using
+*       digi_write_oob_command.
+*    -- Get modem control signals whenever they change, support TIOCMGET/
+*       SET/BIS/BIC ioctls.
+*    -- digi_set_termios now supports parity, word size, stop bits, and
+*       receive enable.
+*    -- Cleaned up open and close, use digi_set_termios and
+*       digi_write_oob_command to set port parameters.
+*    -- Added digi_startup_device to start read chains on all ports.
+*    -- Write buffer is only used when count==1, to be sure put_char can
+*       write a char (unless the buffer is full).
+*
+*  (5/10/2000) pberger and borchers
+*    -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls on open/close.
+*    -- Fixed problem where the first incoming character is lost on
+*       port opens after the first close on that port.  Now we keep
+*       the read_urb chain open until shutdown.
+*    -- Added more port conditioning calls in digi_open and digi_close.
+*    -- Convert port->active to a use count so that we can deal with multiple
+*       opens and closes properly.
+*    -- Fixed some problems with the locking code.
+*
+*  (5/3/2000) pberger and borchers
+*    -- First alpha version of the driver--many known limitations and bugs.
+*
+*
+*  Locking and SMP
+*
+*  - Each port, including the out-of-band port, has a lock used to
+*    serialize all access to the port's private structure.
+*  - The port lock is also used to serialize all writes and access to
+*    the port's URB.
+*  - The port lock is also used for the port write_wait condition
+*    variable.  Holding the port lock will prevent a wake up on the
+*    port's write_wait; this can be used with cond_wait_... to be sure
+*    the wake up is not lost in a race when dropping the lock and
+*    sleeping waiting for the wakeup.
+*  - digi_write() does not sleep, since it is sometimes called on
+*    interrupt time.
+*  - digi_write_bulk_callback() and digi_read_bulk_callback() are
+*    called directly from interrupts.  Hence spin_lock_irqsave()
+*    and spin_lock_irqrestore() are used in the rest of the code
+*    for any locks they acquire.
+*  - digi_write_bulk_callback() gets the port lock before waking up
+*    processes sleeping on the port write_wait.  It also schedules
+*    wake ups so they happen from the scheduler, because the tty
+*    system can miss wake ups from interrupts.
+*  - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to
+*    recheck the condition they are sleeping on.  This is defensive,
+*    in case a wake up is lost.
+*  - Following Documentation/DocBook/kernel-locking.pdf no spin locks
+*    are held when calling copy_to/from_user or printk.
+*    
+*  $Id: digi_acceleport.c,v 1.80 2000/08/09 06:36:18 root Exp $
+*/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/tqueue.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+
+/* Defines */
+
+/* port output buffer length -- must be <= transfer buffer length - 2 */
+/* so we can be sure to send the full buffer in one urb */
+#define DIGI_OUT_BUF_SIZE		8
+
+/* port input buffer length -- must be >= transfer buffer length - 3 */
+/* so we can be sure to hold at least one full buffer from one urb */
+#define DIGI_IN_BUF_SIZE		64
+
+/* retry timeout while sleeping */
+#define DIGI_RETRY_TIMEOUT		(HZ/10)
+
+/* timeout while waiting for tty output to drain in close */
+/* this delay is used twice in close, so the total delay could */
+/* be twice this value */
+#define DIGI_CLOSE_TIMEOUT		(5*HZ)
+
+
+/* AccelePort USB Defines */
+
+/* ids */
+#define DIGI_VENDOR_ID			0x05c5
+#define DIGI_2_ID			0x0002	/* USB-2 */
+#define DIGI_4_ID			0x0004	/* USB-4 */
+
+/* commands
+ * "INB": can be used on the in-band endpoint
+ * "OOB": can be used on the out-of-band endpoint
+ */
+#define DIGI_CMD_SET_BAUD_RATE			0	/* INB, OOB */
+#define DIGI_CMD_SET_WORD_SIZE			1	/* INB, OOB */
+#define DIGI_CMD_SET_PARITY			2	/* INB, OOB */
+#define DIGI_CMD_SET_STOP_BITS			3	/* INB, OOB */
+#define DIGI_CMD_SET_INPUT_FLOW_CONTROL		4	/* INB, OOB */
+#define DIGI_CMD_SET_OUTPUT_FLOW_CONTROL	5	/* INB, OOB */
+#define DIGI_CMD_SET_DTR_SIGNAL			6	/* INB, OOB */
+#define DIGI_CMD_SET_RTS_SIGNAL			7	/* INB, OOB */
+#define DIGI_CMD_READ_INPUT_SIGNALS		8	/*      OOB */
+#define DIGI_CMD_IFLUSH_FIFO			9	/*      OOB */
+#define DIGI_CMD_RECEIVE_ENABLE			10	/* INB, OOB */
+#define DIGI_CMD_BREAK_CONTROL			11	/* INB, OOB */
+#define DIGI_CMD_LOCAL_LOOPBACK			12	/* INB, OOB */
+#define DIGI_CMD_TRANSMIT_IDLE			13	/* INB, OOB */
+#define DIGI_CMD_READ_UART_REGISTER		14	/*      OOB */
+#define DIGI_CMD_WRITE_UART_REGISTER		15	/* INB, OOB */
+#define DIGI_CMD_AND_UART_REGISTER		16	/* INB, OOB */
+#define DIGI_CMD_OR_UART_REGISTER		17	/* INB, OOB */
+#define DIGI_CMD_SEND_DATA			18	/* INB      */
+#define DIGI_CMD_RECEIVE_DATA			19	/* INB      */
+#define DIGI_CMD_RECEIVE_DISABLE		20	/* INB      */
+#define DIGI_CMD_GET_PORT_TYPE			21	/*      OOB */
+
+/* baud rates */
+#define DIGI_BAUD_50				0
+#define DIGI_BAUD_75				1
+#define DIGI_BAUD_110				2
+#define DIGI_BAUD_150				3
+#define DIGI_BAUD_200				4
+#define DIGI_BAUD_300				5
+#define DIGI_BAUD_600				6
+#define DIGI_BAUD_1200				7
+#define DIGI_BAUD_1800				8
+#define DIGI_BAUD_2400				9
+#define DIGI_BAUD_4800				10
+#define DIGI_BAUD_7200				11
+#define DIGI_BAUD_9600				12
+#define DIGI_BAUD_14400				13
+#define DIGI_BAUD_19200				14
+#define DIGI_BAUD_28800				15
+#define DIGI_BAUD_38400				16
+#define DIGI_BAUD_57600				17
+#define DIGI_BAUD_76800				18
+#define DIGI_BAUD_115200			19
+#define DIGI_BAUD_153600			20
+#define DIGI_BAUD_230400			21
+#define DIGI_BAUD_460800			22
+
+/* arguments */
+#define DIGI_WORD_SIZE_5			0
+#define DIGI_WORD_SIZE_6			1
+#define DIGI_WORD_SIZE_7			2
+#define DIGI_WORD_SIZE_8			3
+
+#define DIGI_PARITY_NONE			0
+#define DIGI_PARITY_ODD				1
+#define DIGI_PARITY_EVEN			2
+#define DIGI_PARITY_MARK			3
+#define DIGI_PARITY_SPACE			4
+
+#define DIGI_STOP_BITS_1			0
+#define DIGI_STOP_BITS_2			1
+
+#define DIGI_INPUT_FLOW_CONTROL_XON_XOFF	1
+#define DIGI_INPUT_FLOW_CONTROL_RTS		2
+#define DIGI_INPUT_FLOW_CONTROL_DTR		4
+
+#define DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF	1
+#define DIGI_OUTPUT_FLOW_CONTROL_CTS		2
+#define DIGI_OUTPUT_FLOW_CONTROL_DSR		4
+
+#define DIGI_DTR_INACTIVE			0
+#define DIGI_DTR_ACTIVE				1
+#define DIGI_DTR_INPUT_FLOW_CONTROL		2
+
+#define DIGI_RTS_INACTIVE			0
+#define DIGI_RTS_ACTIVE				1
+#define DIGI_RTS_INPUT_FLOW_CONTROL		2
+#define DIGI_RTS_TOGGLE				3
+
+#define DIGI_FLUSH_TX				1
+#define DIGI_FLUSH_RX				2
+#define DIGI_RESUME_TX				4 /* clears xoff condition */
+
+#define DIGI_TRANSMIT_NOT_IDLE			0
+#define DIGI_TRANSMIT_IDLE			1
+
+#define DIGI_DISABLE				0
+#define DIGI_ENABLE				1
+
+#define DIGI_DEASSERT				0
+#define DIGI_ASSERT				1
+
+/* in band status codes */
+#define DIGI_OVERRUN_ERROR			4
+#define DIGI_PARITY_ERROR			8
+#define DIGI_FRAMING_ERROR			16
+#define DIGI_BREAK_ERROR			32
+
+/* out of band status */
+#define DIGI_NO_ERROR				0
+#define DIGI_BAD_FIRST_PARAMETER		1
+#define DIGI_BAD_SECOND_PARAMETER		2
+#define DIGI_INVALID_LINE			3
+#define DIGI_INVALID_OPCODE			4
+
+/* input signals */
+#define DIGI_READ_INPUT_SIGNALS_SLOT		1
+#define DIGI_READ_INPUT_SIGNALS_ERR		2
+#define DIGI_READ_INPUT_SIGNALS_BUSY		4
+#define DIGI_READ_INPUT_SIGNALS_PE		8
+#define DIGI_READ_INPUT_SIGNALS_CTS		16
+#define DIGI_READ_INPUT_SIGNALS_DSR		32
+#define DIGI_READ_INPUT_SIGNALS_RI		64
+#define DIGI_READ_INPUT_SIGNALS_DCD		128
+
+
+/* macros */
+#define MAX(a,b)	(((a)>(b))?(a):(b))
+#define MIN(a,b)	(((a)<(b))?(a):(b))
+
+
+/* Structures */
+
+typedef struct digi_serial {
+	spinlock_t ds_serial_lock;
+	struct usb_serial_port *ds_oob_port;	/* out-of-band port */
+	int ds_oob_port_num;			/* index of out-of-band port */
+	int ds_device_started;
+} digi_serial_t;
+
+typedef struct digi_port {
+	spinlock_t dp_port_lock;
+	int dp_port_num;
+	int dp_out_buf_len;
+	unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];
+	int dp_in_buf_len;
+	unsigned char dp_in_buf[DIGI_IN_BUF_SIZE];
+	unsigned char dp_in_flag_buf[DIGI_IN_BUF_SIZE];
+	unsigned int dp_modem_signals;
+	wait_queue_head_t dp_modem_change_wait;
+	int dp_open_count;			/* inc on open, dec on close */
+	int dp_transmit_idle;
+	wait_queue_head_t dp_transmit_idle_wait;
+	int dp_throttled;
+	int dp_throttle_restart;
+	wait_queue_head_t dp_flush_wait;
+	int dp_in_close;			/* close in progress */
+	wait_queue_head_t dp_close_wait;	/* wait queue for close */
+	struct tq_struct dp_wakeup_task;
+} digi_port_t;
+
+
+/* Local Function Declarations */
+
+static void digi_wakeup_write( struct usb_serial_port *port );
+static void digi_wakeup_write_lock( struct usb_serial_port *port );
+static int digi_write_oob_command( struct usb_serial_port *port,
+	unsigned char *buf, int count, int interruptible );
+static int digi_write_inb_command( struct usb_serial_port *port,
+	unsigned char *buf, int count, unsigned long timeout );
+static int digi_set_modem_signals( struct usb_serial_port *port,
+	unsigned int modem_signals, int interruptible );
+static int digi_transmit_idle( struct usb_serial_port *port,
+	unsigned long timeout );
+static void digi_rx_throttle (struct usb_serial_port *port);
+static void digi_rx_unthrottle (struct usb_serial_port *port);
+static void digi_set_termios( struct usb_serial_port *port, 
+	struct termios *old_termios );
+static void digi_break_ctl( struct usb_serial_port *port, int break_state );
+static int digi_ioctl( struct usb_serial_port *port, struct file *file,
+	unsigned int cmd, unsigned long arg );
+static int digi_write( struct usb_serial_port *port, int from_user,
+	const unsigned char *buf, int count );
+static void digi_write_bulk_callback( struct urb *urb );
+static int digi_write_room( struct usb_serial_port *port );
+static int digi_chars_in_buffer( struct usb_serial_port *port );
+static int digi_open( struct usb_serial_port *port, struct file *filp );
+static void digi_close( struct usb_serial_port *port, struct file *filp );
+static int digi_startup_device( struct usb_serial *serial );
+static int digi_startup( struct usb_serial *serial );
+static void digi_shutdown( struct usb_serial *serial );
+static void digi_read_bulk_callback( struct urb *urb );
+static int digi_read_inb_callback( struct urb *urb );
+static int digi_read_oob_callback( struct urb *urb );
+
+
+/* Statics */
+
+/* device info needed for the Digi serial converter */
+static u16 digi_vendor_id = DIGI_VENDOR_ID;
+static u16 digi_product_2_id = DIGI_2_ID;	/* USB 2 */
+static u16 digi_product_4_id = DIGI_4_ID;	/* USB 4 */
+
+static struct usb_serial_device_type digi_acceleport_2_device = {
+	name:				"Digi USB",
+	idVendor:			&digi_vendor_id,
+	idProduct:			&digi_product_2_id,
+	needs_interrupt_in:		DONT_CARE,
+	needs_bulk_in:			MUST_HAVE,
+	needs_bulk_out:			MUST_HAVE,
+	num_interrupt_in:		0,
+	num_bulk_in:			4,
+	num_bulk_out:			4,
+	num_ports:			3,
+	open:				digi_open,
+	close:				digi_close,
+	write:				digi_write,
+	write_room:			digi_write_room,
+	write_bulk_callback: 		digi_write_bulk_callback,
+	read_bulk_callback:		digi_read_bulk_callback,
+	chars_in_buffer:		digi_chars_in_buffer,
+	throttle:			digi_rx_throttle,
+	unthrottle:			digi_rx_unthrottle,
+	ioctl:				digi_ioctl,
+	set_termios:			digi_set_termios,
+	break_ctl:			digi_break_ctl,
+	startup:			digi_startup,
+	shutdown:			digi_shutdown,
+};
+
+static struct usb_serial_device_type digi_acceleport_4_device = {
+	name:				"Digi USB",
+	idVendor:			&digi_vendor_id,
+	idProduct:			&digi_product_4_id,
+	needs_interrupt_in:		DONT_CARE,
+	needs_bulk_in:			MUST_HAVE,
+	needs_bulk_out:			MUST_HAVE,
+	num_interrupt_in:		0,
+	num_bulk_in:			5,
+	num_bulk_out:			5,
+	num_ports:			4,
+	open:				digi_open,
+	close:				digi_close,
+	write:				digi_write,
+	write_room:			digi_write_room,
+	write_bulk_callback: 		digi_write_bulk_callback,
+	read_bulk_callback:		digi_read_bulk_callback,
+	chars_in_buffer:		digi_chars_in_buffer,
+	throttle:			digi_rx_throttle,
+	unthrottle:			digi_rx_unthrottle,
+	ioctl:				digi_ioctl,
+	set_termios:			digi_set_termios,
+	break_ctl:			digi_break_ctl,
+	startup:			digi_startup,
+	shutdown:			digi_shutdown,
+};
+
+
+/* Functions */
+
+/*
+*  Cond Wait Interruptible Timeout Irqrestore
+*
+*  Do spin_unlock_irqrestore and interruptible_sleep_on_timeout
+*  so that wake ups are not lost if they occur between the unlock
+*  and the sleep.  In other words, spin_lock_irqrestore and
+*  interruptible_sleep_on_timeout are "atomic" with respect to
+*  wake ups.  This is used to implement condition variables.
+*/
+
+static inline long cond_wait_interruptible_timeout_irqrestore(
+	wait_queue_head_t *q, long timeout,
+	spinlock_t *lock, unsigned long flags )
+{
+
+	wait_queue_t wait;
+
+
+	init_waitqueue_entry( &wait, current );
+
+	set_current_state( TASK_INTERRUPTIBLE );
+
+	add_wait_queue( q, &wait );
+
+	spin_unlock_irqrestore( lock, flags );
+
+	timeout = schedule_timeout(timeout);
+
+	set_current_state( TASK_RUNNING );
+
+	remove_wait_queue( q, &wait );
+
+	return( timeout );
+
+}
+
+
+/*
+*  Digi Wakeup Write
+*
+*  Wake up port, line discipline, and tty processes sleeping
+*  on writes.
+*/
+
+static void digi_wakeup_write_lock( struct usb_serial_port *port )
+{
+
+	unsigned long flags;
+	digi_port_t *priv = (digi_port_t *)(port->private);
+
+
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	digi_wakeup_write( port );
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+}
+
+static void digi_wakeup_write( struct usb_serial_port *port )
+{
+
+	struct tty_struct *tty = port->tty;
+
+
+	/* wake up port processes */
+	wake_up_interruptible( &port->write_wait );
+
+	/* wake up line discipline */
+	if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+	&& tty->ldisc.write_wakeup )
+		(tty->ldisc.write_wakeup)(tty);
+
+	/* wake up other tty processes */
+	wake_up_interruptible( &tty->write_wait );
+	/* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
+
+}
+
+
+/*
+*  Digi Write OOB Command
+*
+*  Write commands on the out of band port.  Commands are 4
+*  bytes each, multiple commands can be sent at once, and
+*  no command will be split across USB packets.  Returns 0
+*  if successful, -EINTR if interrupted while sleeping and
+*  the interruptible flag is true, or a negative error
+*  returned by usb_submit_urb.
+*/
+
+static int digi_write_oob_command( struct usb_serial_port *port,
+	unsigned char *buf, int count, int interruptible )
+{
+
+	int ret = 0;
+	int len;
+	struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;
+	digi_port_t *oob_priv = (digi_port_t *)oob_port->private;
+	unsigned long flags = 0;
+
+
+dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count );
+
+	spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
+
+	while( count > 0 ) {
+
+		while( oob_port->write_urb->status == -EINPROGRESS ) {
+			cond_wait_interruptible_timeout_irqrestore(
+				&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
+				&oob_priv->dp_port_lock, flags );
+			if( interruptible && signal_pending(current) ) {
+				return( -EINTR );
+			}
+			spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
+		}
+
+		/* len must be a multiple of 4, so commands are not split */
+		len = MIN( count, oob_port->bulk_out_size );
+		if( len > 4 )
+			len &= ~3;
+
+		memcpy( oob_port->write_urb->transfer_buffer, buf, len );
+		oob_port->write_urb->transfer_buffer_length = len;
+
+		if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
+			count -= len;
+			buf += len;
+		}
+
+	}
+
+	spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
+
+	if( ret ) {
+		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d",
+			ret );
+	}
+
+	return( ret );
+
+}
+
+
+/*
+*  Digi Write In Band Command
+*
+*  Write commands on the given port.  Commands are 4
+*  bytes each, multiple commands can be sent at once, and
+*  no command will be split across USB packets.  If timeout
+*  is non-zero, write in band command will return after
+*  waiting unsuccessfully for the URB status to clear for
+*  timeout ticks.  Returns 0 if successful, or a negative
+*  error returned by digi_write.
+*/
+
+static int digi_write_inb_command( struct usb_serial_port *port,
+	unsigned char *buf, int count, unsigned long timeout )
+{
+
+	int ret = 0;
+	int len;
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	unsigned char *data = port->write_urb->transfer_buffer;
+	unsigned long flags = 0;
+
+
+dbg( "digi_write_inb_command: TOP: port=%d, count=%d", priv->dp_port_num,
+count );
+
+	if( timeout )
+		timeout += jiffies;
+	else
+		timeout = ULONG_MAX;
+
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+
+	while( count > 0 && ret == 0 ) {
+
+		while( port->write_urb->status == -EINPROGRESS
+		&& jiffies < timeout ) {
+			cond_wait_interruptible_timeout_irqrestore(
+				&port->write_wait, DIGI_RETRY_TIMEOUT,
+				&priv->dp_port_lock, flags );
+			if( signal_pending(current) ) {
+				return( -EINTR );
+			}
+			spin_lock_irqsave( &priv->dp_port_lock, flags );
+		}
+
+		/* len must be a multiple of 4 and small enough to */
+		/* guarantee the write will send buffered data first, */
+		/* so commands are in order with data and not split */
+		len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len );
+		if( len > 4 )
+			len &= ~3;
+
+		/* write any buffered data first */
+		if( priv->dp_out_buf_len > 0 ) {
+			data[0] = DIGI_CMD_SEND_DATA;
+			data[1] = priv->dp_out_buf_len;
+			memcpy( data+2, priv->dp_out_buf,
+				priv->dp_out_buf_len );
+			memcpy( data+2+priv->dp_out_buf_len, buf, len );
+			port->write_urb->transfer_buffer_length
+				= priv->dp_out_buf_len+2+len;
+		} else {
+			memcpy( data, buf, len );
+			port->write_urb->transfer_buffer_length = len;
+		}
+
+		if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+			priv->dp_out_buf_len = 0;
+			count -= len;
+			buf += len;
+		}
+
+	}
+
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+	if( ret ) {
+		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+		ret, priv->dp_port_num );
+	}
+
+	return( ret );
+
+}
+
+
+/*
+*  Digi Set Modem Signals
+*
+*  Sets or clears DTR and RTS on the port, according to the
+*  modem_signals argument.  Use TIOCM_DTR and TIOCM_RTS flags
+*  for the modem_signals argument.  Returns 0 if successful,
+*  -EINTR if interrupted while sleeping, or a non-zero error
+*  returned by usb_submit_urb.
+*/
+
+static int digi_set_modem_signals( struct usb_serial_port *port,
+	unsigned int modem_signals, int interruptible )
+{
+
+	int ret;
+	digi_port_t *port_priv = (digi_port_t *)port->private;
+	struct usb_serial_port *oob_port = (struct usb_serial_port *)((digi_serial_t *)port->serial->private)->ds_oob_port;
+	digi_port_t *oob_priv = (digi_port_t *)oob_port->private;
+	unsigned char *data = oob_port->write_urb->transfer_buffer;
+	unsigned long flags = 0;
+
+
+dbg( "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",
+port_priv->dp_port_num, modem_signals );
+
+	spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
+	spin_lock( &port_priv->dp_port_lock );
+
+	while( oob_port->write_urb->status == -EINPROGRESS ) {
+		spin_unlock( &port_priv->dp_port_lock );
+		cond_wait_interruptible_timeout_irqrestore(
+			&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
+			&oob_priv->dp_port_lock, flags );
+		if( interruptible && signal_pending(current) ) {
+			return( -EINTR );
+		}
+		spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
+		spin_lock( &port_priv->dp_port_lock );
+	}
+
+	data[0] = DIGI_CMD_SET_DTR_SIGNAL;
+	data[1] = port_priv->dp_port_num;
+	data[2] = (modem_signals&TIOCM_DTR) ?
+		DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE;
+	data[3] = 0;
+
+	data[4] = DIGI_CMD_SET_RTS_SIGNAL;
+	data[5] = port_priv->dp_port_num;
+	data[6] = (modem_signals&TIOCM_RTS) ?
+		DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE;
+	data[7] = 0;
+
+	oob_port->write_urb->transfer_buffer_length = 8;
+
+	if( (ret=usb_submit_urb(oob_port->write_urb)) == 0 ) {
+		port_priv->dp_modem_signals =
+			(port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))
+			| (modem_signals&(TIOCM_DTR|TIOCM_RTS));
+	}
+
+	spin_unlock( &port_priv->dp_port_lock );
+	spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
+
+	if( ret ) {
+		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d",
+		ret );
+	}
+
+	return( ret );
+
+}
+
+
+/*
+*  Digi Transmit Idle
+*
+*  Digi transmit idle waits, up to timeout ticks, for the transmitter
+*  to go idle.  It returns 0 if successful or a negative error.
+*
+*  There are race conditions here if more than one process is calling
+*  digi_transmit_idle on the same port at the same time.  However, this
+*  is only called from close, and only one process can be in close on a
+*  port at a time, so its ok.
+*/
+
+static int digi_transmit_idle( struct usb_serial_port *port,
+	unsigned long timeout )
+{
+
+	int ret;
+	unsigned char buf[2];
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	unsigned long flags = 0;
+
+
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	priv->dp_transmit_idle = 0;
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+	buf[0] = DIGI_CMD_TRANSMIT_IDLE;
+	buf[1] = 0;
+
+	timeout += jiffies;
+
+	if( (ret=digi_write_inb_command( port, buf, 2, timeout-jiffies )) != 0 )
+		return( ret );
+
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+
+	while( jiffies < timeout && !priv->dp_transmit_idle ) {
+		cond_wait_interruptible_timeout_irqrestore(
+			&priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT,
+			&priv->dp_port_lock, flags );
+		if( signal_pending(current) ) {
+			return( -EINTR );
+		}
+		spin_lock_irqsave( &priv->dp_port_lock, flags );
+	}
+
+	priv->dp_transmit_idle = 0;
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+	return( 0 );
+
+}
+
+
+static void digi_rx_throttle( struct usb_serial_port *port )
+{
+
+	unsigned long flags;
+	digi_port_t *priv = (digi_port_t *)(port->private);
+
+
+dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num );
+
+	/* stop receiving characters by not resubmitting the read urb */
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	priv->dp_throttled = 1;
+	priv->dp_throttle_restart = 0;
+	priv->dp_in_buf_len = 0;
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+}
+
+
+static void digi_rx_unthrottle( struct usb_serial_port *port )
+{
+
+	int ret = 0;
+	int len;
+	unsigned long flags;
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct tty_struct *tty = port->tty;
+
+
+dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num );
+
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+
+	/* send any buffered chars from throttle time on to tty subsystem */
+	len = MIN( priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count );
+	if( len > 0 ) {
+		memcpy( tty->flip.char_buf_ptr, priv->dp_in_buf, len );
+		memcpy( tty->flip.flag_buf_ptr, priv->dp_in_flag_buf, len );
+		tty->flip.char_buf_ptr += len;
+		tty->flip.flag_buf_ptr += len;
+		tty->flip.count += len;
+		tty_flip_buffer_push( tty );
+	}
+
+	/* restart read chain */
+	if( priv->dp_throttle_restart )
+		ret = usb_submit_urb( port->read_urb );
+
+	/* turn throttle off */
+	priv->dp_throttled = 0;
+	priv->dp_in_buf_len = 0;
+	priv->dp_throttle_restart = 0;
+
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+	if( ret ) {
+		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+			ret, priv->dp_port_num );
+	}
+
+}
+
+
+static void digi_set_termios( struct usb_serial_port *port, 
+	struct termios *old_termios )
+{
+
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	unsigned int iflag = port->tty->termios->c_iflag;
+	unsigned int cflag = port->tty->termios->c_cflag;
+	unsigned int old_iflag = old_termios->c_iflag;
+	unsigned int old_cflag = old_termios->c_cflag;
+	unsigned char buf[32];
+	unsigned int modem_signals;
+	int arg,ret;
+	int i = 0;
+
+
+dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag );
+
+	/* set baud rate */
+	if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
+
+		arg = -1;
+
+		/* reassert DTR and (maybe) RTS on transition from B0 */
+		if( (old_cflag&CBAUD) == B0 ) {
+			/* don't set RTS if using hardware flow control */
+			/* and throttling input */
+			modem_signals = TIOCM_DTR;
+			if( !(port->tty->termios->c_cflag & CRTSCTS) ||
+			!test_bit(TTY_THROTTLED, &port->tty->flags) ) {
+				modem_signals |= TIOCM_RTS;
+			}
+			digi_set_modem_signals( port, modem_signals, 1 );
+		}
+
+		switch( (cflag&CBAUD) ) {
+			/* drop DTR and RTS on transition to B0 */
+		case B0: digi_set_modem_signals( port, 0, 1 ); break;
+		case B50: arg = DIGI_BAUD_50; break;
+		case B75: arg = DIGI_BAUD_75; break;
+		case B110: arg = DIGI_BAUD_110; break;
+		case B150: arg = DIGI_BAUD_150; break;
+		case B200: arg = DIGI_BAUD_200; break;
+		case B300: arg = DIGI_BAUD_300; break;
+		case B600: arg = DIGI_BAUD_600; break;
+		case B1200: arg = DIGI_BAUD_1200; break;
+		case B1800: arg = DIGI_BAUD_1800; break;
+		case B2400: arg = DIGI_BAUD_2400; break;
+		case B4800: arg = DIGI_BAUD_4800; break;
+		case B9600: arg = DIGI_BAUD_9600; break;
+		case B19200: arg = DIGI_BAUD_19200; break;
+		case B38400: arg = DIGI_BAUD_38400; break;
+		case B57600: arg = DIGI_BAUD_57600; break;
+		case B115200: arg = DIGI_BAUD_115200; break;
+		case B230400: arg = DIGI_BAUD_230400; break;
+		case B460800: arg = DIGI_BAUD_460800; break;
+		default:
+			dbg( "digi_set_termios: can't handle baud rate 0x%x",
+				(cflag&CBAUD) );
+			break;
+		}
+
+		if( arg != -1 ) {
+			buf[i++] = DIGI_CMD_SET_BAUD_RATE;
+			buf[i++] = priv->dp_port_num;
+			buf[i++] = arg;
+			buf[i++] = 0;
+		}
+
+	}
+
+	/* set parity */
+	if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) {
+
+		if( (cflag&PARENB) ) {
+			if( (cflag&PARODD) )
+				arg = DIGI_PARITY_ODD;
+			else
+				arg = DIGI_PARITY_EVEN;
+		} else {
+			arg = DIGI_PARITY_NONE;
+		}
+
+		buf[i++] = DIGI_CMD_SET_PARITY;
+		buf[i++] = priv->dp_port_num;
+		buf[i++] = arg;
+		buf[i++] = 0;
+
+	}
+
+	/* set word size */
+	if( (cflag&CSIZE) != (old_cflag&CSIZE) ) {
+
+		arg = -1;
+
+		switch( (cflag&CSIZE) ) {
+		case CS5: arg = DIGI_WORD_SIZE_5; break;
+		case CS6: arg = DIGI_WORD_SIZE_6; break;
+		case CS7: arg = DIGI_WORD_SIZE_7; break;
+		case CS8: arg = DIGI_WORD_SIZE_8; break;
+		default:
+			dbg( "digi_set_termios: can't handle word size %d",
+				(cflag&CSIZE) );
+			break;
+		}
+
+		if( arg != -1 ) {
+			buf[i++] = DIGI_CMD_SET_WORD_SIZE;
+			buf[i++] = priv->dp_port_num;
+			buf[i++] = arg;
+			buf[i++] = 0;
+		}
+
+	}
+
+	/* set stop bits */
+	if( (cflag&CSTOPB) != (old_cflag&CSTOPB) ) {
+
+		if( (cflag&CSTOPB) )
+			arg = DIGI_STOP_BITS_2;
+		else
+			arg = DIGI_STOP_BITS_1;
+
+		buf[i++] = DIGI_CMD_SET_STOP_BITS;
+		buf[i++] = priv->dp_port_num;
+		buf[i++] = arg;
+		buf[i++] = 0;
+
+	}
+
+	/* set input flow control */
+	if( (iflag&IXOFF) != (old_iflag&IXOFF)
+	|| (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
+
+		arg = 0;
+
+		if( (iflag&IXOFF) )
+			arg |= DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
+		else
+			arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
+
+		if( (cflag&CRTSCTS) ) {
+
+			arg |= DIGI_INPUT_FLOW_CONTROL_RTS;
+
+			/* On USB-4 it is necessary to assert RTS prior */
+			/* to selecting RTS input flow control.  */
+			buf[i++] = DIGI_CMD_SET_RTS_SIGNAL;
+			buf[i++] = priv->dp_port_num;
+			buf[i++] = DIGI_RTS_ACTIVE;
+			buf[i++] = 0;
+
+		} else {
+			arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS;
+		}
+
+		buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
+		buf[i++] = priv->dp_port_num;
+		buf[i++] = arg;
+		buf[i++] = 0;
+
+	}
+
+	/* set output flow control */
+	if( (iflag&IXON) != (old_iflag&IXON)
+	|| (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
+
+		arg = 0;
+
+		if( (iflag&IXON) )
+			arg |= DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
+		else
+			arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
+
+		if( (cflag&CRTSCTS) ) {
+			arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS;
+		} else {
+			arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS;
+			port->tty->hw_stopped = 0;
+		}
+
+		buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
+		buf[i++] = priv->dp_port_num;
+		buf[i++] = arg;
+		buf[i++] = 0;
+
+	}
+
+	/* set receive enable/disable */
+	if( (cflag&CREAD) != (old_cflag&CREAD) ) {
+
+		if( (cflag&CREAD) )
+			arg = DIGI_ENABLE;
+		else
+			arg = DIGI_DISABLE;
+
+		buf[i++] = DIGI_CMD_RECEIVE_ENABLE;
+		buf[i++] = priv->dp_port_num;
+		buf[i++] = arg;
+		buf[i++] = 0;
+
+	}
+
+	if( (ret=digi_write_oob_command( port, buf, i, 1 )) != 0 )
+		dbg( "digi_set_termios: write oob failed, ret=%d", ret );
+
+}
+
+
+static void digi_break_ctl( struct usb_serial_port *port, int break_state )
+{
+
+	unsigned char buf[4];
+
+
+	buf[0] = DIGI_CMD_BREAK_CONTROL;
+	buf[1] = 2;				/* length */
+	buf[2] = break_state ? 1 : 0;
+	buf[3] = 0;				/* pad */
+
+	digi_write_inb_command( port, buf, 4, 0 );
+
+}
+
+
+static int digi_ioctl( struct usb_serial_port *port, struct file *file,
+	unsigned int cmd, unsigned long arg )
+{
+
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	unsigned int val;
+	unsigned long flags = 0;
+
+
+dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd );
+
+	switch (cmd) {
+
+	case TIOCMGET:
+		spin_lock_irqsave( &priv->dp_port_lock, flags );
+		val = priv->dp_modem_signals;
+		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+		if( copy_to_user((unsigned int *)arg, &val, sizeof(int)) )
+			return( -EFAULT );
+		return( 0 );
+
+	case TIOCMSET:
+	case TIOCMBIS:
+	case TIOCMBIC:
+		if( copy_from_user(&val, (unsigned int *)arg, sizeof(int)) )
+			return( -EFAULT );
+		spin_lock_irqsave( &priv->dp_port_lock, flags );
+		if( cmd == TIOCMBIS )
+			val = priv->dp_modem_signals | val;
+		else if( cmd == TIOCMBIC )
+			val = priv->dp_modem_signals & ~val;
+		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+		return( digi_set_modem_signals( port, val, 1 ) );
+
+	case TIOCMIWAIT:
+		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+		/* TODO */
+		return( 0 );
+
+	case TIOCGICOUNT:
+		/* return count of modemline transitions */
+		/* TODO */
+		return 0;
+
+	}
+
+	return( -ENOIOCTLCMD );
+
+}
+
+
+static int digi_write( struct usb_serial_port *port, int from_user,
+	const unsigned char *buf, int count )
+{
+
+	int ret,data_len,new_len;
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	unsigned char *data = port->write_urb->transfer_buffer;
+	unsigned char user_buf[64];	/* 64 bytes is max USB bulk packet */
+	unsigned long flags = 0;
+
+
+dbg( "digi_write: TOP: port=%d, count=%d, from_user=%d, in_interrupt=%d",
+priv->dp_port_num, count, from_user, in_interrupt() );
+
+	/* copy user data (which can sleep) before getting spin lock */
+	count = MIN( 64, MIN( count, port->bulk_out_size-2 ) );
+	if( from_user && copy_from_user( user_buf, buf, count ) ) {
+		return( -EFAULT );
+	}
+
+	/* be sure only one write proceeds at a time */
+	/* there are races on the port private buffer */
+	/* and races to check write_urb->status */
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+
+	/* wait for urb status clear to submit another urb */
+	if( port->write_urb->status == -EINPROGRESS ) {
+
+		/* buffer data if count is 1 (probably put_char) if possible */
+		if( count == 1 ) {
+			new_len = MIN( count,
+				DIGI_OUT_BUF_SIZE-priv->dp_out_buf_len );
+			memcpy( priv->dp_out_buf+priv->dp_out_buf_len, buf,
+				new_len );
+			priv->dp_out_buf_len += new_len;
+		} else {
+			new_len = 0;
+		}
+
+		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+		return( new_len );
+
+	}
+
+	/* allow space for any buffered data and for new data, up to */
+	/* transfer buffer size - 2 (for command and length bytes) */
+	new_len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len );
+	data_len = new_len + priv->dp_out_buf_len;
+
+	if( data_len == 0 ) {
+		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+		return( 0 );
+	}
+
+	port->write_urb->transfer_buffer_length = data_len+2;
+
+	*data++ = DIGI_CMD_SEND_DATA;
+	*data++ = data_len;
+
+	/* copy in buffered data first */
+	memcpy( data, priv->dp_out_buf, priv->dp_out_buf_len );
+	data += priv->dp_out_buf_len;
+
+	/* copy in new data */
+	memcpy( data, from_user ? user_buf : buf, new_len );
+
+	if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+		ret = new_len;
+		priv->dp_out_buf_len = 0;
+	}
+
+	/* return length of new data written, or error */
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+	if( ret < 0 ) {
+		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+			ret, priv->dp_port_num );
+	}
+
+dbg( "digi_write: returning %d", ret );
+	return( ret );
+
+} 
+
+
+static void digi_write_bulk_callback( struct urb *urb )
+{
+
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+	digi_port_t *priv;
+	int ret = 0;
+
+
+dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status );
+
+	/* port and serial sanity check */
+	if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) {
+		err( __FUNCTION__ ": port or port->private is NULL, status=%d",
+			urb->status );
+		return;
+	}
+	serial = port->serial;
+	if( serial == NULL || serial->private == NULL ) {
+		err( __FUNCTION__ ": serial or serial->private is NULL, status=%d", urb->status );
+		return;
+	}
+
+	/* handle oob callback */
+	if( priv->dp_port_num
+	== ((digi_serial_t *)(serial->private))->ds_oob_port_num ) {
+		dbg( "digi_write_bulk_callback: oob callback" );
+		spin_lock( &priv->dp_port_lock );
+		wake_up_interruptible( &port->write_wait );
+		spin_unlock( &priv->dp_port_lock );
+		return;
+	}
+
+	/* further sanity checks */
+	if( port_paranoia_check( port, __FUNCTION__ )
+	|| serial_paranoia_check( serial, __FUNCTION__ ) )
+		return;
+
+	/* try to send any buffered data on this port, if it is open */
+	spin_lock( &priv->dp_port_lock );
+	if( priv->dp_open_count && port->write_urb->status != -EINPROGRESS
+	&& priv->dp_out_buf_len > 0 ) {
+
+		*((unsigned char *)(port->write_urb->transfer_buffer))
+			= (unsigned char)DIGI_CMD_SEND_DATA;
+		*((unsigned char *)(port->write_urb->transfer_buffer)+1)
+			= (unsigned char)priv->dp_out_buf_len;
+
+		port->write_urb->transfer_buffer_length
+			= priv->dp_out_buf_len+2;
+
+		memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf,
+			priv->dp_out_buf_len );
+
+		if( (ret=usb_submit_urb(port->write_urb)) == 0 ) {
+			priv->dp_out_buf_len = 0;
+		}
+
+	}
+
+	/* wake up processes sleeping on writes immediately */
+	digi_wakeup_write( port );
+
+	/* also queue up a wakeup at scheduler time, in case we */
+	/* lost the race in write_chan(). */
+	queue_task( &priv->dp_wakeup_task, &tq_scheduler );
+
+	spin_unlock( &priv->dp_port_lock );
+
+	if( ret ) {
+		err( __FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+			ret, priv->dp_port_num );
+	}
+
+}
+
+
+static int digi_write_room( struct usb_serial_port *port )
+{
+
+	int room;
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	unsigned long flags = 0;
+
+
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+
+	if( port->write_urb->status == -EINPROGRESS )
+		room = 0;
+	else
+		room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
+
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+dbg( "digi_write_room: port=%d, room=%d", priv->dp_port_num, room );
+	return( room );
+
+}
+
+
+static int digi_chars_in_buffer( struct usb_serial_port *port )
+{
+
+	digi_port_t *priv = (digi_port_t *)(port->private);
+
+
+	if( port->write_urb->status == -EINPROGRESS ) {
+dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 );
+		/* return( port->bulk_out_size - 2 ); */
+		return( 256 );
+	} else {
+dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_out_buf_len );
+		return( priv->dp_out_buf_len );
+	}
+
+}
+
+
+static int digi_open( struct usb_serial_port *port, struct file *filp )
+{
+
+	int ret;
+	unsigned char buf[32];
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	struct termios not_termios;
+	unsigned long flags = 0;
+
+
+dbg( "digi_open: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, port->active, priv->dp_open_count );
+
+	/* be sure the device is started up */
+	if( digi_startup_device( port->serial ) != 0 )
+		return( -ENXIO );
+
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+
+	/* don't wait on a close in progress for non-blocking opens */
+	if( priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
+		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+		return( -EAGAIN );
+	}
+
+	/* inc module use count before sleeping to wait for closes */
+	++priv->dp_open_count;
+	MOD_INC_USE_COUNT;
+
+	/* wait for a close in progress to finish */
+	while( priv->dp_in_close ) {
+		cond_wait_interruptible_timeout_irqrestore(
+			&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
+			&priv->dp_port_lock, flags );
+		if( signal_pending(current) ) {
+			--priv->dp_open_count;
+			MOD_DEC_USE_COUNT;
+			return( -EINTR );
+		}
+		spin_lock_irqsave( &priv->dp_port_lock, flags );
+	}
+
+	/* if port is already open, just return */
+	/* be sure exactly one open proceeds */
+	if( port->active ) {
+		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+		return( 0 );
+	}
+
+	/* first open, mark port as active */
+	port->active = 1;
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+ 
+	/* read modem signals automatically whenever they change */
+	buf[0] = DIGI_CMD_READ_INPUT_SIGNALS;
+	buf[1] = priv->dp_port_num;
+	buf[2] = DIGI_ENABLE;
+	buf[3] = 0;
+
+	/* flush fifos */
+	buf[4] = DIGI_CMD_IFLUSH_FIFO;
+	buf[5] = priv->dp_port_num;
+	buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+	buf[7] = 0;
+
+	if( (ret=digi_write_oob_command( port, buf, 8, 1 )) != 0 )
+		dbg( "digi_open: write oob failed, ret=%d", ret );
+
+	/* set termios settings */
+	not_termios.c_cflag = ~port->tty->termios->c_cflag;
+	not_termios.c_iflag = ~port->tty->termios->c_iflag;
+	digi_set_termios( port, &not_termios );
+
+	/* set DTR and RTS */
+	digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS, 1 );
+
+	return( 0 );
+
+}
+
+
+static void digi_close( struct usb_serial_port *port, struct file *filp )
+{
+
+	int ret;
+	unsigned char buf[32];
+	struct tty_struct *tty = port->tty;
+	digi_port_t *priv = (digi_port_t *)port->private;
+	unsigned long flags = 0;
+
+
+dbg( "digi_close: TOP: port=%d, active=%d, open_count=%d", priv->dp_port_num, port->active, priv->dp_open_count );
+
+
+	/* do cleanup only after final close on this port */
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	if( priv->dp_open_count > 1 ) {
+		--priv->dp_open_count;
+		MOD_DEC_USE_COUNT;
+		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+		return;
+	} else if( priv->dp_open_count <= 0 ) {
+		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+		return;
+	}
+	priv->dp_in_close = 1;
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+	/* tell line discipline to process only XON/XOFF */
+        tty->closing = 1;
+
+	/* wait for output to drain */
+	if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
+		tty_wait_until_sent( tty, DIGI_CLOSE_TIMEOUT );
+	}
+
+	/* flush driver and line discipline buffers */
+	if( tty->driver.flush_buffer )
+		tty->driver.flush_buffer( tty );
+	if( tty->ldisc.flush_buffer )
+		tty->ldisc.flush_buffer( tty );
+
+	/* wait for transmit idle */
+	if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
+		digi_transmit_idle( port, DIGI_CLOSE_TIMEOUT );
+	}
+
+	/* drop DTR and RTS */
+	digi_set_modem_signals( port, 0, 0 );
+
+	/* disable input flow control */
+	buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
+	buf[1] = priv->dp_port_num;
+	buf[2] = DIGI_DISABLE;
+	buf[3] = 0;
+
+	/* disable output flow control */
+	buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
+	buf[5] = priv->dp_port_num;
+	buf[6] = DIGI_DISABLE;
+	buf[7] = 0;
+
+	/* disable reading modem signals automatically */
+	buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;
+	buf[9] = priv->dp_port_num;
+	buf[10] = DIGI_DISABLE;
+	buf[11] = 0;
+
+	/* disable receive */
+	buf[12] = DIGI_CMD_RECEIVE_ENABLE;
+	buf[13] = priv->dp_port_num;
+	buf[14] = DIGI_DISABLE;
+	buf[15] = 0;
+
+	/* flush fifos */
+	buf[16] = DIGI_CMD_IFLUSH_FIFO;
+	buf[17] = priv->dp_port_num;
+	buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+	buf[19] = 0;
+
+	if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 )
+		dbg( "digi_close: write oob failed, ret=%d", ret );
+
+	/* wait for final commands on oob port to complete */
+	interruptible_sleep_on_timeout( &priv->dp_flush_wait,
+		DIGI_CLOSE_TIMEOUT );
+
+	/* shutdown any outstanding bulk writes */
+	usb_unlink_urb (port->write_urb);
+
+	tty->closing = 0;
+
+	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	port->active = 0;
+	priv->dp_in_close = 0;
+	--priv->dp_open_count;
+	MOD_DEC_USE_COUNT;
+	wake_up_interruptible( &priv->dp_close_wait );
+	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+
+dbg( "digi_close: done" );
+}
+
+
+/*
+*  Digi Startup Device
+*
+*  Starts reads on all ports.  Must be called AFTER startup, with
+*  urbs initialized.  Returns 0 if successful, non-zero error otherwise.
+*/
+
+static int digi_startup_device( struct usb_serial *serial )
+{
+
+	int i,ret = 0;
+	digi_serial_t *serial_priv = (digi_serial_t *)serial->private;
+	struct usb_serial_port *port;
+
+
+	/* be sure this happens exactly once */
+	spin_lock( &serial_priv->ds_serial_lock );
+	if( serial_priv->ds_device_started ) {
+		spin_unlock( &serial_priv->ds_serial_lock );
+		return( 0 );
+	}
+	serial_priv->ds_device_started = 1;
+	spin_unlock( &serial_priv->ds_serial_lock );
+
+	/* start reading from each bulk in endpoint for the device */
+	/* set USB_DISABLE_SPD flag for write bulk urbs */
+	for( i=0; i<serial->type->num_ports+1; i++ ) {
+
+		port = &serial->port[i];
+
+		port->write_urb->transfer_flags |= USB_DISABLE_SPD;
+
+		if( (ret=usb_submit_urb(port->read_urb)) != 0 ) {
+			err(
+			__FUNCTION__ ": usb_submit_urb failed, ret=%d, port=%d",
+			ret, i );
+			break;
+		}
+
+	}
+
+	return( ret );
+
+}
+
+
+static int digi_startup( struct usb_serial *serial )
+{
+
+	int i;
+	digi_port_t *priv;
+	digi_serial_t *serial_priv;
+
+
+dbg( "digi_startup: TOP" );
+
+	/* allocate the private data structures for all ports */
+	/* number of regular ports + 1 for the out-of-band port */
+	for( i=0; i<serial->type->num_ports+1; i++ ) {
+
+		serial->port[i].active = 0;
+
+		/* allocate port private structure */
+		priv = serial->port[i].private =
+			(digi_port_t *)kmalloc( sizeof(digi_port_t),
+			GFP_KERNEL );
+		if( priv == (digi_port_t *)0 ) {
+			while( --i >= 0 )
+				kfree( serial->port[i].private );
+			return( 1 );			/* error */
+		}
+
+		/* initialize port private structure */
+		spin_lock_init( &priv->dp_port_lock );
+		priv->dp_port_num = i;
+		priv->dp_out_buf_len = 0;
+		priv->dp_in_buf_len = 0;
+		priv->dp_modem_signals = 0;
+		init_waitqueue_head( &priv->dp_modem_change_wait );
+		priv->dp_open_count = 0;
+		priv->dp_transmit_idle = 0;
+		init_waitqueue_head( &priv->dp_transmit_idle_wait );
+		priv->dp_throttled = 0;
+		priv->dp_throttle_restart = 0;
+		init_waitqueue_head( &priv->dp_flush_wait );
+		priv->dp_in_close = 0;
+		init_waitqueue_head( &priv->dp_close_wait );
+		priv->dp_wakeup_task.next = NULL;
+		priv->dp_wakeup_task.sync = 0;
+		priv->dp_wakeup_task.routine = (void *)digi_wakeup_write_lock;
+		priv->dp_wakeup_task.data = (void *)(&serial->port[i]);
+
+		/* initialize write wait queue for this port */
+		init_waitqueue_head( &serial->port[i].write_wait );
+
+	}
+
+	/* allocate serial private structure */
+	serial_priv = serial->private =
+		(digi_serial_t *)kmalloc( sizeof(digi_serial_t),
+		GFP_KERNEL );
+	if( serial_priv == (digi_serial_t *)0 ) {
+		for( i=0; i<serial->type->num_ports+1; i++ )
+			kfree( serial->port[i].private );
+		return( 1 );			/* error */
+	}
+
+	/* initialize serial private structure */
+	spin_lock_init( &serial_priv->ds_serial_lock );
+	serial_priv->ds_oob_port_num = serial->type->num_ports;
+	serial_priv->ds_oob_port = &serial->port[serial_priv->ds_oob_port_num];
+	serial_priv->ds_device_started = 0;
+
+	return( 0 );
+
+}
+
+
+static void digi_shutdown( struct usb_serial *serial )
+{
+
+	int i;
+	digi_port_t *priv;
+	unsigned long flags;
+
+
+dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() );
+
+	/* stop reads and writes on all ports */
+	for( i=0; i<serial->type->num_ports+1; i++ ) {
+		usb_unlink_urb( serial->port[i].read_urb );
+		usb_unlink_urb( serial->port[i].write_urb );
+	}
+
+	/* dec module use count */
+	for( i=0; i<serial->type->num_ports; i++ ) {
+		priv = serial->port[i].private;
+		spin_lock_irqsave( &priv->dp_port_lock, flags );
+		while( priv->dp_open_count > 0 ) {
+			MOD_DEC_USE_COUNT;
+			--priv->dp_open_count;
+		}
+		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+	}
+
+	/* free the private data structures for all ports */
+	/* number of regular ports + 1 for the out-of-band port */
+	for( i=0; i<serial->type->num_ports+1; i++ )
+		kfree( serial->port[i].private );
+	kfree( serial->private );
+
+}
+
+
+static void digi_read_bulk_callback( struct urb *urb )
+{
+
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	digi_port_t *priv;
+	int ret;
+
+
+dbg( "digi_read_bulk_callback: TOP" );
+
+	/* port sanity check, do not resubmit if port is not valid */
+	if( port == NULL || (priv=(digi_port_t *)(port->private)) == NULL ) {
+		err( __FUNCTION__ ": port or port->private is NULL, status=%d",
+			urb->status );
+		return;
+	}
+	if( port->serial == NULL
+	|| serial_paranoia_check( port->serial, __FUNCTION__ )
+	|| port->serial->private == NULL ) {
+		err( __FUNCTION__ ": serial is bad or serial->private is NULL, status=%d", urb->status );
+		return;
+	}
+
+	/* do not resubmit urb if it has any status error */
+	if( urb->status ) {
+		err( __FUNCTION__ ": nonzero read bulk status: status=%d, port=%d", urb->status, priv->dp_port_num );
+		return;
+	}
+
+	/* handle oob or inb callback, do not resubmit if error */
+	if( priv->dp_port_num
+	== ((digi_serial_t *)(port->serial->private))->ds_oob_port_num ) {
+		if( digi_read_oob_callback( urb ) != 0 )
+			return;
+	} else {
+		if( digi_read_inb_callback( urb ) != 0 )
+			return;
+	}
+
+	/* continue read */
+	if( (ret=usb_submit_urb(urb)) != 0 ) {
+		err( __FUNCTION__ ": failed resubmitting urb, ret=%d, port=%d",
+			ret, priv->dp_port_num );
+	}
+
+}
+
+
+/* 
+*  Digi Read INB Callback
+*
+*  Digi Read INB Callback handles reads on the in band ports, sending
+*  the data on to the tty subsystem.  When called we know port and
+*  port->private are not NULL and port->serial has been validated.
+*  It returns 0 if successful, 1 if successful but the port is
+*  throttled, and -1 if the sanity checks failed.
+*/
+
+static int digi_read_inb_callback( struct urb *urb )
+{
+
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct tty_struct *tty = port->tty;
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	int opcode = ((unsigned char *)urb->transfer_buffer)[0];
+	int len = ((unsigned char *)urb->transfer_buffer)[1];
+	int status = ((unsigned char *)urb->transfer_buffer)[2];
+	unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3;
+	int flag,throttled;
+
+
+	/* sanity check */
+	if( port_paranoia_check( port, __FUNCTION__ ) )
+		return( -1 );
+
+	/* do not process callbacks on closed ports */
+	/* but do continue the read chain */
+	if( priv->dp_open_count == 0 )
+		return( 0 );
+
+	/* short/multiple packet check */
+	if( urb->actual_length != len + 2 ) {
+     		err( __FUNCTION__ ": INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, port=%d, opcode=%d, len=%d, actual_length=%d, status=%d", urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status );
+		return( -1 );
+	}
+
+	spin_lock( &priv->dp_port_lock );
+
+	/* check for throttle; if set, do not resubmit read urb */
+	/* indicate the read chain needs to be restarted on unthrottle */
+	throttled = priv->dp_throttled;
+	if( throttled )
+		priv->dp_throttle_restart = 1;
+
+	/* receive data */
+	if( opcode == DIGI_CMD_RECEIVE_DATA ) {
+
+		/* get flag from status */
+		flag = 0;
+
+		/* overrun is special, not associated with a char */
+		if( status & DIGI_OVERRUN_ERROR ) {
+			tty_insert_flip_char( tty, 0, TTY_OVERRUN );
+		}
+
+		/* break takes precedence over parity, */
+		/* which takes precedence over framing errors */
+		if( status & DIGI_BREAK_ERROR ) {
+			flag = TTY_BREAK;
+		} else if( status & DIGI_PARITY_ERROR ) {
+			flag = TTY_PARITY;
+		} else if( status & DIGI_FRAMING_ERROR ) {
+			flag = TTY_FRAME;
+		}
+
+		/* data length is len-1 (one byte of len is status) */
+		--len;
+
+		if( throttled ) {
+
+			len = MIN( len,
+				DIGI_IN_BUF_SIZE - priv->dp_in_buf_len );
+
+			if( len > 0 ) {
+				memcpy( priv->dp_in_buf + priv->dp_in_buf_len,
+					data, len );
+				memset( priv->dp_in_flag_buf
+					+ priv->dp_in_buf_len, flag, len );
+				priv->dp_in_buf_len += len;
+			}
+
+		} else {
+
+			len = MIN( len, TTY_FLIPBUF_SIZE - tty->flip.count );
+
+			if( len > 0 ) {
+				memcpy( tty->flip.char_buf_ptr, data, len );
+				memset( tty->flip.flag_buf_ptr, flag, len );
+				tty->flip.char_buf_ptr += len;
+				tty->flip.flag_buf_ptr += len;
+				tty->flip.count += len;
+				tty_flip_buffer_push( tty );
+			}
+
+		}
+
+	}
+
+	spin_unlock( &priv->dp_port_lock );
+
+	if( opcode == DIGI_CMD_RECEIVE_DISABLE ) {
+		dbg( __FUNCTION__ ": got RECEIVE_DISABLE" );
+	} else if( opcode != DIGI_CMD_RECEIVE_DATA ) {
+		dbg( __FUNCTION__ ": unknown opcode: %d", opcode );
+	}
+
+	return( throttled ? 1 : 0 );
+
+}
+
+
+/* 
+*  Digi Read OOB Callback
+*
+*  Digi Read OOB Callback handles reads on the out of band port.
+*  When called we know port and port->private are not NULL and
+*  the port->serial is valid.  It returns 0 if successful, and
+*  -1 if the sanity checks failed.
+*/
+
+static int digi_read_oob_callback( struct urb *urb )
+{
+
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = port->serial;
+	digi_port_t *priv = (digi_port_t *)(port->private);
+	int opcode, line, status, val;
+	int i;
+
+
+dbg( "digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num,
+urb->actual_length );
+
+	/* handle each oob command */
+	for( i=0; i<urb->actual_length-3; ) {
+
+		opcode = ((unsigned char *)urb->transfer_buffer)[i++];
+		line = ((unsigned char *)urb->transfer_buffer)[i++];
+		status = ((unsigned char *)urb->transfer_buffer)[i++];
+		val = ((unsigned char *)urb->transfer_buffer)[i++];
+
+dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",
+opcode, line, status, val );
+
+		if( status != 0 || line >= serial->type->num_ports )
+			continue;
+
+		port = &serial->port[line];
+
+		if( port_paranoia_check( port, __FUNCTION__ )
+		|| (priv=port->private) == NULL )
+			return( -1 );
+
+		if( opcode == DIGI_CMD_READ_INPUT_SIGNALS ) {
+
+			spin_lock( &priv->dp_port_lock );
+
+			/* convert from digi flags to termiox flags */
+			if( val & DIGI_READ_INPUT_SIGNALS_CTS ) {
+				priv->dp_modem_signals |= TIOCM_CTS;
+				/* port must be open to use tty struct */
+				if( priv->dp_open_count
+				&& port->tty->termios->c_cflag & CRTSCTS ) {
+					port->tty->hw_stopped = 0;
+					digi_wakeup_write( port );
+				}
+			} else {
+				priv->dp_modem_signals &= ~TIOCM_CTS;
+				/* port must be open to use tty struct */
+				if( priv->dp_open_count
+				&& port->tty->termios->c_cflag & CRTSCTS ) {
+					port->tty->hw_stopped = 1;
+				}
+			}
+			if( val & DIGI_READ_INPUT_SIGNALS_DSR )
+				priv->dp_modem_signals |= TIOCM_DSR;
+			else
+				priv->dp_modem_signals &= ~TIOCM_DSR;
+			if( val & DIGI_READ_INPUT_SIGNALS_RI )
+				priv->dp_modem_signals |= TIOCM_RI;
+			else
+				priv->dp_modem_signals &= ~TIOCM_RI;
+			if( val & DIGI_READ_INPUT_SIGNALS_DCD )
+				priv->dp_modem_signals |= TIOCM_CD;
+			else
+				priv->dp_modem_signals &= ~TIOCM_CD;
+
+			wake_up_interruptible( &priv->dp_modem_change_wait );
+			spin_unlock( &priv->dp_port_lock );
+
+		} else if( opcode == DIGI_CMD_TRANSMIT_IDLE ) {
+
+			spin_lock( &priv->dp_port_lock );
+			priv->dp_transmit_idle = 1;
+			wake_up_interruptible( &priv->dp_transmit_idle_wait );
+			spin_unlock( &priv->dp_port_lock );
+
+		} else if( opcode == DIGI_CMD_IFLUSH_FIFO ) {
+
+			wake_up_interruptible( &priv->dp_flush_wait );
+
+		}
+
+	}
+
+	return( 0 );
+
+}
+
+
+int digi_init (void)
+{
+	usb_serial_register (&digi_acceleport_2_device);
+	usb_serial_register (&digi_acceleport_4_device);
+	return 0;
+}
+
+
+void digi_exit (void)
+{
+	usb_serial_deregister (&digi_acceleport_2_device);
+	usb_serial_deregister (&digi_acceleport_4_device);
+}
+
+
+module_init(digi_init);
+module_exit(digi_exit);
+
+
+MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>");
+MODULE_DESCRIPTION("Digi AccelePort USB-4 Serial Converter driver");
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/ezusb_convert.pl linux.18p8/drivers/usb/serial/ezusb_convert.pl
--- linux.vanilla/drivers/usb/serial/ezusb_convert.pl	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/ezusb_convert.pl	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,50 @@
+#! /usr/bin/perl -w
+
+
+# convert an Intel HEX file into a set of C records usable by the firmware
+# loading code in usb-serial.c (or others)
+
+# accepts the .hex file(s) on stdin, a basename (to name the initialized
+# array) as an argument, and prints the .h file to stdout. Typical usage:
+#  perl ezusb_convert.pl foo <foo.hex >fw_foo.h
+
+
+my $basename = $ARGV[0];
+die "no base name specified" unless $basename;
+
+while (<STDIN>) {
+    # ':' <len> <addr> <type> <len-data> <crc> '\r'
+    #  len, type, crc are 2-char hex, addr is 4-char hex. type is 00 for
+    # normal records, 01 for EOF
+    my($lenstring, $addrstring, $typestring, $reststring, $doscrap) =
+      /^:(\w\w)(\w\w\w\w)(\w\w)(\w+)(\r?)$/;
+    die "malformed line: $_" unless $reststring;
+    last if $typestring eq '01';
+    my($len) = hex($lenstring);
+    my($addr) = hex($addrstring);
+    my(@bytes) = unpack("C*", pack("H".(2*$len), $reststring));
+    #pop(@bytes); # last byte is a CRC
+    push(@records, [$addr, \@bytes]);
+}
+
+@sorted_records = sort { $a->[0] <=> $b->[0] } @records;
+
+print <<"EOF";
+/*
+ * ${basename}_fw.h
+ *
+ * Generated from ${basename}.s by ezusb_convert.pl
+ * This file is presumed to be under the same copyright as the source file
+ * from which it was derived.
+ */
+
+EOF
+
+print "static const struct ezusb_hex_record ${basename}_firmware[] = {\n";
+foreach $r (@sorted_records) {
+    printf("{ 0x%04x,\t%d,\t{", $r->[0], scalar(@{$r->[1]}));
+    print join(", ", map {sprintf('0x%02x', $_);} @{$r->[1]});
+    print "} },\n";
+}
+print "{ 0xffff,\t0,\t{0x00} }\n";
+print "};\n";
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/ftdi_sio.c linux.18p8/drivers/usb/serial/ftdi_sio.c
--- linux.vanilla/drivers/usb/serial/ftdi_sio.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/ftdi_sio.c	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,745 @@
+/*
+ * USB FTDI SIO driver
+ *
+ * 	Copyright (C) 1999, 2000
+ * 	    Greg Kroah-Hartman (greg@kroah.com)
+ *          Bill Ryder (bryder@sgi.com)
+ *
+ * 	This program is free software; you can redistribute it and/or modify
+ * 	it under the terms of the GNU General Public License as published by
+ * 	the Free Software Foundation; either version 2 of the License, or
+ * 	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (07/19/2000) gkh
+ *	Added module_init and module_exit functions to handle the fact that this
+ *	driver is a loadable module now.
+ *
+ * (04/04/2000) Bill Ryder 
+ *         Fixed bugs in TCGET/TCSET ioctls (by removing them - they are 
+ *             handled elsewhere in the serial driver chain).
+ *
+ * (03/30/2000) Bill Ryder 
+ *         Implemented lots of ioctls
+ * 	Fixed a race condition in write
+ * 	Changed some dbg's to errs
+ *
+ * (03/26/2000) gkh
+ * 	Split driver up into device specific pieces.
+ *
+ */
+
+/* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
+/* Thanx to FTDI for so kindly providing details of the protocol required */
+/*   to talk to the device */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "ftdi_sio.h"
+
+#define FTDI_VENDOR_ID			0x0403
+#define FTDI_SIO_SERIAL_CONVERTER_ID	0x8372
+
+/* function prototypes for a FTDI serial converter */
+static int  ftdi_sio_startup		(struct usb_serial *serial);
+static int  ftdi_sio_open		(struct usb_serial_port *port, struct file *filp);
+static void ftdi_sio_close		(struct usb_serial_port *port, struct file *filp);
+static int  ftdi_sio_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static void ftdi_sio_write_bulk_callback (struct urb *urb);
+static void ftdi_sio_read_bulk_callback	(struct urb *urb);
+static void ftdi_sio_set_termios	(struct usb_serial_port *port, struct termios * old);
+static int  ftdi_sio_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+
+/* All of the device info needed for the FTDI SIO serial converter */
+static __u16	ftdi_vendor_id		= FTDI_VENDOR_ID;
+static __u16	ftdi_sio_product_id	= FTDI_SIO_SERIAL_CONVERTER_ID;
+struct usb_serial_device_type ftdi_sio_device = {
+	name:			"FTDI SIO",
+	idVendor:		&ftdi_vendor_id,	/* the FTDI vendor ID */
+	idProduct:		&ftdi_sio_product_id,	/* the FTDI SIO product id */
+	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
+	num_interrupt_in:	0,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			ftdi_sio_open,
+	close:			ftdi_sio_close,
+	write:			ftdi_sio_write,
+	read_bulk_callback:	ftdi_sio_read_bulk_callback,
+	write_bulk_callback:	ftdi_sio_write_bulk_callback,
+	ioctl:			ftdi_sio_ioctl,
+	set_termios:		ftdi_sio_set_termios,
+	startup:		ftdi_sio_startup,
+};
+
+
+/*
+ * ***************************************************************************
+ * FTDI SIO Serial Converter specific driver functions
+ * ***************************************************************************
+ *
+ * Bill Ryder bryder@sgi.com of Silicon Graphics, Inc. did the FTDI_SIO code
+ * Thanx to FTDI for so kindly providing details of the protocol required
+ *   to talk to the device - http://www.ftdi.co.uk
+ *
+ * Tested as at this version - other stuff might work
+ * 23 March 2000
+ *     Works:
+ *      Baudrates - 9600, 38400,19200, 57600, 115200  
+ *      TIOCMBIC - TIOCM_DTR / TIOCM_RTS 
+ *      TIOCMBIS - TIOCM_DTR / TIOCM_RTS 
+ *      TIOCMSET - DTR on/RTSon  / DTR off, RTS off 
+ *      no parity:CS8 even parity:CS7 odd parity:CS7 
+ *      CRTSCTS flow control 
+ *     
+ *      Pilot-xfer zillions of times
+ *  
+ *      cu works with dir option 
+ *
+ *   Not Tested (ie might not work): 
+ *      xon/xoff flow control 
+ *      ppp (modem handling in general) 
+ *
+ *   KNOWN BUGS:
+ *    Multiple Opens
+ *    ==============
+ *      Seems to have problem when opening an already open port, 
+ *      Get I/O error on first attempt, then it lets you in. 
+ *      Need to do proper usage counting - keep registered callbacks for first opener.
+ *     
+ *     Reproduce with: 
+ *       cu -l /dev/ttyUSB0 dir 
+ *       whilst cu is running do:
+ *        stty -a < /dev/ttyUSB0  
+ *
+ *     from stty get: 'bash: /dev/ttyUSB0: Invalid argument ' 
+ *     from cu get 
+ *        write: Invalid argument 
+ *    
+ *    Initialisation Problem
+ *    ======================
+ *    Pilot transfer required me to run the serial_loopback program before it would work.
+ *    Still working on this. See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio
+ *
+ */
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int ftdi_sio_startup (struct usb_serial *serial)
+{
+	init_waitqueue_head(&serial->port[0].write_wait);
+	
+	return (0);
+}
+
+static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_sio_open */
+	struct termios tmp_termios;
+	struct usb_serial *serial = port->serial;
+	char buf[1]; /* Needed for the usb_control_msg I think */
+
+	dbg("ftdi_sio_open port %d", port->number);
+
+        /* FIXME - multiple concurrent opens cause trouble */
+	if (port->active) {
+		err ("port already open");
+		return -EINVAL;
+	}
+	port->active = 1; /* FIXME - For multiple open this should increment */
+
+	/* See ftdi_sio.h for description of what is reset */
+	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
+			FTDI_SIO_RESET_SIO, 
+			0, buf, 0, WDR_TIMEOUT);
+
+	/* Setup termios */
+	port->tty->termios->c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+	
+	ftdi_sio_set_termios(port, &tmp_termios);	
+
+	/* Disable flow control */
+	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+			    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+			    0, 0, 
+			    buf, 0, WDR_TIMEOUT) < 0) {
+		err("error from flowcontrol urb");
+		return(-EINVAL);
+	}	    
+
+	/* Turn on RTS and DTR since we are not flow controlling*/
+	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+			    (unsigned)FTDI_SIO_SET_DTR_HIGH, 0, 
+			    buf, 0, WDR_TIMEOUT) < 0) {
+		err("Error from DTR HIGH urb");
+	}
+	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+			    (unsigned)FTDI_SIO_SET_RTS_HIGH, 0, 
+			    buf, 0, WDR_TIMEOUT) < 0) {
+		err("Error from RTS HIGH urb");
+	}
+	
+	/*Start reading from the device*/
+	if (usb_submit_urb(port->read_urb))
+		err("usb_submit_urb(read bulk) failed");
+
+	return (0);
+} /* ftdi_sio_open */
+
+
+static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
+{ /* ftdi_sio_close */
+	struct usb_serial *serial = port->serial;
+	unsigned int c_cflag = port->tty->termios->c_cflag;
+	char buf[1];
+
+	dbg("ftdi_sio_close port %d", port->number);
+	
+	if (c_cflag & HUPCL){
+		/* Disable flow control */
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+				    0, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("error from flowcontrol urb");
+		}	    
+
+		/* drop DTR */
+ 		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    (unsigned)FTDI_SIO_SET_DTR_LOW, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("Error from DTR LOW urb");
+		}
+		/* drop RTS */
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    (unsigned)FTDI_SIO_SET_RTS_LOW, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("Error from RTS LOW urb");
+		}	
+	}
+
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	port->active = 0;
+} /* ftdi_sio_close */
+
+
+  
+/* The ftdi_sio requires the first byte to have:
+ *  B0 1
+ *  B1 0
+ *  B2..7 length of message excluding byte 0
+ */
+static int ftdi_sio_write (struct usb_serial_port *port, int from_user, 
+			   const unsigned char *buf, int count)
+{ /* ftdi_sio_write */
+	struct usb_serial *serial = port->serial;
+	const int data_offset = 1;
+	int rc; 
+	DECLARE_WAITQUEUE(wait, current);
+	
+	dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
+
+	if (count == 0) {
+		err("write request of 0 bytes");
+		return 0;
+	}
+
+	/* only do something if we have a bulk out endpoint */
+	if (serial->num_bulk_out) {
+		unsigned char *first_byte = port->write_urb->transfer_buffer;
+
+		/* Was seeing a race here, got a read callback, then write callback before
+		   hitting interuptible_sleep_on  - so wrapping in add_wait_queue stuff */
+
+		add_wait_queue(&port->write_wait, &wait);
+		set_current_state (TASK_INTERRUPTIBLE);
+		while (port->write_urb->status == -EINPROGRESS) {
+			dbg("ftdi_sio - write in progress - retrying");
+			if (0 /* file->f_flags & O_NONBLOCK */) {
+				rc = -EAGAIN;
+				goto err;
+			}
+			if (signal_pending(current)) {
+				current->state = TASK_RUNNING;
+				remove_wait_queue(&port->write_wait, &wait);
+				rc = -ERESTARTSYS;
+				goto err;
+			}
+			schedule();
+		}		
+		remove_wait_queue(&port->write_wait, &wait);
+		set_current_state(TASK_RUNNING);
+
+		count += data_offset;
+		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+		if (count == 0) {
+			return 0;
+		}
+
+		/* Copy in the data to send */
+		if (from_user) {
+			copy_from_user(port->write_urb->transfer_buffer + data_offset , 
+				       buf, count - data_offset );
+		}
+		else {
+			memcpy(port->write_urb->transfer_buffer + data_offset,
+			       buf, count - data_offset );
+		}  
+
+		/* Write the control byte at the front of the packet*/
+		first_byte = port->write_urb->transfer_buffer;
+		*first_byte = 1 | ((count-data_offset) << 2) ; 
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+		dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+
+		if (count) {
+			int i;
+			printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count);
+			for (i = 0; i < count; ++i) {
+				printk ( "0x%02x ", first_byte[i]);
+				if (first_byte[i] > ' ' && first_byte[i] < '~') {
+					printk( "%c ", first_byte[i]);
+				} else {
+					printk( "  ");
+				}
+			}
+
+		     
+			printk ( "\n");
+		}
+
+#endif
+		/* send the data out the bulk port */
+		port->write_urb->transfer_buffer_length = count;
+
+		if (usb_submit_urb(port->write_urb))
+			err("usb_submit_urb(write bulk) failed");
+
+		dbg("write returning: %d", count - data_offset);
+		return (count - data_offset);
+	}
+	
+	/* no bulk out, so return 0 bytes written */
+	return 0;
+ err: /* error exit */
+	return(rc);
+} /* ftdi_sio_write */
+
+static void ftdi_sio_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+       	struct tty_struct *tty = port->tty;
+
+	dbg("ftdi_sio_write_bulk_callback");
+
+	if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "ftdi_sio_write_bulk_callback")) {
+		return;
+	}
+	
+	if (urb->status) {
+		dbg("nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	wake_up_interruptible(&port->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+	
+	return;
+} /* ftdi_sio_write_bulk_callback */
+
+static void ftdi_sio_read_bulk_callback (struct urb *urb)
+{ /* ftdi_sio_serial_buld_callback */
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+       	struct tty_struct *tty = port->tty ;
+       	unsigned char *data = urb->transfer_buffer;
+
+	const int data_offset = 2;
+	int i;
+
+	dbg("ftdi_sio read callback");
+
+	if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
+		return;
+	}
+	
+	/* TO DO -- check for hung up line and handle appropriately: */
+	/*   send hangup (need to find out how to do this) */
+ 
+
+	if (urb->status) {
+		/* This will happen at close every time so it is a dbg not an err */
+		dbg("nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	if (urb->actual_length > 2) {
+		printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length);
+		for (i = 0; i < urb->actual_length; ++i) {
+			printk ( "0x%.2x ", data[i]);
+			if (data[i] > ' ' && data[i] < '~') {
+				printk( "%c ", data[i]);
+			} else {
+				printk( "  ");
+			}
+		}
+		printk ( "\n");
+	} else {
+                dbg("Just status");
+        }
+#endif
+	
+
+	if (urb->actual_length > data_offset) {
+		for (i = data_offset ; i < urb->actual_length ; ++i) {
+			tty_insert_flip_char(tty, data[i], 0);
+	  	}
+	  	tty_flip_buffer_push(tty);
+	}
+
+	/* Continue trying to always read  */
+	if (usb_submit_urb(urb))
+		err("failed resubmitting read urb");
+
+	return;
+} /* ftdi_sio_serial_read_bulk_callback */
+
+/* As I understand this - old_termios contains the original termios settings */
+/*  and tty->termios contains the new setting to be used */
+/* */
+/*   WARNING: set_termios calls this with old_termios in kernel space */
+
+static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{ /* ftdi_sio_set_termios */
+	struct usb_serial *serial = port->serial;
+	unsigned int cflag = port->tty->termios->c_cflag;
+	__u16 urb_value; /* Will hold the new flags */
+	char buf[1]; /* Perhaps I should dynamically alloc this? */
+	
+	dbg("ftdi_sio_set_termios port %d", port->number);
+
+
+	/* FIXME -For this cut I don't care if the line is really changing or 
+	   not  - so just do the change regardless  - should be able to 
+	   compare old_termios and tty->termios */
+	/* NOTE These routines can get interrupted by 
+	   ftdi_sio_read_bulk_callback  - need to examine what this 
+           means - don't see any problems yet */
+	
+	/* Set number of data bits, parity, stop bits */
+	
+	urb_value = 0;
+	urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
+		      FTDI_SIO_SET_DATA_STOP_BITS_1);
+	urb_value |= (cflag & PARENB ? 
+		      (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : 
+		       FTDI_SIO_SET_DATA_PARITY_EVEN) :
+		      FTDI_SIO_SET_DATA_PARITY_NONE);
+	if (cflag & CSIZE) {
+		switch (cflag & CSIZE) {
+		case CS5: urb_value |= 5; dbg("Setting CS5"); break;
+		case CS6: urb_value |= 6; dbg("Setting CS6"); break;
+		case CS7: urb_value |= 7; dbg("Setting CS7"); break;
+		case CS8: urb_value |= 8; dbg("Setting CS8"); break;
+		default:
+			err("CSIZE was set but not CS5-CS8");
+		}
+	}
+	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			    FTDI_SIO_SET_DATA_REQUEST, 
+			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
+			    urb_value , 0,
+			    buf, 0, 100) < 0) {
+		err("FAILED to set databits/stopbits/parity");
+	}	   
+
+	/* Now do the baudrate */
+
+	switch(cflag & CBAUD){
+	case B0: break; /* Handled below */
+	case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
+	case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
+	case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
+	case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
+	case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
+	case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
+	case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
+	case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
+	case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
+	case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
+	default: dbg("FTDI_SIO does not support the baudrate requested"); 
+		/* FIXME - how to return an error for this? */ break;
+	}
+	if ((cflag & CBAUD) == B0 ) {
+		/* Disable flow control */
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+				    0, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("error from disable flowcontrol urb");
+		}	    
+		/* Drop RTS and DTR */
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    (unsigned)FTDI_SIO_SET_DTR_LOW, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("Error from DTR LOW urb");
+		}
+		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    (unsigned)FTDI_SIO_SET_RTS_LOW, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("Error from RTS LOW urb");
+		}	
+		
+	} else {
+		if (usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_BAUDRATE_REQUEST, 
+				    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
+				    urb_value, 0, 
+				    buf, 0, 100) < 0) {
+			err("urb failed to set baurdrate");
+		}
+	}
+	/* Set flow control */
+	/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
+	if (cflag & CRTSCTS) {
+		dbg("Setting to CRTSCTS flow control");
+		if (usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+				    0 , FTDI_SIO_RTS_CTS_HS,
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("urb failed to set to rts/cts flow control");
+		}		
+		
+	} else { 
+		/* CHECK Assuming XON/XOFF handled by stack - not by device */
+		/* Disable flow control */
+		dbg("Turning off hardware flow control");
+		if (usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+				    0, 0, 
+				    buf, 0, WDR_TIMEOUT) < 0) {
+			err("urb failed to clear flow control");
+		}				
+		
+	}
+	return;
+} /* ftdi_sio_set_termios */
+
+static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial *serial = port->serial;
+	__u16 urb_value=0; /* Will hold the new flags */
+	char buf[1];
+	int  ret, mask;
+	
+	dbg("ftdi_sio_ioctl - cmd 0x%04x", cmd);
+
+	/* Based on code from acm.c and others */
+	switch (cmd) {
+
+	case TIOCMGET:
+		dbg("TIOCMGET");
+		/* Request the status from the device */
+		if ((ret = usb_control_msg(serial->dev, 
+					   usb_rcvctrlpipe(serial->dev, 0),
+					   FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
+					   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+					   0, 0, 
+					   buf, 1, HZ * 5)) < 0 ) {
+			dbg("Get not get modem status of device");
+			return(ret);
+		}
+
+		return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
+				(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
+				(buf[0]  & FTDI_SIO_RI_MASK  ? TIOCM_RI  : 0) |
+				(buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0),
+				(unsigned long *) arg);
+		break;
+
+	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+		dbg("TIOCMSET");
+		if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+		urb_value = ((mask & TIOCM_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW);
+		if ((ret = usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    urb_value , 0,
+				    buf, 0, WDR_TIMEOUT)) < 0){
+			err("Urb to set DTR failed");
+			return(ret);
+		}
+		urb_value = ((mask & TIOCM_RTS) ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW);
+		if ((ret = usb_control_msg(serial->dev, 
+				    usb_sndctrlpipe(serial->dev, 0),
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+				    urb_value , 0,
+				    buf, 0, WDR_TIMEOUT)) < 0){
+			err("Urb to set RTS failed");
+			return(ret);
+		}
+		break;
+					
+	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+		dbg("TIOCMBIS");
+ 	        if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+  	        if (mask & TIOCM_DTR){
+			if ((ret = usb_control_msg(serial->dev, 
+					    usb_sndctrlpipe(serial->dev, 0),
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+					    FTDI_SIO_SET_DTR_HIGH , 0,
+					    buf, 0, WDR_TIMEOUT)) < 0){
+				err("Urb to set DTR failed");
+				return(ret);
+				}
+			}
+			if (mask & TIOCM_RTS) {
+			if ((ret = usb_control_msg(serial->dev, 
+					    usb_sndctrlpipe(serial->dev, 0),
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+					    FTDI_SIO_SET_RTS_HIGH , 0,
+					    buf, 0, WDR_TIMEOUT)) < 0){
+				err("Urb to set RTS failed");
+				return(ret);
+			}
+		}
+					break;
+
+	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+		dbg("TIOCMBIC");
+ 	        if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+  	        if (mask & TIOCM_DTR){
+			if ((ret = usb_control_msg(serial->dev, 
+					    usb_sndctrlpipe(serial->dev, 0),
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+					    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+					    FTDI_SIO_SET_DTR_LOW , 0,
+					    buf, 0, WDR_TIMEOUT)) < 0){
+				err("Urb to unset DTR failed");
+				return(ret);
+			}
+		}	
+		if (mask & TIOCM_RTS) {
+			if ((ret = usb_control_msg(serial->dev, 
+					       usb_sndctrlpipe(serial->dev, 0),
+					       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+					       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+					    FTDI_SIO_SET_RTS_LOW , 0,
+					    buf, 0, WDR_TIMEOUT)) < 0){
+				err("Urb to unset RTS failed");
+				return(ret);
+			}
+		}
+		break;
+
+		/*
+		 * I had originally implemented TCSET{A,S}{,F,W} and
+		 * TCGET{A,S} here separately, however when testing I
+		 * found that the higher layers actually do the termios
+		 * conversions themselves and pass the call onto
+		 * ftdi_sio_set_termios. 
+		 *
+		 */
+
+	default:
+	  /* This is not an error - turns out the higher layers will do 
+	   *  some ioctls itself (see comment above)
+ 	   */
+		dbg("ftdi_sio ioctl arg not supported - it was 0x%04x",cmd);
+		return(-ENOIOCTLCMD);
+		break;
+	}
+	dbg("ftdi_sio_ioctl returning 0");
+	return 0;
+} /* ftdi_sio_ioctl */
+
+
+int ftdi_sio_init (void)
+{
+	usb_serial_register (&ftdi_sio_device);
+	return 0;
+}
+
+
+void ftdi_sio_exit (void)
+{
+	usb_serial_deregister (&ftdi_sio_device);
+}
+
+
+module_init(ftdi_sio_init);
+module_exit(ftdi_sio_exit);
+
+MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>");
+MODULE_DESCRIPTION("USB FTDI SIO driver");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/ftdi_sio.h linux.18p8/drivers/usb/serial/ftdi_sio.h
--- linux.vanilla/drivers/usb/serial/ftdi_sio.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/ftdi_sio.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,413 @@
+/*
+ * Definitions for the FTDI USB Single Port Serial Converter - 
+ * known as FTDI_SIO (Serial Input/Output application of the chipset) 
+ *
+ * The example I have is known as the USC-1000 which is available from
+ * http://www.dse.co.nz - cat no XH4214 It looks similar to this:
+ * http://www.dansdata.com/usbser.htm but I can't be sure There are other
+ * USC-1000s which don't look like my device though so beware!
+ *
+ * The device is based on the FTDI FT8U100AX chip. It has a DB25 on one side, 
+ * USB on the other.
+ *
+ * Thanx to FTDI (http://www.ftdi.co.uk) for so kindly providing details
+ * of the protocol required to talk to the device and ongoing assistence
+ * during development.
+ *
+ * Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the 
+ * FTDI_SIO implementation.
+ *
+ */
+
+#define FTDI_VID	0x0403	/* Vendor Id */
+#define FTDI_SIO_PID	0x8372	/* Product Id */
+
+/* Vendor Request Interface */
+#define FTDI_SIO_RESET 		0 /* Reset the port */
+#define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
+#define FTDI_SIO_SET_FLOW_CTRL	2 /* Set flow control register */
+#define FTDI_SIO_SET_BAUD_RATE	3 /* Set baud rate */
+#define FTDI_SIO_SET_DATA	4 /* Set the data characteristics of the port */
+#define FTDI_SIO_GET_MODEM_STATUS	5 /* Retrieve current value of modern status register */
+#define FTDI_SIO_SET_EVENT_CHAR	6 /* Set the event character */
+#define FTDI_SIO_SET_ERROR_CHAR	7 /* Set the error character */
+
+/* Port Identifier Table */
+#define PIT_DEFAULT 		0 /* SIOA */
+#define PIT_SIOA		1 /* SIOA */
+/* The device this driver is tested with one has only one port */
+#define PIT_SIOB		2 /* SIOB */
+#define PIT_PARALLEL		3 /* Parallel */
+
+/* FTDI_SIO_RESET */
+#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET
+#define FTDI_SIO_RESET_REQUEST_TYPE 0x40
+#define FTDI_SIO_RESET_SIO 0
+#define FTDI_SIO_RESET_PURGE_RX 1
+#define FTDI_SIO_RESET_PURGE_TX 2
+
+/*
+ * BmRequestType:  0100 0000B
+ * bRequest:       FTDI_SIO_RESET
+ * wValue:         Control Value 
+ *                   0 = Reset SIO
+ *                   1 = Purge RX buffer
+ *                   2 = Purge TX buffer
+ * wIndex:         Port
+ * wLength:        0
+ * Data:           None
+ *
+ * The Reset SIO command has this effect:
+ *
+ *    Sets flow control set to 'none'
+ *    Event char = $0D
+ *    Event trigger = disabled
+ *    Purge RX buffer
+ *    Purge TX buffer
+ *    Clear DTR
+ *    Clear RTS
+ *    baud and data format not reset
+ *
+ * The Purge RX and TX buffer commands affect nothing except the buffers
+ *
+   */
+
+/* FTDI_SIO_SET_BAUDRATE */
+#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_BAUDRATE_REQUEST 3
+
+/*
+ * BmRequestType:  0100 0000B
+ * bRequest:       FTDI_SIO_SET_BAUDRATE
+ * wValue:         BaudRate value - see below
+ * wIndex:         Port
+ * wLength:        0
+ * Data:           None
+ */
+
+typedef enum {
+ ftdi_sio_b300 = 0, 
+ ftdi_sio_b600 = 1, 
+ ftdi_sio_b1200 = 2,
+ ftdi_sio_b2400 = 3,
+ ftdi_sio_b4800 = 4,
+ ftdi_sio_b9600 = 5,
+ ftdi_sio_b19200 = 6,
+ ftdi_sio_b38400 = 7,
+ ftdi_sio_b57600 = 8,
+ ftdi_sio_b115200 = 9
+} FTDI_SIO_baudrate_t ;
+
+#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
+#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8 )
+#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8 )
+#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8 )
+#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8 )
+#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8 )
+#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11 )
+#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11 )
+#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11 )
+
+/* FTDI_SIO_SET_DATA */
+
+/*
+ * BmRequestType:  0100 0000B 
+ * bRequest:       FTDI_SIO_SET_DATA
+ * wValue:         Data characteristics (see below)
+ * wIndex:         Port
+ * wLength:        0
+ * Data:           No
+ *
+ * Data characteristics
+ *
+ *   B0..7   Number of data bits
+ *   B8..10  Parity
+ *           0 = None
+ *           1 = Odd
+ *           2 = Even
+ *           3 = Mark
+ *           4 = Space
+ *   B11..13 Stop Bits
+ *           0 = 1
+ *           1 = 1.5
+ *           2 = 2
+ *   B14..15 Reserved
+ *
+ */
+
+
+
+/* FTDI_SIO_MODEM_CTRL */
+#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL
+
+/* 
+ * BmRequestType:   0100 0000B
+ * bRequest:        FTDI_SIO_MODEM_CTRL
+ * wValue:          ControlValue (see below)
+ * wIndex:          Port
+ * wLength:         0
+ * Data:            None
+ *
+ * NOTE: If the device is in RTS/CTS flow control, the RTS set by this
+ * command will be IGNORED without an error being returned
+ * Also - you can not set DTR and RTS with one control message
+ */
+
+#define FTDI_SIO_SET_DTR_MASK 0x1
+#define FTDI_SIO_SET_DTR_HIGH ( 1 | ( FTDI_SIO_SET_DTR_MASK  << 8))
+#define FTDI_SIO_SET_DTR_LOW  ( 0 | ( FTDI_SIO_SET_DTR_MASK  << 8))
+#define FTDI_SIO_SET_RTS_MASK 0x2
+#define FTDI_SIO_SET_RTS_HIGH ( 2 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
+#define FTDI_SIO_SET_RTS_LOW ( 0 | ( FTDI_SIO_SET_RTS_MASK << 8 ))
+
+/*
+ * ControlValue
+ * B0    DTR state
+ *          0 = reset
+ *          1 = set
+ * B1    RTS state
+ *          0 = reset
+ *          1 = set
+ * B2..7 Reserved
+ * B8    DTR state enable
+ *          0 = ignore
+ *          1 = use DTR state
+ * B9    RTS state enable
+ *          0 = ignore
+ *          1 = use RTS state
+ * B10..15 Reserved
+ */
+
+/* FTDI_SIO_SET_FLOW_CTRL */
+#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40
+#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL
+#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 
+#define FTDI_SIO_RTS_CTS_HS (0x1 << 8)
+#define FTDI_SIO_DTR_DSR_HS (0x2 << 8)
+#define FTDI_SIO_XON_XOFF_HS (0x4 << 8)
+/*
+ *   BmRequestType:  0100 0000b
+ *   bRequest:       FTDI_SIO_SET_FLOW_CTRL
+ *   wValue:         Xoff/Xon
+ *   wIndex:         Protocol/Port - hIndex is protocl / lIndex is port
+ *   wLength:        0 
+ *   Data:           None
+ *
+ * hIndex protocol is:
+ *   B0 Output handshaking using RTS/CTS
+ *       0 = disabled
+ *       1 = enabled
+ *   B1 Output handshaking using DTR/DSR
+ *       0 = disabled
+ *       1 = enabled
+ *   B2 Xon/Xoff handshaking
+ *       0 = disabled
+ *       1 = enabled
+ *
+ * A value of zero in the hIndex field disables handshaking
+ *
+ * If Xon/Xoff handshaking is specified, the hValue field should contain the XOFF character 
+ * and the lValue field contains the XON character.
+ */  
+ 
+/*
+ * FTDI_SIO_SET_EVENT_CHAR 
+ *
+ * Set the special event character for the specified communications port.
+ * If the device sees this character it will immediately return the
+ * data read so far - rather than wait 40ms or until 62 bytes are read
+ * which is what normally happens.
+ */
+
+
+#define  FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR
+#define  FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40
+
+
+/* 
+ *  BmRequestType:   0100 0000b
+ *  bRequest:        FTDI_SIO_SET_EVENT_CHAR
+ *  wValue:          EventChar
+ *  wIndex:          Port
+ *  wLength:         0
+ *  Data:            None
+ *
+ * wValue:
+ *   B0..7   Event Character
+ *   B8      Event Character Processing
+ *             0 = disabled
+ *             1 = enabled
+ *   B9..15  Reserved
+ *
+ */
+          
+/* FTDI_SIO_SET_ERROR_CHAR */
+
+/* Set the parity error replacement character for the specified communications port */
+
+/* 
+ *  BmRequestType:  0100 0000b
+ *  bRequest:       FTDI_SIO_SET_EVENT_CHAR
+ *  wValue:         Error Char
+ *  wIndex:         Port
+ *  wLength:        0
+ *  Data:           None
+ *
+ *Error Char
+ *  B0..7  Error Character
+ *  B8     Error Character Processing
+ *           0 = disabled
+ *           1 = enabled
+ *  B9..15 Reserved
+ *
+ */
+
+/* FTDI_SIO_GET_MODEM_STATUS */
+/* Retreive the current value of the modem status register */
+
+#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0
+#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS
+#define FTDI_SIO_CTS_MASK 0x10
+#define FTDI_SIO_DSR_MASK 0x20
+#define FTDI_SIO_RI_MASK  0x40
+#define FTDI_SIO_RLSD_MASK 0x80
+/* 
+ *   BmRequestType:   1100 0000b
+ *   bRequest:        FTDI_SIO_GET_MODEM_STATUS
+ *   wValue:          zero
+ *   wIndex:          Port
+ *   wLength:         1
+ *   Data:            Status
+ * 
+ * One byte of data is returned 
+ * B0..3 0
+ * B4    CTS
+ *         0 = inactive
+ *         1 = active
+ * B5    DSR
+ *         0 = inactive
+ *         1 = active
+ * B6    Ring Indicator (RI)
+ *         0 = inactive
+ *         1 = active
+ * B7    Receive Line Signal Detect (RLSD)
+ *         0 = inactive
+ *         1 = active 
+ */
+
+
+
+/* Descriptors returned by the device 
+ * 
+ *  Device Descriptor
+ * 
+ * Offset	Field		Size	Value	Description
+ * 0	bLength		1	0x12	Size of descriptor in bytes
+ * 1	bDescriptorType	1	0x01	DEVICE Descriptor Type
+ * 2	bcdUSB		2	0x0110	USB Spec Release Number
+ * 4	bDeviceClass	1	0x00	Class Code
+ * 5	bDeviceSubClass	1	0x00	SubClass Code
+ * 6	bDeviceProtocol	1	0x00	Protocol Code
+ * 7	bMaxPacketSize0 1	0x08	Maximum packet size for endpoint 0
+ * 8	idVendor	2	0x0403	Vendor ID
+ * 10	idProduct	2	0x8372	Product ID (FTDI_SIO_PID)
+ * 12	bcdDevice	2	0x0001	Device release number
+ * 14	iManufacturer	1	0x01	Index of man. string desc
+ * 15	iProduct	1	0x02	Index of prod string desc
+ * 16	iSerialNumber	1	0x02	Index of serial nmr string desc
+ * 17	bNumConfigurations 1    0x01	Number of possible configurations
+ * 
+ * Configuration Descriptor
+ * 
+ * Offset	Field			Size	Value
+ * 0	bLength			1	0x09	Size of descriptor in bytes
+ * 1	bDescriptorType		1	0x02	CONFIGURATION Descriptor Type
+ * 2	wTotalLength		2	0x0020	Total length of data
+ * 4	bNumInterfaces		1	0x01	Number of interfaces supported
+ * 5	bConfigurationValue	1	0x01	Argument for SetCOnfiguration() req
+ * 6	iConfiguration		1	0x02	Index of config string descriptor
+ * 7	bmAttributes		1	0x20	Config characteristics Remote Wakeup
+ * 8	MaxPower		1	0x1E	Max power consumption
+ * 
+ * Interface Descriptor
+ * 
+ * Offset	Field			Size	Value
+ * 0	bLength			1	0x09	Size of descriptor in bytes
+ * 1	bDescriptorType		1	0x04	INTERFACE Descriptor Type
+ * 2	bInterfaceNumber	1	0x00	Number of interface
+ * 3	bAlternateSetting	1	0x00	Value used to select alternate
+ * 4	bNumEndpoints		1	0x02	Number of endpoints
+ * 5	bInterfaceClass		1	0xFF	Class Code
+ * 6	bInterfaceSubClass	1	0xFF	Subclass Code
+ * 7	bInterfaceProtocol	1	0xFF	Protocol Code
+ * 8	iInterface		1	0x02	Index of interface string description
+ * 
+ * IN Endpoint Descriptor
+ * 
+ * Offset	Field			Size	Value
+ * 0	bLength			1	0x07	Size of descriptor in bytes
+ * 1	bDescriptorType		1	0x05	ENDPOINT descriptor type
+ * 2	bEndpointAddress	1	0x82	Address of endpoint
+ * 3	bmAttributes		1	0x02	Endpoint attributes - Bulk
+ * 4	bNumEndpoints		2	0x0040	maximum packet size
+ * 5	bInterval		1	0x00	Interval for polling endpoint
+ * 
+ * OUT Endpoint Descriptor
+ * 
+ * Offset	Field			Size	Value
+ * 0	bLength			1	0x07	Size of descriptor in bytes
+ * 1	bDescriptorType		1	0x05	ENDPOINT descriptor type
+ * 2	bEndpointAddress	1	0x02	Address of endpoint
+ * 3	bmAttributes		1	0x02	Endpoint attributes - Bulk
+ * 4	bNumEndpoints		2	0x0040	maximum packet size
+ * 5	bInterval		1	0x00	Interval for polling endpoint
+ *     
+ * DATA FORMAT
+ * 
+ * IN Endpoint
+ * 
+ * The device reserves the first two bytes of data on this endpoint to contain the current
+ * values of the modem and line status registers. In the absence of data, the device 
+ * generates a message consisting of these two status bytes every 40 ms
+ * 
+ * Byte 0: Modem Status
+ * 
+ * Offset	Description
+ * B0	Reserved - must be 1
+ * B1	Reserved - must be 0
+ * B2	Reserved - must be 0
+ * B3	Reserved - must be 0
+ * B4	Clear to Send (CTS)
+ * B5	Data Set Ready (DSR)
+ * B6	Ring Indicator (RI)
+ * B7	Receive Line Signal Detect (RLSD)
+ * 
+ * Byte 1: Line Status
+ * 
+ * Offset	Description
+ * B0	Data Ready (DR)
+ * B1	Overrun Error (OE)
+ * B2	Parity Error (PE)
+ * B3	Framing Error (FE)
+ * B4	Break Interrupt (BI)
+ * B5	Transmitter Holding Register (THRE)
+ * B6	Transmitter Empty (TEMT)
+ * B7	Error in RCVR FIFO
+ * 
+ * OUT Endpoint
+ * 
+ * This device reserves the first bytes of data on this endpoint contain the length
+ * and port identifier of the message. For the FTDI USB Serial converter the port 
+ * identifier is always 1.
+ * 
+ * Byte 0: Line Status
+ * 
+ * Offset	Description
+ * B0	Reserved - must be 1
+ * B1	Reserved - must be 0
+ * B2..7	Length of message - (not including Byte 0)
+ * 
+ */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan.c linux.18p8/drivers/usb/serial/keyspan.c
--- linux.vanilla/drivers/usb/serial/keyspan.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan.c	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,725 @@
+/*
+  Keyspan USB to Serial Converter driver
+ 
+  (C) Copyright (C) 2000
+      Hugh Blemings <hugh@linuxcare.com>
+   
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  See http://www.linuxcare.com.au/hugh/keyspan.html for more
+  information on this driver.
+  
+  Code in this driver inspired by and in a number of places taken
+  from Brian Warner's original Keyspan-PDA driver.
+
+  This driver has been put together with the support of Innosys, Inc.
+  and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
+  Thanks Guys :)
+  
+  Tip 'o the hat to Linuxcare for supporting staff in their work on
+  open source projects.
+
+  Wed Jul 19 14:00:42 EST 2000 gkh
+	Added module_init and module_exit functions to handle the fact that this
+	driver is a loadable module now.
+
+  Tue Jul 18 16:14:52 EST 2000 Hugh
+    Basic character input/output for USA-19 now mostly works,
+    fixed at 9600 baud for the moment.
+
+*/
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+#include "keyspan.h"
+
+	/* Per device and per port private data */
+struct keyspan_serial_private {
+	struct urb	*in_urbs[8];
+	struct urb	*out_urbs[8];
+	char		out_buffer[64];
+	char		in_buffer[64];
+};
+
+struct keyspan_port_private {
+ 		/* Keep track of which output endpoint to use */
+	int		out_flip;
+
+		/* Settings for the port */
+	int		baud;
+	int		old_baud;
+	enum		{parity_none, parity_odd, parity_even} parity;
+	enum		{flow_none, flow_cts, flow_xon} flow_control;
+	int		rts_state;
+	int		dtr_state;
+
+};
+
+
+	/* FIXME this will break if multiple physical interfaces used */
+static wait_queue_head_t	out_wait;
+	
+	/* Include Keyspan message headers (not both yet, need some tweaks
+	   to get clean build) */
+/*#include "keyspan_usa26msg.h"*/
+#include "keyspan_usa28msg.h"
+	
+	/* If you don't get debugging output, uncomment the following
+	   two lines to enable cheat. */
+#undef 	dbg
+#define	dbg	printk
+
+	/* Functions - mostly stubs for now */
+static void keyspan_rx_throttle (struct usb_serial_port *port)
+{
+	dbg("keyspan_rx_throttle port %d", port->number);
+}
+
+
+static void keyspan_rx_unthrottle (struct usb_serial_port *port)
+{
+	dbg("keyspan_rx_unthrottle port %d", port->number);
+}
+
+
+static void keyspan_break_ctl (struct usb_serial_port *port, int break_state)
+{
+	dbg("keyspan_break_ctl");
+}
+
+
+static void keyspan_set_termios (struct usb_serial_port *port, 
+				     struct termios *old_termios)
+{
+	dbg("keyspan_set_termios");
+}
+
+static int keyspan_ioctl(struct usb_serial_port *port, struct file *file,
+			     unsigned int cmd, unsigned long arg)
+{
+	unsigned int		value;
+
+	dbg("keyspan_ioctl_info");
+	
+	switch (cmd) {
+	case TIOCMGET:
+		value = TIOCM_DTR | TIOCM_RNG;
+		if (copy_to_user((unsigned int *)arg, &value, sizeof(int))) {
+			return -EFAULT;
+		}
+		else {
+			return 0;
+		}
+		
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	return -ENOIOCTLCMD;
+}
+
+static int keyspan_write(struct usb_serial_port *port, int from_user, 
+			     const unsigned char *buf, int count)
+{
+	struct usb_serial 		*serial = port->serial;
+	struct keyspan_serial_private 	*s_priv;
+	struct keyspan_port_private 	*p_priv;
+	int				current_urb;
+	int				i;
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+	p_priv = (struct keyspan_port_private *)(port->private);
+	
+	if (p_priv->out_flip == 0) {
+		current_urb = 0;
+		p_priv->out_flip = 1;
+	}
+	else {
+		current_urb = 1;
+		p_priv->out_flip = 0;
+	}
+
+	dbg("keyspan_write called for port %d (%d) chars {", port->number, count);
+	for (i = 0; i < count ; i++) {
+		dbg("%02x ", buf[i]);
+	}
+	dbg("}\n");
+
+	if (count == 0) {
+		dbg("write request of 0 bytes");
+		return (0);
+	}
+
+		/* only send data if we have a bulk out endpoint */
+	if (s_priv->out_urbs[current_urb]) {
+		while (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) {
+			dbg (__FUNCTION__ " INPROGRES\n");
+			interruptible_sleep_on(&out_wait);
+			if (signal_pending(current)) {
+				dbg (__FUNCTION__ " signal\n");
+				return (-ERESTARTSYS);
+			}
+		}
+		/*if (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) {
+			dbg ("already writing");
+			return (-EAGAIN);
+		}*/
+			/* First byte in buffer is "last flag" - unused so
+			   for now so set to zero */
+		memset(s_priv->out_urbs[current_urb]->transfer_buffer, 0, 1);
+
+		if (from_user) {
+			copy_from_user(s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count);
+		}
+		else {
+			memcpy (s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count);
+		}  
+
+		/* send the data out the bulk port */
+		s_priv->out_urbs[current_urb]->transfer_buffer_length = count + 1;
+
+		if (usb_submit_urb(s_priv->out_urbs[current_urb])) {
+			dbg("usb_submit_urb(write bulk) failed");
+		}
+
+		return (count);
+	}
+	
+	/* no bulk out, so return 0 bytes written */
+	return (0);
+}
+
+
+static void keyspan_write_bulk_callback (struct urb *urb)
+{
+	int		endpoint;
+	
+	endpoint = usb_pipeendpoint(urb->pipe);
+
+	dbg("keyspan_write_bulk_callback for endpoint %d\n", endpoint);
+
+		/* Only do wakeup if this callback is from one of the data
+		   endpoints.  */
+	if (endpoint == 2 || endpoint == 3) {
+		wake_up_interruptible(&out_wait);
+	}
+
+}
+
+
+static void keyspan_read_bulk_callback (struct urb *urb)
+{
+	int			i;
+	int			endpoint;
+	struct usb_serial	*serial;
+	struct usb_serial_port	*port;
+	struct tty_struct	*tty;
+	unsigned char 		*data = urb->transfer_buffer;
+
+	endpoint = usb_pipeendpoint(urb->pipe);
+
+
+	if (urb->status) {
+		dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.\n",
+			      		urb->status, endpoint);
+		return;
+	}
+
+	switch (endpoint) {
+
+			/* If this is one of the data endpoints, stuff it's
+		   	   contents into the tty flip_buffer. */
+		case 1:
+		case 2: serial = (struct usb_serial *) urb->context;
+			port = &serial->port[0];
+			tty = port->tty;
+			if (urb->actual_length) {
+				for (i = 0; i < urb->actual_length ; ++i) {
+					 tty_insert_flip_char(tty, data[i], 0);
+				}
+				tty_flip_buffer_push(tty);
+			}
+			break;
+
+			/* INACK endpoint */	
+		case 3: dbg(__FUNCTION__ " callback for INACK endpoint\n");
+			break;
+
+			/* INSTAT endpoint */
+		case 4: dbg(__FUNCTION__ " callback for INSTAT endpoint\n");
+			break;
+		
+		default:
+		       	dbg(__FUNCTION__ " callback for unknown endpoint!\n");
+			break;
+	}
+				
+		/* Resubmit urb so we continue receiving */
+	if (usb_submit_urb(urb)) {
+		dbg(__FUNCTION__ "resubmit read urb failed.\n");
+	}
+	return;
+	
+}
+
+static int keyspan_write_room (struct usb_serial_port *port)
+{
+//	dbg("keyspan_write_room called\n");
+	return (32);
+
+}
+
+
+static int keyspan_chars_in_buffer (struct usb_serial_port *port)
+{
+	return (0);
+}
+
+
+static int keyspan_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct keyspan_port_private 	*p_priv;
+	struct keyspan_serial_private 	*s_priv;
+	struct usb_serial 		*serial = port->serial;
+	int				i;
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+	p_priv = (struct keyspan_port_private *)(port->private);
+	
+	dbg("keyspan_open called.\n");
+	
+	if (port->active) {
+		dbg(__FUNCTION__ "port->active already true!\n");
+		return (-EINVAL);
+	}
+
+	p_priv = (struct keyspan_port_private *)(port->private);
+	
+	p_priv->out_flip = 0;
+	port->active = 1;
+
+		/* Start reading from port */
+	for (i = 0; i < 4; i++) {
+		if (s_priv->in_urbs[i]) {
+			if (usb_submit_urb(s_priv->in_urbs[i])) {
+				dbg(__FUNCTION__ " submit in urb %d failed", i);
+			}
+		}
+
+	}
+	
+	keyspan_usa19_send_setup(serial, port);
+
+	return (0);
+}
+
+
+static void keyspan_close(struct usb_serial_port *port, struct file *filp)
+{
+	int			i;
+	struct usb_serial	*serial = port->serial; /* FIXME should so sanity check */
+	struct keyspan_serial_private 	*s_priv;
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+	
+		/* Stop reading/writing urbs */
+	for (i = 0; i < 4; i++) {
+		if (s_priv->in_urbs[i]) {
+			usb_unlink_urb(s_priv->in_urbs[i]);
+		}
+
+	}
+	for (i = 0; i < 3; i++) {
+		if (s_priv->out_urbs[i]) {
+			usb_unlink_urb(s_priv->out_urbs[i]);
+		}
+
+	}
+	port->active = 0;
+	dbg("keyspan_close called\n");
+}
+
+
+	/* download the firmware to a pre-renumeration device */
+static int keyspan_fake_startup (struct usb_serial *serial)
+{
+	int 				response;
+	const struct ezusb_hex_record 	*record;
+	char				*fw_name;
+
+	dbg("Keyspan startup version %04x product %04x\n", serial->dev->descriptor.bcdDevice,
+		       					serial->dev->descriptor.idProduct); 
+	
+	if ((serial->dev->descriptor.bcdDevice & 0x8000) != 0x8000) {
+		dbg("Firmware already loaded.  Quitting.\n");
+		return(1);
+	}
+
+		/* Select firmware image on the basis of idProduct */
+	switch (serial->dev->descriptor.idProduct) {
+		case 0x0101: record = &keyspan_usa28_firmware[0];
+			     fw_name = "USA28";
+			     break;
+			     
+		case 0x0102: record = &keyspan_usa28x_firmware[0];
+			     fw_name = "USA28X";
+			     break;
+
+		case 0x0103: record = &keyspan_usa19_firmware[0];
+			     fw_name = "USA19";
+			     break;
+			     
+		case 0x0105: record = &keyspan_usa18x_firmware[0];
+			     fw_name = "USA18X";
+			     break;
+			     
+		case 0x0106: record = &keyspan_usa19w_firmware[0];
+			     fw_name = "USA19W";
+			     break;
+		
+		default:     record = NULL;
+			     fw_name = "Unknown";
+			     break;
+	}
+
+	if (record == NULL) {
+		err("Required keyspan firmware image (%s) unavailable.\n", fw_name);
+		return(1);
+	}
+
+	dbg("Uploading Keyspan %s firmware.\n", fw_name);
+
+		/* download the firmware image */
+	response = ezusb_set_reset(serial, 1);
+
+	while(record->address != 0xffff) {
+		response = ezusb_writememory(serial, record->address,
+					     (unsigned char *)record->data,
+					     record->data_size, 0xa0);
+		if (response < 0) {
+			err("ezusb_writememory failed for Keyspan"
+			    "firmware (%d %04X %p %d)",
+			    response, 
+			    record->address, record->data, record->data_size);
+			break;
+		}
+		record++;
+	}
+		/* bring device out of reset. Renumeration will occur in a
+		   moment and the new device will bind to the real driver */
+	response = ezusb_set_reset(serial, 0);
+
+		/* we don't want this device to have a driver assigned to it. */
+	return (1);
+}
+
+	/* USA-19 uses three output endpoints and four input
+	   endpoints.  First two output endpoints are for
+	   data (used in an alternating fashion), the third is
+	   output control.  First two input endpoints are for
+	   data (again alternating), the third is the ACK
+	   endpoint, the fourth is input status. */
+static void keyspan_usa19_setup_urbs(struct usb_serial *serial)
+{
+	struct keyspan_serial_private 	*s_priv;
+	int			i;
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+
+		/* Output urbs first */
+	dbg(__FUNCTION__ "Allocating output urbs.\n");
+	for (i = 0; i < 3; i++) {
+
+		s_priv->out_urbs[i] = usb_alloc_urb (0);	/* No ISO */
+		if (!s_priv->out_urbs[i]) {
+			dbg (__FUNCTION__ "Alloc for %d out urb failed.\n", i);
+			return;
+		}
+
+		FILL_BULK_URB(s_priv->out_urbs[i], serial->dev, 
+			      usb_sndbulkpipe(serial->dev, i + 1),
+			      &s_priv->out_buffer[i], sizeof(s_priv->out_buffer[i]),
+			      keyspan_write_bulk_callback, 
+			      serial);
+	}
+
+		/* Now input urbs */
+	dbg(__FUNCTION__ "Allocating input urbs.\n");
+	for (i = 0; i < 4; i++) {
+
+		s_priv->in_urbs[i] = usb_alloc_urb (0);	/* No ISO */
+		if (!s_priv->in_urbs[i]) {
+			dbg (__FUNCTION__ "Alloc for %d in urb failed.\n", i);
+			return;
+		}
+
+		FILL_BULK_URB(s_priv->in_urbs[i], serial->dev, 
+			      usb_rcvbulkpipe(serial->dev, i + 0x81),
+			      &s_priv->in_buffer[i], sizeof(s_priv->in_buffer[i]),
+			      keyspan_read_bulk_callback, 
+			      serial);
+	}
+	
+}
+
+static int keyspan_usa19_calc_baud(u32 baud_rate, u8 *rate_hi, u8 *rate_low)
+{
+	u32 b16,	/* baud rate times 16 (actual rate used internally) */
+		div,	/* divisor */	
+		cnt;	/* inverse of divisor (programmed into 8051) */
+
+		/* prevent divide by zero...  */
+	if( (b16 = (baud_rate * 16L)) == 0) {
+		return (KEYSPAN_INVALID_BAUD_RATE);
+	}
+
+		/* calculate the divisor and the counter (its inverse) */
+	if( (div = (USA19_BAUDCLK / b16)) == 0) {
+		return (KEYSPAN_INVALID_BAUD_RATE);
+	}
+	else {
+		cnt = 0 - div;
+	}
+
+	if(div > 0xffff) {
+		return (KEYSPAN_INVALID_BAUD_RATE);
+	}
+
+		/* return the counter values */
+	*rate_low = (u8) (cnt & 0xff);
+	*rate_hi = (u8) ((cnt >> 8) & 0xff);
+	
+	dbg(__FUNCTION__ " Baud rate of %d is %02x %02x.\n", baud_rate, *rate_hi, *rate_low);
+
+	return (KEYSPAN_BAUD_RATE_OK);
+}
+
+static int keyspan_usa19_send_setup(struct usb_serial *serial, struct usb_serial_port *port)
+{
+	struct portControlMessage	msg;		
+	struct keyspan_serial_private 	*s_priv;
+	struct keyspan_port_private 	*p_priv;
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+	p_priv = (struct keyspan_port_private *)(port->private);
+
+	//memset(msg, 0, sizeof (struct portControlMessage));
+		
+	msg.setBaudRate = 1;
+	if (keyspan_usa19_calc_baud(9600, &msg.baudHi, &msg.baudLo) ==
+		KEYSPAN_INVALID_BAUD_RATE ) {
+		dbg(__FUNCTION__ "Invalid baud rate requested %d.\n", 9600);
+		msg.baudLo = 0xff;
+		msg.baudHi = 0xb2;	/* Values for 9600 baud */
+	}
+
+		/* If parity is enabled, we must calculate it ourselves. */
+	if (p_priv->parity) {
+		msg.parity = 1;
+	}
+	else {
+		msg.parity = 0;
+	}
+
+	msg.ctsFlowControl = 0;
+	msg.xonFlowControl = 0;
+	msg.rts = 1;
+	msg.dtr = 0;
+	
+	msg.forwardingLength = 1;
+	msg.forwardMs = 10;
+	msg.breakThreshold = 45;
+	msg.xonChar = 17;
+	msg.xoffChar = 19;
+	
+	msg._txOn = 1;
+	msg._txOff = 0;
+	msg.txFlush = 0;
+	msg.txForceXoff = 0;
+	msg.txBreak = 0;
+	msg.rxOn = 1;
+	msg.rxOff = 0;
+	msg.rxFlush = 0;
+	msg.rxForward = 0;
+	msg.returnStatus = 1;
+	msg.resetDataToggle = 1;
+
+		
+	/* only do something if we have a bulk out endpoint */
+	if (s_priv->out_urbs[2]) {
+		if (s_priv->out_urbs[2]->status == -EINPROGRESS) {
+			dbg (__FUNCTION__ " already writing");
+			return(-1);
+		}
+		memcpy (s_priv->out_urbs[2]->transfer_buffer, &msg, sizeof(msg));
+	
+			/* send the data out the device on control endpoint */
+		s_priv->out_urbs[2]->transfer_buffer_length = sizeof(msg);
+
+		if (usb_submit_urb(s_priv->out_urbs[2])) {
+			dbg(__FUNCTION__ " usb_submit_urb(setup) failed\n");
+		}
+		else {
+			dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes\n", s_priv->out_urbs[2]->transfer_buffer_length);
+		}
+	
+	}
+	return (0);
+}
+
+
+	/* Gets called by the "real" driver (ie once firmware is loaded
+	   and renumeration has taken place. */
+static int keyspan_startup (struct usb_serial *serial)
+{
+	int			i;
+	struct usb_serial_port	*port;
+
+	dbg("keyspan_startup called.\n");
+
+		/* Setup private data for serial driver */
+	serial->private = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
+	if (!serial->private) {
+		dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed!.\n");
+		return (1);
+	}
+	memset(serial->private, 0, sizeof(struct keyspan_serial_private));
+		
+	init_waitqueue_head(&out_wait);
+	
+		/* Now setup per port private data */
+	for (i = 0; i < serial->num_ports; i++) {
+		port = &serial->port[i];
+		port->private = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
+		if (!port->private) {
+			dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.\n", i);
+			return (1);
+		}
+		memset(port->private, 0, sizeof(struct keyspan_port_private));
+	}
+
+	
+
+	switch (serial->dev->descriptor.idProduct) {
+		case 0x0107:	keyspan_usa19_setup_urbs(serial);
+				//keyspan_send_usa19_setup(serial);
+				break;
+
+		default:	break;
+	}
+
+			
+	return (0);
+}
+
+static void keyspan_shutdown (struct usb_serial *serial)
+{
+	int				i;
+	struct usb_serial_port		*port;
+	struct keyspan_serial_private 	*s_priv;
+
+	dbg("keyspan_shutdown called freeing ");
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+
+		/* Stop reading/writing urbs */
+	for (i = 0; i < 4; i++) {
+		if (s_priv->in_urbs[i]) {
+			usb_unlink_urb(s_priv->in_urbs[i]);
+		}
+
+	}
+	for (i = 0; i < 3; i++) {
+		if (s_priv->out_urbs[i]) {
+			usb_unlink_urb(s_priv->out_urbs[i]);
+		}
+
+	}
+		/* Now free them */
+	for (i = 0; i < 7; i ++) {
+		if (s_priv->in_urbs[i] != NULL) {
+			dbg("in%d ", i);
+			usb_free_urb(s_priv->in_urbs[i]);
+		}
+		
+		if (s_priv->out_urbs[i] != NULL) {
+			dbg("out%d ", i);
+			usb_free_urb(s_priv->out_urbs[i]);
+		}
+	}
+	dbg("urbs.\n");
+
+	dbg("Freeing serial->private.\n");	
+	kfree(serial->private);
+
+	dbg("Freeing port->private.\n");	
+		/* Now free per port private data */
+	for (i = 0; i < serial->num_ports; i++) {
+		port = &serial->port[i];
+		kfree(port->private);
+	}
+	
+}
+
+
+int keyspan_init (void)
+{
+	usb_serial_register (&keyspan_usa18x_pre_device);
+	usb_serial_register (&keyspan_usa19_pre_device);
+	usb_serial_register (&keyspan_usa19w_pre_device);
+	usb_serial_register (&keyspan_usa28_pre_device);
+	usb_serial_register (&keyspan_usa28x_pre_device);
+	usb_serial_register (&keyspan_usa18x_device);
+	usb_serial_register (&keyspan_usa19_device);
+	usb_serial_register (&keyspan_usa19w_device);
+	usb_serial_register (&keyspan_usa28_device);
+	usb_serial_register (&keyspan_usa28x_device);
+	return 0;
+}
+
+
+void keyspan_exit (void)
+{
+	usb_serial_deregister (&keyspan_usa18x_pre_device);
+	usb_serial_deregister (&keyspan_usa19_pre_device);
+	usb_serial_deregister (&keyspan_usa19w_pre_device);
+	usb_serial_deregister (&keyspan_usa28_pre_device);
+	usb_serial_deregister (&keyspan_usa28x_pre_device);
+	usb_serial_deregister (&keyspan_usa18x_device);
+	usb_serial_deregister (&keyspan_usa19_device);
+	usb_serial_deregister (&keyspan_usa19w_device);
+	usb_serial_deregister (&keyspan_usa28_device);
+	usb_serial_deregister (&keyspan_usa28x_device);
+}
+
+
+module_init(keyspan_init);
+module_exit(keyspan_exit);
+
+MODULE_AUTHOR("Hugh Blemings <hugh@linuxcare.com>");
+MODULE_DESCRIPTION("Keyspan USB to Serial Converter driver");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan.h linux.18p8/drivers/usb/serial/keyspan.h
--- linux.vanilla/drivers/usb/serial/keyspan.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan.h	Fri Sep  8 17:20:11 2000
@@ -0,0 +1,327 @@
+/*
+  Keyspan USB to Serial Converter driver
+ 
+  (C) Copyright (C) 2000
+      Hugh Blemings <hugh@linuxcare.com>
+   
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  See http://www.linuxcare.com.au/hugh/keyspan.html for more
+  information on this driver.
+  
+  Code in this driver inspired by and in a number of places taken
+  from Brian Warner's original Keyspan-PDA driver.
+
+  This driver has been put together with the support of Innosys, Inc.
+  and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
+  Thanks Guys :)
+  
+  Tip 'o the hat to Linuxcare for supporting staff in their work on
+  open source projects.
+  
+  See keyspan.c for update history.
+
+*/
+
+#ifndef __LINUX_USB_SERIAL_KEYSPAN_H
+#define __LINUX_USB_SERIAL_KEYSPAN_H
+
+#include <linux/config.h>
+
+	/* Function prototypes for Keyspan serial converter */
+static int  keyspan_open		(struct usb_serial_port *port,
+					 struct file *filp);
+static void keyspan_close		(struct usb_serial_port *port,
+					 struct file *filp);
+static int  keyspan_startup		(struct usb_serial *serial);
+static void keyspan_shutdown		(struct usb_serial *serial);
+static void keyspan_rx_throttle		(struct usb_serial_port *port);
+static void keyspan_rx_unthrottle	(struct usb_serial_port *port);
+static int  keyspan_write_room		(struct usb_serial_port *port);
+static int  keyspan_write		(struct usb_serial_port *port,
+					 int from_user,
+					 const unsigned char *buf,
+					 int count);
+static void keyspan_write_bulk_callback (struct urb *urb);
+static void keyspan_read_bulk_callback  (struct urb *urb);
+static int  keyspan_chars_in_buffer 	(struct usb_serial_port *port);
+static int  keyspan_ioctl		(struct usb_serial_port *port,
+					 struct file *file,
+					 unsigned int cmd,
+					 unsigned long arg);
+static void keyspan_set_termios		(struct usb_serial_port *port,
+					 struct termios *old);
+static void keyspan_break_ctl		(struct usb_serial_port *port,
+					 int break_state);
+static int  keyspan_fake_startup	(struct usb_serial *serial);
+
+static int  keyspan_usa19_calc_baud	(u32 baud_rate, u8 *rate_hi, 
+					 u8 *rate_low);
+static void keyspan_usa19_setup_urbs	(struct usb_serial *serial);
+static int  keyspan_usa19_send_setup	(struct usb_serial *serial,
+					 struct usb_serial_port *port);
+
+
+	/* Functions from usbserial.c for ezusb firmware handling */
+extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
+extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
+
+	/* Struct used for firmware */
+struct ezusb_hex_record {
+	__u16 address;
+	__u8 data_size;
+	__u8 data[16];
+};
+	/* Conditionally include firmware images, if they aren't
+	   included create a null pointer instead.  Current 
+	   firmware images aren't optimised to remove duplicate
+	   addresses. */
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28
+        #include "keyspan_usa28_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_usa28_firmware = NULL;
+#endif
+
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA28X
+        #include "keyspan_usa28x_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_usa28x_firmware = NULL;
+#endif
+
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19
+        #include "keyspan_usa19_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_usa19_firmware = NULL;
+#endif
+
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA18X
+        #include "keyspan_usa18x_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_usa18x_firmware = NULL;
+#endif
+
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA19W
+        #include "keyspan_usa19w_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_usa19w_firmware = NULL;
+#endif
+
+
+	/* Values used for baud rate calculation - device specific */
+#define	KEYSPAN_INVALID_BAUD_RATE		(-1)
+#define	KEYSPAN_BAUD_RATE_OK			(0)
+#define	USA19_BAUDCLK				(12000000L)
+
+	/* Device info for the Keyspan serial converter */
+#define KEYSPAN_VENDOR_ID			(0x06cd)
+static __u16	keyspan_vendor_id		= KEYSPAN_VENDOR_ID;
+
+    /* Product IDs for the five products supported, pre-renumeration */
+static __u16	keyspan_usa18x_pre_product_id	= 0x0105;	
+static __u16	keyspan_usa19_pre_product_id	= 0x0103;	
+static __u16	keyspan_usa19w_pre_product_id	= 0x0106;	
+static __u16	keyspan_usa28_pre_product_id	= 0x0101;	
+static __u16	keyspan_usa28x_pre_product_id	= 0x0102;	
+
+    /* Product IDs post-renumeration */
+static __u16	keyspan_usa18x_product_id	= 0x0112;	
+static __u16	keyspan_usa19_product_id	= 0x0107;	
+static __u16	keyspan_usa19w_product_id	= 0x0108;	
+static __u16	keyspan_usa28_product_id	= 0x010f;	
+static __u16	keyspan_usa28x_product_id	= 0x0110;	
+
+    /* Structs for the devices, pre and post renumeration.
+       These are incomplete at present - HAB 20000708  */
+struct usb_serial_device_type keyspan_usa18x_pre_device = {
+	name:			"Keyspan USA18X - (prerenumeration)",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa18x_pre_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	startup:		keyspan_fake_startup	
+};
+
+struct usb_serial_device_type keyspan_usa19_pre_device = {
+	name:			"Keyspan USA19 - (prerenumeration)",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa19_pre_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	startup:		keyspan_fake_startup	
+};
+
+
+struct usb_serial_device_type keyspan_usa19w_pre_device = {
+	name:			"Keyspan USA19W - (prerenumeration)",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa19w_pre_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	startup:		keyspan_fake_startup	
+};
+
+
+struct usb_serial_device_type keyspan_usa28_pre_device = {
+	name:			"Keyspan USA28 - (prerenumeration)",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa28_pre_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		2,
+	startup:		keyspan_fake_startup	
+};
+
+struct usb_serial_device_type keyspan_usa28x_pre_device = {
+	name:			"Keyspan USA28X - (prerenumeration)",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa28x_pre_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		2,
+	startup:		keyspan_fake_startup	
+};
+
+
+struct usb_serial_device_type keyspan_usa18x_device = {
+	name:			"Keyspan USA18X",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa18x_product_id,
+	needs_interrupt_in:	DONT_CARE,	
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	open:			keyspan_open,
+	close:			keyspan_close,
+	throttle:		keyspan_rx_throttle,
+	unthrottle:		keyspan_rx_unthrottle,
+	set_termios:		keyspan_set_termios,
+};
+
+struct usb_serial_device_type keyspan_usa19_device = {
+	name:			"Keyspan USA19",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa19_product_id,
+	needs_interrupt_in:	DONT_CARE,	
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		3,
+	num_bulk_out:		4,
+	num_ports:		1,
+	open:			keyspan_open,
+	close:			keyspan_close,
+	write:			keyspan_write,
+	write_room:		keyspan_write_room,
+	write_bulk_callback: 	keyspan_write_bulk_callback,
+	read_int_callback:	keyspan_read_bulk_callback,
+	chars_in_buffer:	keyspan_chars_in_buffer,
+	throttle:		keyspan_rx_throttle,
+	unthrottle:		keyspan_rx_unthrottle,
+	ioctl:			keyspan_ioctl,
+	set_termios:		keyspan_set_termios,
+	break_ctl:		keyspan_break_ctl,
+	startup:		keyspan_startup,
+	shutdown:		keyspan_shutdown,
+};
+
+
+struct usb_serial_device_type keyspan_usa19w_device = {
+	name:			"Keyspan USA19W",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa19w_product_id,
+	needs_interrupt_in:	DONT_CARE,	
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	open:			keyspan_open,
+	close:			keyspan_close,
+	throttle:		keyspan_rx_throttle,
+	unthrottle:		keyspan_rx_unthrottle,
+	set_termios:		keyspan_set_termios,
+};
+
+
+struct usb_serial_device_type keyspan_usa28_device = {
+	name:			"Keyspan USA28",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa28_product_id,
+	needs_interrupt_in:	DONT_CARE,	
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		2,
+	open:			keyspan_open,
+	close:			keyspan_close,
+	throttle:		keyspan_rx_throttle,
+	unthrottle:		keyspan_rx_unthrottle,
+	set_termios:		keyspan_set_termios,
+};
+
+
+struct usb_serial_device_type keyspan_usa28x_device = {
+	name:			"Keyspan USA28X",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa28x_product_id,
+	needs_interrupt_in:	DONT_CARE,	
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		2,
+	open:			keyspan_open,
+	close:			keyspan_close,
+	write:			keyspan_write,
+	write_room:		keyspan_write_room,
+	write_bulk_callback: 	keyspan_write_bulk_callback,
+	read_int_callback:	keyspan_read_bulk_callback,
+	chars_in_buffer:	keyspan_chars_in_buffer,
+	throttle:		keyspan_rx_throttle,
+	unthrottle:		keyspan_rx_unthrottle,
+	ioctl:			keyspan_ioctl,
+	set_termios:		keyspan_set_termios,
+	break_ctl:		keyspan_break_ctl,
+	startup:		keyspan_startup,
+	shutdown:		keyspan_shutdown,
+
+				
+
+};
+
+
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_pda.S linux.18p8/drivers/usb/serial/keyspan_pda.S
--- linux.vanilla/drivers/usb/serial/keyspan_pda.S	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_pda.S	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,1124 @@
+/*  $Id: loop.s,v 1.23 2000/03/20 09:49:06 warner Exp $
+ * 
+ *  Firmware for the Keyspan PDA Serial Adapter, a USB serial port based on
+ *  the EzUSB microcontroller.
+ * 
+ *  (C) Copyright 2000 Brian Warner <warner@lothar.com>
+ * 
+ * 	This program is free software; you can redistribute it and/or modify
+ * 	it under the terms of the GNU General Public License as published by
+ * 	the Free Software Foundation; either version 2 of the License, or
+ * 	(at your option) any later version.
+ * 
+ *  "Keyspan PDA Serial Adapter" is probably a copyright of Keyspan, the
+ *  company.
+ * 
+ *  This serial adapter is basically an EzUSB chip and an RS-232 line driver
+ *  in a little widget that has a DB-9 on one end and a USB plug on the other.
+ *  It uses the EzUSB's internal UART0 (using the pins from Port C) and timer2
+ *  as a baud-rate generator. The wiring is:
+ *   PC0/RxD0 <- rxd (DB9 pin 2)         PC4 <- dsr pin 6
+ *   PC1/TxD0 -> txd pin 3               PC5 <- ri  pin 9
+ *   PC2      -> rts pin 7               PC6 <- dcd pin 1
+ *   PC3      <- cts pin 8               PC7 -> dtr pin 4
+ *   PB1 -> line driver standby
+ *
+ *  The EzUSB register constants below come from their excellent documentation
+ *  and sample code (which used to be available at www.anchorchips.com, but
+ *  that has now been absorbed into Cypress' site and the CD-ROM contents
+ *  don't appear to be available online anymore). If we get multiple
+ *  EzUSB-based drivers into the kernel, it might be useful to pull them out
+ *  into a separate .h file.
+ * 
+ * THEORY OF OPERATION:
+ *
+ *   There are two 256-byte ring buffers, one for tx, one for rx.
+ *
+ *   EP2out is pure tx data. When it appears, the data is copied into the tx
+ *   ring and serial transmission is started if it wasn't already running. The
+ *   "tx buffer empty" interrupt may kick off another character if the ring
+ *   still has data. If the host is tx-blocked because the ring filled up,
+ *   it will request a "tx unthrottle" interrupt. If sending a serial character
+ *   empties the ring below the desired threshold, we set a bit that will send
+ *   up the tx unthrottle message as soon as the rx buffer becomes free.
+ *
+ *   EP2in (interrupt) is used to send both rx chars and rx status messages
+ *   (only "tx unthrottle" at this time) back up to the host. The first byte
+ *   of the rx message indicates data (0) or status msg (1). Status messages
+ *   are sent before any data.
+ *
+ *   Incoming serial characters are put into the rx ring by the serial
+ *   interrupt, and the EP2in buffer sent if it wasn't already in transit.
+ *   When the EP2in buffer returns, the interrupt prompts us to send more
+ *   rx chars (or status messages) if they are pending.
+ *
+ *   Device control happens through "vendor specific" control messages on EP0.
+ *   All messages are destined for the "Interface" (with the index always 0,
+ *   so that if their two-port device might someday use similar firmware, we
+ *   can use index=1 to refer to the second port). The messages defined are:
+ *
+ *    bRequest = 0 : set baud/bits/parity
+ *               1 : unused
+ *               2 : reserved for setting HW flow control (CTSRTS)
+ *               3 : get/set "modem info" (pin states: DTR, RTS, DCD, RI, etc)
+ *               4 : set break (on/off)
+ *               5 : reserved for requesting interrupts on pin state change
+ *               6 : query buffer room or chars in tx buffer
+ *               7 : request tx unthrottle interrupt
+ *
+ *  The host-side driver is set to recognize the device ID values stashed in
+ *  serial EEPROM (0x06cd, 0x0103), program this firmware into place, then
+ *  start it running. This firmware will use EzUSB's "renumeration" trick by
+ *  simulating a bus disconnect, then reconnect with a different device ID
+ *  (encoded in the desc_device descriptor below). The host driver then
+ *  recognizes the new device ID and glues it to the real serial driver code.
+ *
+ * USEFUL DOCS:
+ *  EzUSB Technical Reference Manual: <http://www.anchorchips.com>
+ *  8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is
+ *   basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports
+ *   use totally different registers!
+ *  USB 1.1 spec: www.usb.org
+ *
+ * HOW TO BUILD:
+ *  gcc -x assembler-with-cpp -P -E -o keyspan_pda.asm keyspan_pda.s
+ *  as31 -l keyspan_pda.asm
+ *  mv keyspan_pda.obj keyspan_pda.hex
+ *  perl ezusb_convert.pl keyspan_pda < keyspan_pda.hex > keyspan_pda_fw.h
+ * Get as31 from <http://www.pjrc.com/tech/8051/index.html>, and hack on it
+ * a bit to make it build.
+ *
+ * THANKS:
+ *  Greg Kroah-Hartman, for coordinating the whole usb-serial thing.
+ *  AnchorChips, for making such an incredibly useful little microcontroller.
+ *  KeySpan, for making a handy, cheap ($40) widget that was so easy to take
+ *           apart and trace with an ohmmeter.
+ *
+ * TODO:
+ *  lots. grep for TODO. Interrupt safety needs stress-testing. Better flow
+ *  control. Interrupting host upon change in DCD, etc, counting transitions.
+ *  Need to find a safe device id to use (the one used by the Keyspan firmware
+ *  under Windows would be ideal.. can anyone figure out what it is?). Parity.
+ *  More baud rates. Oh, and the string-descriptor-length silicon bug
+ *  workaround should be implemented, but I'm lazy, and the consequence is
+ *  that the device name strings that show up in your kernel log will have
+ *  lots of trailing binary garbage in them (appears as ????). Device strings
+ *  should be made more accurate.
+ *
+ * Questions, bugs, patches to Brian.
+ *
+ *  -Brian Warner <warner@lothar.com>
+ *
+ */
+	
+#define HIGH(x) (((x) & 0xff00) / 256)
+#define LOW(x) ((x) & 0xff)
+
+#define dpl1 0x84
+#define dph1 0x85
+#define dps 0x86
+
+;;; our bit assignments
+#define TX_RUNNING 0
+#define DO_TX_UNTHROTTLE 1
+	
+	;; stack from 0x60 to 0x7f: should really set SP to 0x60-1, not 0x60
+#define STACK #0x60-1
+
+#define EXIF 0x91
+#define EIE 0xe8
+	.flag EUSB, EIE.0
+	.flag ES0, IE.4
+
+#define EP0CS #0x7fb4
+#define EP0STALLbit #0x01
+#define IN0BUF #0x7f00
+#define IN0BC #0x7fb5
+#define OUT0BUF #0x7ec0
+#define OUT0BC #0x7fc5		
+#define IN2BUF #0x7e00
+#define IN2BC #0x7fb9
+#define IN2CS #0x7fb8
+#define OUT2BC #0x7fc9
+#define OUT2CS #0x7fc8
+#define OUT2BUF #0x7dc0
+#define IN4BUF #0x7d00
+#define IN4BC #0x7fbd
+#define IN4CS #0x7fbc
+#define OEB #0x7f9d
+#define OUTB #0x7f97
+#define OEC #0x7f9e
+#define OUTC #0x7f98
+#define PINSC #0x7f9b
+#define PORTCCFG #0x7f95
+#define IN07IRQ #0x7fa9
+#define OUT07IRQ #0x7faa
+#define IN07IEN #0x7fac
+#define OUT07IEN #0x7fad
+#define USBIRQ #0x7fab
+#define USBIEN #0x7fae
+#define USBBAV #0x7faf
+#define USBCS #0x7fd6
+#define SUDPTRH #0x7fd4
+#define SUDPTRL #0x7fd5
+#define SETUPDAT #0x7fe8
+		
+	;; usb interrupt : enable is EIE.0 (0xe8), flag is EXIF.4 (0x91)
+
+	.org 0
+	ljmp start
+	;; interrupt vectors
+	.org 23H
+	ljmp serial_int
+	.byte 0
+	
+	.org 43H
+	ljmp USB_Jump_Table
+	.byte 0			; filled in by the USB core
+
+;;; local variables. These are not initialized properly: do it by hand.
+	.org 30H
+rx_ring_in:	.byte 0
+rx_ring_out:	.byte 0
+tx_ring_in:	.byte 0
+tx_ring_out:	.byte 0
+tx_unthrottle_threshold:	.byte 0
+		
+	.org 0x100H		; wants to be on a page boundary
+USB_Jump_Table:
+	ljmp	ISR_Sudav	; Setup Data Available
+	.byte 0
+	ljmp	0		; Start of Frame
+	.byte 0
+	ljmp	0		; Setup Data Loading
+	.byte 0
+	ljmp	0		; Global Suspend
+	.byte 	0
+	ljmp	0		; USB Reset  	
+	.byte	0
+	ljmp	0		; Reserved
+	.byte	0
+	ljmp	0		; End Point 0 In
+	.byte	0
+	ljmp	0		; End Point 0 Out
+	.byte	0
+	ljmp	0		; End Point 1 In
+	.byte	0
+	ljmp	0		; End Point 1 Out
+	.byte	0
+	ljmp	ISR_Ep2in
+	.byte	0
+	ljmp	ISR_Ep2out
+	.byte	0
+
+
+	.org 0x200
+		
+start:	mov SP,STACK-1 ; set stack
+	;; clear local variables
+	clr a
+	mov tx_ring_in, a
+	mov tx_ring_out, a
+	mov rx_ring_in, a
+	mov rx_ring_out, a
+	mov tx_unthrottle_threshold, a
+	clr TX_RUNNING
+	clr DO_TX_UNTHROTTLE
+	
+	;; clear fifo with "fe"
+	mov r1, 0
+	mov a, #0xfe
+	mov dptr, #tx_ring
+clear_tx_ring_loop:
+	movx @dptr, a
+	inc dptr
+	djnz r1, clear_tx_ring_loop
+
+	mov a, #0xfd
+	mov dptr, #rx_ring
+clear_rx_ring_loop:
+	movx @dptr, a
+	inc dptr
+	djnz r1, clear_rx_ring_loop
+
+;;; turn on the RS-232 driver chip (bring the STANDBY pin low)
+	;; set OEB.1
+	mov a, #02H
+	mov dptr,OEB
+	movx @dptr,a
+	;; clear PB1
+	mov a, #00H
+	mov dptr,OUTB
+	movx @dptr,a
+	;; set OEC.[127]
+	mov a, #0x86
+	mov dptr,OEC
+	movx @dptr,a
+	;; set PORTCCFG.[01] to route TxD0,RxD0 to serial port
+	mov dptr, PORTCCFG
+	mov a, #0x03
+	movx @dptr, a
+	
+	;; set up interrupts, autovectoring
+	mov dptr, USBBAV
+	movx a,@dptr
+	setb acc.0		; AVEN bit to 0
+	movx @dptr, a
+
+	mov a,#0x01		; enable SUDAV:	setup data available (for ep0)
+	mov dptr, USBIRQ
+	movx @dptr, a		; clear SUDAVI
+	mov dptr, USBIEN
+	movx @dptr, a
+	
+	mov dptr, IN07IEN
+	mov a,#0x04		; enable IN2 int
+	movx @dptr, a
+	
+	mov dptr, OUT07IEN
+	mov a,#0x04		; enable OUT2 int
+	movx @dptr, a
+	mov dptr, OUT2BC
+	movx @dptr, a		; arm OUT2
+
+	mov a, #0x84		; turn on RTS, DTR
+	mov dptr,OUTC
+	movx @dptr, a
+	;; setup the serial port. 9600 8N1.
+	mov a,#01010011		; mode 1, enable rx, clear int
+	mov SCON, a
+	;;  using timer2, in 16-bit baud-rate-generator mode
+	;;   (xtal 12MHz, internal fosc 24MHz)
+	;;  RCAP2H,RCAP2L = 65536 - fosc/(32*baud)
+	;;  57600: 0xFFF2.F, say 0xFFF3
+	;;   9600: 0xFFB1.E, say 0xFFB2
+	;;    300: 0xF63C
+#define BAUD 9600
+#define BAUD_TIMEOUT(rate) (65536 - (24 * 1000 * 1000) / (32 * rate))
+#define BAUD_HIGH(rate) HIGH(BAUD_TIMEOUT(rate))
+#define BAUD_LOW(rate) LOW(BAUD_TIMEOUT(rate))
+		
+	mov T2CON, #030h	; rclk=1,tclk=1,cp=0,tr2=0(enable later)
+	mov r3, #5
+	acall set_baud
+	setb TR2
+	mov SCON, #050h
+	
+#if 0
+	mov r1, #0x40
+	mov a, #0x41
+send:	
+	mov SBUF, a
+	inc a
+	anl a, #0x3F
+	orl a, #0x40
+;	xrl a, #0x02
+wait1:	
+	jnb TI, wait1
+	clr TI
+	djnz r1, send
+;done:	sjmp done
+
+#endif
+	
+	setb EUSB
+	setb EA
+	setb ES0
+	;acall dump_stat
+
+	;; hey, what say we RENUMERATE! (TRM p.62)
+	mov a, #0
+	mov dps, a
+	mov dptr, USBCS
+	mov a, #0x02		; DISCON=0, DISCOE=0, RENUM=1
+	movx @dptr, a
+	;; now presence pin is floating, simulating disconnect. wait 0.5s
+	mov r1, #46
+renum_wait1:
+	mov r2, #0
+renum_wait2:
+	mov r3, #0
+renum_wait3:
+	djnz r3, renum_wait3
+	djnz r2, renum_wait2
+	djnz r1, renum_wait1	; wait about n*(256^2) 6MHz clocks
+	mov a, #0x06		; DISCON=0, DISCOE=1, RENUM=1
+	movx @dptr, a
+	;; we are back online. the host device will now re-query us
+	
+	
+main:	sjmp main
+
+	
+
+ISR_Sudav:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	mov a,EXIF
+	clr acc.4
+	mov EXIF,a		; clear INT2 first
+	mov dptr, USBIRQ	; clear USB int
+	mov a,#01h
+	movx @dptr,a
+
+	;; get request type
+	mov dptr, SETUPDAT
+	movx a, @dptr
+	mov r1, a		; r1 = bmRequestType
+	inc dptr
+	movx a, @dptr
+	mov r2, a		; r2 = bRequest
+	inc dptr
+	movx a, @dptr
+	mov r3, a		; r3 = wValueL
+	inc dptr
+	movx a, @dptr
+	mov r4, a		; r4 = wValueH
+
+	;; main switch on bmRequest.type: standard or vendor
+	mov a, r1
+	anl a, #0x60
+	cjne a, #0x00, setup_bmreq_type_not_standard
+	;; standard request: now main switch is on bRequest
+	ljmp setup_bmreq_is_standard
+	
+setup_bmreq_type_not_standard:	
+	;; a still has bmreq&0x60
+	cjne a, #0x40, setup_bmreq_type_not_vendor
+	;; Anchor reserves bRequest 0xa0-0xaf, we use small ones
+	;; switch on bRequest. bmRequest will always be 0x41 or 0xc1
+	cjne r2, #0x00, setup_ctrl_not_00
+	;; 00 is set baud, wValue[0] has baud rate index
+	lcall set_baud		; index in r3, carry set if error
+	jc setup_bmreq_type_not_standard__do_stall
+	ljmp setup_done_ack
+setup_bmreq_type_not_standard__do_stall:
+	ljmp setup_stall
+setup_ctrl_not_00:
+	cjne r2, #0x01, setup_ctrl_not_01
+	;; 01 is reserved for set bits (parity). TODO
+	ljmp setup_stall
+setup_ctrl_not_01:
+	cjne r2, #0x02, setup_ctrl_not_02
+	;; 02 is set HW flow control. TODO
+	ljmp setup_stall
+setup_ctrl_not_02:
+	cjne r2, #0x03, setup_ctrl_not_03
+	;; 03 is control pins (RTS, DTR).
+	ljmp control_pins	; will jump to setup_done_ack,
+				;  or setup_return_one_byte
+setup_ctrl_not_03:
+	cjne r2, #0x04, setup_ctrl_not_04
+	;; 04 is send break (really "turn break on/off"). TODO
+	cjne r3, #0x00, setup_ctrl_do_break_on
+	;; do break off: restore PORTCCFG.1 to reconnect TxD0 to serial port
+	mov dptr, PORTCCFG
+	movx a, @dptr
+	orl a, #0x02
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_ctrl_do_break_on:
+	;; do break on: clear PORTCCFG.0, set TxD high(?) (b1 low)
+	mov dptr, OUTC
+	movx a, @dptr
+	anl a, #0xfd		; ~0x02
+	movx @dptr, a
+	mov dptr, PORTCCFG
+	movx a, @dptr
+	anl a, #0xfd		; ~0x02
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_ctrl_not_04:
+	cjne r2, #0x05, setup_ctrl_not_05
+	;; 05 is set desired interrupt bitmap. TODO
+	ljmp setup_stall
+setup_ctrl_not_05:
+	cjne r2, #0x06, setup_ctrl_not_06
+	;; 06 is query room
+	cjne r3, #0x00, setup_ctrl_06_not_00
+	;; 06, wValue[0]=0 is query write_room
+	mov a, tx_ring_out
+	setb c
+	subb a, tx_ring_in	; out-1-in = 255 - (in-out)
+	ljmp setup_return_one_byte
+setup_ctrl_06_not_00:
+	cjne r3, #0x01, setup_ctrl_06_not_01
+	;; 06, wValue[0]=1 is query chars_in_buffer
+	mov a, tx_ring_in
+	clr c
+	subb a, tx_ring_out	; in-out
+	ljmp setup_return_one_byte
+setup_ctrl_06_not_01:	
+	ljmp setup_stall
+setup_ctrl_not_06:
+	cjne r2, #0x07, setup_ctrl_not_07
+	;; 07 is request tx unthrottle interrupt
+	mov tx_unthrottle_threshold, r3; wValue[0] is threshold value
+	ljmp setup_done_ack
+setup_ctrl_not_07:
+	ljmp setup_stall
+	
+setup_bmreq_type_not_vendor:
+	ljmp setup_stall
+
+
+setup_bmreq_is_standard:	
+	cjne r2, #0x00, setup_breq_not_00
+	;; 00:	Get_Status (sub-switch on bmRequestType: device, ep, int)
+	cjne r1, #0x80, setup_Get_Status_not_device
+	;; Get_Status(device)
+	;;  are we self-powered? no. can we do remote wakeup? no
+	;;   so return two zero bytes. This is reusable
+setup_return_two_zero_bytes:
+	mov dptr, IN0BUF
+	clr a
+	movx @dptr, a
+	inc dptr
+	movx @dptr, a
+	mov dptr, IN0BC
+	mov a, #2
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_Get_Status_not_device:
+	cjne r1, #0x82, setup_Get_Status_not_endpoint
+	;; Get_Status(endpoint)
+	;;  must get stall bit for ep[wIndexL], return two bytes, bit in lsb 0
+	;; for now: cheat. TODO
+	sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_endpoint:
+	cjne r1, #0x81, setup_Get_Status_not_interface
+	;; Get_Status(interface): return two zeros
+	sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_interface:	
+	ljmp setup_stall
+	
+setup_breq_not_00:
+	cjne r2, #0x01, setup_breq_not_01
+	;; 01:	Clear_Feature (sub-switch on wValueL: stall, remote wakeup)
+	cjne r3, #0x00, setup_Clear_Feature_not_stall
+	;; Clear_Feature(stall). should clear a stall bit. TODO
+	ljmp setup_stall
+setup_Clear_Feature_not_stall:
+	cjne r3, #0x01, setup_Clear_Feature_not_rwake
+	;; Clear_Feature(remote wakeup). ignored.
+	ljmp setup_done_ack
+setup_Clear_Feature_not_rwake:
+	ljmp setup_stall
+	
+setup_breq_not_01:
+	cjne r2, #0x03, setup_breq_not_03
+	;; 03:	Set_Feature (sub-switch on wValueL: stall, remote wakeup)
+	cjne r3, #0x00, setup_Set_Feature_not_stall
+	;; Set_Feature(stall). Should set a stall bit. TODO
+	ljmp setup_stall
+setup_Set_Feature_not_stall:
+	cjne r3, #0x01, setup_Set_Feature_not_rwake
+	;; Set_Feature(remote wakeup). ignored.
+	ljmp setup_done_ack
+setup_Set_Feature_not_rwake:
+	ljmp setup_stall
+	
+setup_breq_not_03:	
+	cjne r2, #0x06, setup_breq_not_06
+	;; 06:	Get_Descriptor (s-switch on wValueH: dev, config[n], string[n])
+	cjne r4, #0x01, setup_Get_Descriptor_not_device
+	;; Get_Descriptor(device)
+	mov dptr, SUDPTRH
+	mov a, #HIGH(desc_device)
+	movx @dptr, a
+	mov dptr, SUDPTRL
+	mov a, #LOW(desc_device)
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_Get_Descriptor_not_device:
+	cjne r4, #0x02, setup_Get_Descriptor_not_config
+	;; Get_Descriptor(config[n])
+	cjne r3, #0x00, setup_stall; only handle n==0
+	;; Get_Descriptor(config[0])
+	mov dptr, SUDPTRH
+	mov a, #HIGH(desc_config1)
+	movx @dptr, a
+	mov dptr, SUDPTRL
+	mov a, #LOW(desc_config1)
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_Get_Descriptor_not_config:
+	cjne r4, #0x03, setup_Get_Descriptor_not_string
+	;; Get_Descriptor(string[wValueL])
+	;;  if (wValueL >= maxstrings) stall
+	mov a, #((desc_strings_end-desc_strings)/2)
+	clr c
+	subb a,r3		; a=4, r3 = 0..3 . if a<=0 then stall
+	jc  setup_stall
+	jz  setup_stall
+	mov a, r3
+	add a, r3		; a = 2*wValueL
+	mov dptr, #desc_strings
+	add a, dpl
+	mov dpl, a
+	mov a, #0
+	addc a, dph
+	mov dph, a		; dph = desc_strings[a]. big endian! (handy)
+	;; it looks like my adapter uses a revision of the EZUSB that
+	;; contains "rev D errata number 8", as hinted in the EzUSB example
+	;; code. I cannot find an actual errata description on the Cypress
+	;; web site, but from the example code it looks like this bug causes
+	;; the length of string descriptors to be read incorrectly, possibly
+	;; sending back more characters than the descriptor has. The workaround
+	;; is to manually send out all of the data. The consequence of not
+	;; using the workaround is that the strings gathered by the kernel
+	;; driver are too long and are filled with trailing garbage (including
+	;; leftover strings). Writing this out by hand is a nuisance, so for
+	;; now I will just live with the bug.
+	movx a, @dptr
+	mov r1, a
+	inc dptr
+	movx a, @dptr
+	mov r2, a
+	mov dptr, SUDPTRH
+	mov a, r1
+	movx @dptr, a
+	mov dptr, SUDPTRL
+	mov a, r2
+	movx @dptr, a
+	;; done
+	ljmp setup_done_ack
+	
+setup_Get_Descriptor_not_string:
+	ljmp setup_stall
+	
+setup_breq_not_06:
+	cjne r2, #0x08, setup_breq_not_08
+	;; Get_Configuration. always 1. return one byte.
+	;; this is reusable
+	mov a, #1
+setup_return_one_byte:	
+	mov dptr, IN0BUF
+	movx @dptr, a
+	mov a, #1
+	mov dptr, IN0BC
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_breq_not_08:
+	cjne r2, #0x09, setup_breq_not_09
+	;; 09: Set_Configuration. ignored.
+	ljmp setup_done_ack
+setup_breq_not_09:
+	cjne r2, #0x0a, setup_breq_not_0a
+	;; 0a: Get_Interface. get the current altsetting for int[wIndexL]
+	;;  since we only have one interface, ignore wIndexL, return a 0
+	mov a, #0
+	ljmp setup_return_one_byte
+setup_breq_not_0a:
+	cjne r2, #0x0b, setup_breq_not_0b
+	;; 0b: Set_Interface. set altsetting for interface[wIndexL]. ignored
+	ljmp setup_done_ack
+setup_breq_not_0b:
+	ljmp setup_stall
+
+		
+setup_done_ack:	
+	;; now clear HSNAK
+	mov dptr, EP0CS
+	mov a, #0x02
+	movx @dptr, a
+	sjmp setup_done
+setup_stall:	
+	;; unhandled. STALL
+	;EP0CS |= bmEPSTALL
+	mov dptr, EP0CS
+	movx a, @dptr
+	orl a, EP0STALLbit
+	movx @dptr, a
+	sjmp setup_done
+	
+setup_done:	
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+;;; ==============================================================
+	
+set_baud:			; baud index in r3
+	;; verify a < 10
+	mov a, r3
+	jb ACC.7, set_baud__badbaud
+	clr c
+	subb a, #10
+	jnc set_baud__badbaud
+	mov a, r3
+	rl a			; a = index*2
+	add a, #LOW(baud_table)
+	mov dpl, a
+	mov a, #HIGH(baud_table)
+	addc a, #0
+	mov dph, a
+	;; TODO: shut down xmit/receive
+	;; TODO: wait for current xmit char to leave
+	;; TODO: shut down timer to avoid partial-char glitch
+	movx a,@dptr		; BAUD_HIGH
+	mov RCAP2H, a
+	mov TH2, a
+	inc dptr
+	movx a,@dptr		; BAUD_LOW
+	mov RCAP2L, a
+	mov TL2, a
+	;; TODO: restart xmit/receive
+	;; TODO: reenable interrupts, resume tx if pending
+	clr c			; c=0: success
+	ret
+set_baud__badbaud:
+	setb c			; c=1: failure
+	ret
+	
+;;; ==================================================
+control_pins:
+	cjne r1, #0x41, control_pins_in
+control_pins_out:
+	mov a, r3 ; wValue[0] holds new bits:	b7 is new DTR, b2 is new RTS
+	xrl a, #0xff		; 1 means active, 0V, +12V ?
+	anl a, #0x84
+	mov r3, a
+	mov dptr, OUTC
+	movx a, @dptr		; only change bits 7 and 2
+	anl a, #0x7b		; ~0x84
+	orl a, r3
+	movx @dptr, a		; other pins are inputs, bits ignored
+	ljmp setup_done_ack
+control_pins_in:
+	mov dptr, PINSC
+	movx a, @dptr
+	xrl a, #0xff
+	ljmp setup_return_one_byte
+
+;;; ========================================
+	
+ISR_Ep2in:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	mov a,EXIF
+	clr acc.4
+	mov EXIF,a		; clear INT2 first
+	mov dptr, IN07IRQ	; clear USB int
+	mov a,#04h
+	movx @dptr,a
+
+	;; do stuff
+	lcall start_in
+	
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+ISR_Ep2out:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	mov a,EXIF
+	clr acc.4
+	mov EXIF,a		; clear INT2 first
+	mov dptr, OUT07IRQ	; clear USB int
+	mov a,#04h
+	movx @dptr,a
+
+	;; do stuff
+
+	;; copy data into buffer. for now, assume we will have enough space
+	mov dptr, OUT2BC	; get byte count
+	movx a,@dptr
+	mov r1, a
+	clr a
+	mov dps, a
+	mov dptr, OUT2BUF	; load DPTR0 with source
+	mov dph1, #HIGH(tx_ring)	; load DPTR1 with target
+	mov dpl1, tx_ring_in
+OUT_loop:
+	movx a,@dptr		; read
+	inc dps			; switch to DPTR1: target
+	inc dpl1		; target = tx_ring_in+1
+	movx @dptr,a		; store
+	mov a,dpl1
+	cjne a, tx_ring_out, OUT_no_overflow
+	sjmp OUT_overflow
+OUT_no_overflow:	
+	inc tx_ring_in		; tx_ring_in++
+	inc dps			; switch to DPTR0: source
+	inc dptr
+	djnz r1, OUT_loop
+	sjmp OUT_done
+OUT_overflow:
+	;; signal overflow
+	;; fall through
+OUT_done:	
+	;; ack
+	mov dptr,OUT2BC
+	movx @dptr,a
+
+	;; start tx
+	acall maybe_start_tx
+	;acall dump_stat
+	
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+dump_stat:
+	;; fill in EP4in with a debugging message:
+	;;   tx_ring_in, tx_ring_out, rx_ring_in, rx_ring_out
+	;;   tx_active
+	;;   tx_ring[0..15]
+	;;   0xfc
+	;;   rx_ring[0..15]
+	clr a
+	mov dps, a
+	
+	mov dptr, IN4CS
+	movx a, @dptr
+	jb acc.1, dump_stat__done; busy: cannot dump, old one still pending
+	mov dptr, IN4BUF
+	
+	mov a, tx_ring_in
+	movx @dptr, a
+	inc dptr
+	mov a, tx_ring_out
+	movx @dptr, a
+	inc dptr
+
+	mov a, rx_ring_in
+	movx @dptr, a
+	inc dptr
+	mov a, rx_ring_out
+	movx @dptr, a
+	inc dptr
+	
+	clr a
+	jnb TX_RUNNING, dump_stat__no_tx_running
+	inc a
+dump_stat__no_tx_running:
+	movx @dptr, a
+	inc dptr
+	;; tx_ring[0..15]
+	inc dps
+	mov dptr, #tx_ring	; DPTR1: source
+	mov r1, #16
+dump_stat__tx_ring_loop:
+	movx a, @dptr
+	inc dptr
+	inc dps
+	movx @dptr, a
+	inc dptr
+	inc dps
+	djnz r1, dump_stat__tx_ring_loop
+	inc dps
+	
+	mov a, #0xfc
+	movx @dptr, a
+	inc dptr
+	
+	;; rx_ring[0..15]
+	inc dps
+	mov dptr, #rx_ring	; DPTR1: source
+	mov r1, #16
+dump_stat__rx_ring_loop:
+	movx a, @dptr
+	inc dptr
+	inc dps
+	movx @dptr, a
+	inc dptr
+	inc dps
+	djnz r1, dump_stat__rx_ring_loop
+	
+	;; now send it
+	clr a
+	mov dps, a
+	mov dptr, IN4BC
+	mov a, #38
+	movx @dptr, a
+dump_stat__done:	
+	ret
+		
+;;; ============================================================
+	
+maybe_start_tx:
+	;; make sure the tx process is running.
+	jb TX_RUNNING, start_tx_done
+start_tx:
+	;; is there work to be done?
+	mov a, tx_ring_in
+	cjne a,tx_ring_out, start_tx__work
+	ret			; no work
+start_tx__work:	
+	;; tx was not running. send the first character, setup the TI int
+	inc tx_ring_out		; [++tx_ring_out]
+	mov dph, #HIGH(tx_ring)
+	mov dpl, tx_ring_out
+	movx a, @dptr
+	mov sbuf, a
+	setb TX_RUNNING
+start_tx_done:
+	;; can we unthrottle the host tx process?
+	;;  step 1: do we care?
+	mov a, #0
+	cjne a, tx_unthrottle_threshold, start_tx__maybe_unthrottle_tx
+	;; nope
+start_tx_really_done:
+	ret
+start_tx__maybe_unthrottle_tx:
+	;;  step 2: is there now room?
+	mov a, tx_ring_out
+	setb c
+	subb a, tx_ring_in
+	;; a is now write_room. If thresh >= a, we can unthrottle
+	clr c
+	subb a, tx_unthrottle_threshold
+	jc start_tx_really_done	; nope
+	;; yes, we can unthrottle. remove the threshold and mark a request
+	mov tx_unthrottle_threshold, #0
+	setb DO_TX_UNTHROTTLE
+	;; prod rx, which will actually send the message when in2 becomes free
+	ljmp start_in
+	
+
+serial_int:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	jnb TI, serial_int__not_tx
+	;; tx finished. send another character if we have one
+	clr TI			; clear int
+	clr TX_RUNNING
+	lcall start_tx
+serial_int__not_tx:
+	jnb RI, serial_int__not_rx
+	lcall get_rx_char
+	clr RI			; clear int
+serial_int__not_rx:	
+	;; return
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+get_rx_char:
+	mov dph, #HIGH(rx_ring)
+	mov dpl, rx_ring_in
+	inc dpl			; target = rx_ring_in+1
+	mov a, sbuf
+	movx @dptr, a
+	;; check for overflow before incrementing rx_ring_in
+	mov a, dpl
+	cjne a, rx_ring_out, get_rx_char__no_overflow
+	;; signal overflow
+	ret
+get_rx_char__no_overflow:	
+	inc rx_ring_in
+	;; kick off USB INpipe
+	acall start_in
+	ret
+
+start_in:
+	;; check if the inpipe is already running.
+	mov dptr, IN2CS
+	movx a, @dptr
+	jb acc.1, start_in__done; int will handle it
+	jb DO_TX_UNTHROTTLE, start_in__do_tx_unthrottle
+	;; see if there is any work to do. a serial interrupt might occur
+	;; during this sequence?
+	mov a, rx_ring_in
+	cjne a, rx_ring_out, start_in__have_work
+	ret			; nope
+start_in__have_work:	
+	;; now copy as much data as possible into the pipe. 63 bytes max.
+	clr a
+	mov dps, a
+	mov dph, #HIGH(rx_ring)	; load DPTR0 with source
+	inc dps
+	mov dptr, IN2BUF	; load DPTR1 with target
+	movx @dptr, a		; in[0] signals that rest of IN is rx data
+	inc dptr
+	inc dps
+	;; loop until we run out of data, or we have copied 64 bytes
+	mov r1, #1		; INbuf size counter
+start_in__loop:
+	mov a, rx_ring_in
+	cjne a, rx_ring_out, start_in__still_copying
+	sjmp start_in__kick
+start_in__still_copying:
+	inc rx_ring_out
+	mov dpl, rx_ring_out
+	movx a, @dptr
+	inc dps
+	movx @dptr, a		; write into IN buffer
+	inc dptr
+	inc dps
+	inc r1
+	cjne r1, #64, start_in__loop; loop
+start_in__kick:
+	;; either we ran out of data, or we copied 64 bytes. r1 has byte count
+	;; kick off IN
+	mov dptr, IN2BC
+	mov a, r1
+	jz start_in__done
+	movx @dptr, a
+	;; done
+start_in__done:
+	;acall dump_stat
+	ret
+start_in__do_tx_unthrottle:
+	;; special sequence: send a tx unthrottle message
+	clr DO_TX_UNTHROTTLE
+	clr a
+	mov dps, a
+	mov dptr, IN2BUF
+	mov a, #1
+	movx @dptr, a
+	inc dptr
+	mov a, #2
+	movx @dptr, a
+	mov dptr, IN2BC
+	movx @dptr, a
+	ret
+	
+putchar:
+	clr TI
+	mov SBUF, a
+putchar_wait:
+	jnb TI, putchar_wait
+	clr TI
+	ret
+
+	
+baud_table:			; baud_high, then baud_low
+	;; baud[0]: 110
+	.byte BAUD_HIGH(110)
+	.byte BAUD_LOW(110)
+	;; baud[1]: 300
+	.byte BAUD_HIGH(300)
+	.byte BAUD_LOW(300)
+	;; baud[2]: 1200
+	.byte BAUD_HIGH(1200)
+	.byte BAUD_LOW(1200)
+	;; baud[3]: 2400
+	.byte BAUD_HIGH(2400)
+	.byte BAUD_LOW(2400)
+	;; baud[4]: 4800
+	.byte BAUD_HIGH(4800)
+	.byte BAUD_LOW(4800)
+	;; baud[5]: 9600
+	.byte BAUD_HIGH(9600)
+	.byte BAUD_LOW(9600)
+	;; baud[6]: 19200
+	.byte BAUD_HIGH(19200)
+	.byte BAUD_LOW(19200)
+	;; baud[7]: 38400
+	.byte BAUD_HIGH(38400)
+	.byte BAUD_LOW(38400)
+	;; baud[8]: 57600
+	.byte BAUD_HIGH(57600)
+	.byte BAUD_LOW(57600)
+	;; baud[9]: 115200
+	.byte BAUD_HIGH(115200)
+	.byte BAUD_LOW(115200)
+
+desc_device:
+	.byte 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40
+	.byte 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab, 1, 2, 3, 0x01
+;;; The "real" device id, which must match the host driver, is that
+;;; "0xcd 0x06 0x04 0x01" sequence, which is 0x06cd, 0x0104
+	
+desc_config1:
+	.byte 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32
+	.byte 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00
+	.byte 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01
+	.byte 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00
+
+desc_strings:
+	.word string_langids, string_mfg, string_product, string_serial
+desc_strings_end:
+
+string_langids:	.byte string_langids_end-string_langids
+	.byte 3
+	.word 0
+string_langids_end:
+
+	;; sigh. These strings are Unicode, meaning UTF16? 2 bytes each. Now
+	;; *that* is a pain in the ass to encode. And they are little-endian
+	;; too. Use this perl snippet to get the bytecodes:
+	/* while (<>) {
+	    @c = split(//);
+	    foreach $c (@c) {
+	     printf("0x%02x, 0x00, ", ord($c));
+	    }
+	   }
+	*/
+
+string_mfg:	.byte string_mfg_end-string_mfg
+	.byte 3
+;	.byte "ACME usb widgets"
+	.byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00, 0x73, 0x00
+string_mfg_end:
+	
+string_product:	.byte string_product_end-string_product
+	.byte 3
+;	.byte "ACME USB serial widget"
+	.byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00
+string_product_end:
+	
+string_serial:	.byte string_serial_end-string_serial
+	.byte 3
+;	.byte "47"
+	.byte 0x34, 0x00, 0x37, 0x00
+string_serial_end:
+		
+;;; ring buffer memory
+	;; tx_ring_in+1 is where the next input byte will go
+	;; [tx_ring_out] has been sent
+	;; if tx_ring_in == tx_ring_out, theres no work to do
+	;; there are (tx_ring_in - tx_ring_out) chars to be written
+	;; dont let _in lap _out
+	;;   cannot inc if tx_ring_in+1 == tx_ring_out
+	;;  write [tx_ring_in+1] then tx_ring_in++
+	;;   if (tx_ring_in+1 == tx_ring_out), overflow
+	;;   else tx_ring_in++
+	;;  read/send [tx_ring_out+1], then tx_ring_out++
+
+	;; rx_ring_in works the same way
+	
+	.org 0x1000
+tx_ring:
+	.skip 0x100		; 256 bytes
+rx_ring:
+	.skip 0x100		; 256 bytes
+	
+	
+	.END
+	
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_pda.c linux.18p8/drivers/usb/serial/keyspan_pda.c
--- linux.vanilla/drivers/usb/serial/keyspan_pda.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_pda.c	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,750 @@
+/*
+ * USB Keyspan PDA Converter driver
+ *
+ * Copyright (c) 1999, 2000 Greg Kroah-Hartman	<greg@kroah.com>
+ * Copyright (c) 1999, 2000 Brian Warner	<warner@lothar.com>
+ * Copyright (c) 2000 Al Borchers		<borchers@steinerpoint.com>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ * (07/20/2000) borchers
+ *	- keyspan_pda_write no longer sleeps if it is called on interrupt time;
+ *	  PPP and the line discipline with stty echo on can call write on
+ *	  interrupt time and this would cause an oops if write slept
+ *	- if keyspan_pda_write is in an interrupt, it will not call
+ *	  usb_control_msg (which sleeps) to query the room in the device
+ *	  buffer, it simply uses the current room value it has
+ *	- if the urb is busy or if it is throttled keyspan_pda_write just
+ *	  returns 0, rather than sleeping to wait for this to change; the
+ *	  write_chan code in n_tty.c will sleep if needed before calling
+ *	  keyspan_pda_write again
+ *	- if the device needs to be unthrottled, write now queues up the
+ *	  call to usb_control_msg (which sleeps) to unthrottle the device
+ *	- the wakeups from keyspan_pda_write_bulk_callback are queued rather
+ *	  than done directly from the callback to avoid the race in write_chan
+ *	- keyspan_pda_chars_in_buffer also indicates its buffer is full if the
+ *	  urb status is -EINPROGRESS, meaning it cannot write at the moment
+ *      
+ * (07/19/2000) gkh
+ *	Added module_init and module_exit functions to handle the fact that this
+ *	driver is a loadable module now.
+ *
+ * (03/26/2000) gkh
+ *	Split driver up into device specific pieces.
+ * 
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/tqueue.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+struct ezusb_hex_record {
+	__u16 address;
+	__u8 data_size;
+	__u8 data[16];
+};
+
+#include "keyspan_pda_fw.h"
+
+#include "usb-serial.h"
+
+struct keyspan_pda_private {
+	int			tx_room;
+	int			tx_throttled;
+	struct tq_struct	wakeup_task;
+	struct tq_struct	unthrottle_task;
+};
+
+#define KEYSPAN_VENDOR_ID		0x06cd
+#define KEYSPAN_PDA_FAKE_ID		0x0103
+#define KEYSPAN_PDA_ID			0x0104 /* no clue */
+
+/* All of the device info needed for the Keyspan PDA serial converter */
+static __u16	keyspan_vendor_id		= KEYSPAN_VENDOR_ID;
+static __u16	keyspan_pda_fake_product_id	= KEYSPAN_PDA_FAKE_ID;
+static __u16	keyspan_pda_product_id		= KEYSPAN_PDA_ID;
+
+
+
+static void keyspan_pda_wakeup_write( struct usb_serial_port *port )
+{
+
+	struct tty_struct *tty = port->tty;
+
+	/* wake up port processes */
+	wake_up_interruptible( &port->write_wait );
+
+	/* wake up line discipline */
+	if( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+	&& tty->ldisc.write_wakeup )
+		(tty->ldisc.write_wakeup)(tty);
+
+	/* wake up other tty processes */
+	wake_up_interruptible( &tty->write_wait );
+	/* For 2.2.16 backport -- wake_up_interruptible( &tty->poll_wait ); */
+
+}
+
+static void keyspan_pda_request_unthrottle( struct usb_serial *serial )
+{
+
+	dbg(" request_unthrottle");
+	/* ask the device to tell us when the tx buffer becomes
+	   sufficiently empty */
+	usb_control_msg(serial->dev, 
+			     usb_sndctrlpipe(serial->dev, 0),
+			     7, /* request_unthrottle */
+			     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+			     | USB_DIR_OUT,
+			     16, /* value: threshold */
+			     0, /* index */
+			     NULL,
+			     0,
+			     2*HZ);
+
+}
+
+
+static void keyspan_pda_rx_interrupt (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+       	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int i;
+	struct keyspan_pda_private *priv;
+	priv = (struct keyspan_pda_private *)(port->private);
+
+	/* the urb might have been killed. */
+	if (urb->status)
+		return;
+	
+	if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+		return;
+	}
+	
+ 	/* see if the message is data or a status interrupt */
+	switch (data[0]) {
+	case 0:
+		/* rest of message is rx data */
+		if (urb->actual_length) {
+			tty = serial->port[0].tty;
+			for (i = 1; i < urb->actual_length ; ++i) {
+				tty_insert_flip_char(tty, data[i], 0);
+			}
+			tty_flip_buffer_push(tty);
+		}
+		break;
+	case 1:
+		/* status interrupt */
+		dbg(" rx int, d1=%d, d2=%d", data[1], data[2]);
+		switch (data[1]) {
+		case 1: /* modemline change */
+			break;
+		case 2: /* tx unthrottle interrupt */
+			tty = serial->port[0].tty;
+			priv->tx_throttled = 0;
+			/* queue up a wakeup at scheduler time */
+			queue_task( &priv->wakeup_task, &tq_scheduler );
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	/* INT urbs are automatically re-submitted */
+}
+
+
+static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
+{
+	/* stop receiving characters. We just turn off the URB request, and
+	   let chars pile up in the device. If we're doing hardware
+	   flowcontrol, the device will signal the other end when its buffer
+	   fills up. If we're doing XON/XOFF, this would be a good time to
+	   send an XOFF, although it might make sense to foist that off
+	   upon the device too. */
+
+	dbg("keyspan_pda_rx_throttle port %d", port->number);
+	usb_unlink_urb(port->interrupt_in_urb);
+}
+
+
+static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
+{
+	/* just restart the receive interrupt URB */
+	dbg("keyspan_pda_rx_unthrottle port %d", port->number);
+	if (usb_submit_urb(port->interrupt_in_urb))
+		dbg(" usb_submit_urb(read urb) failed");
+	return;
+}
+
+
+static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+{
+	int rc;
+	int bindex;
+
+	switch(baud) {
+		case 110: bindex = 0; break;
+		case 300: bindex = 1; break;
+		case 1200: bindex = 2; break;
+		case 2400: bindex = 3; break;
+		case 4800: bindex = 4; break;
+		case 9600: bindex = 5; break;
+		case 19200: bindex = 6; break;
+		case 38400: bindex = 7; break;
+		case 57600: bindex = 8; break;
+		case 115200: bindex = 9; break;
+		default: return -EINVAL;
+	}
+
+	/* rather than figure out how to sleep while waiting for this
+	   to complete, I just use the "legacy" API. */
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     0, /* set baud */
+			     USB_TYPE_VENDOR 
+			     | USB_RECIP_INTERFACE
+			     | USB_DIR_OUT, /* type */
+			     bindex, /* value */
+			     0, /* index */
+			     NULL, /* &data */
+			     0, /* size */
+			     2*HZ); /* timeout */
+	return(rc);
+}
+
+
+static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state)
+{
+	struct usb_serial *serial = port->serial;
+	int value;
+	if (break_state == -1)
+		value = 1; /* start break */
+	else
+		value = 0; /* clear break */
+	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			4, /* set break */
+			USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			value, 0, NULL, 0, 2*HZ);
+	/* there is something funky about this.. the TCSBRK that 'cu' performs
+	   ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4
+	   seconds apart, but it feels like the break sent isn't as long as it
+	   is on /dev/ttyS0 */
+}
+
+
+static void keyspan_pda_set_termios (struct usb_serial_port *port, 
+				     struct termios *old_termios)
+{
+	struct usb_serial *serial = port->serial;
+	unsigned int cflag = port->tty->termios->c_cflag;
+
+	/* cflag specifies lots of stuff: number of stop bits, parity, number
+	   of data bits, baud. What can the device actually handle?:
+	   CSTOPB (1 stop bit or 2)
+	   PARENB (parity)
+	   CSIZE (5bit .. 8bit)
+	   There is minimal hw support for parity (a PSW bit seems to hold the
+	   parity of whatever is in the accumulator). The UART either deals
+	   with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data,
+	   1 special, stop). So, with firmware changes, we could do:
+	   8N1: 10 bit
+	   8N2: 11 bit, extra bit always (mark?)
+	   8[EOMS]1: 11 bit, extra bit is parity
+	   7[EOMS]1: 10 bit, b0/b7 is parity
+	   7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
+
+	   HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
+	   bit.
+
+	   For now, just do baud. */
+
+	switch (cflag & CBAUD) {
+		/* we could support more values here, just need to calculate
+		   the necessary divisors in the firmware. <asm/termbits.h>
+		   has the Bnnn constants. */
+		case B110: keyspan_pda_setbaud(serial, 110); break;
+		case B300: keyspan_pda_setbaud(serial, 300); break;
+		case B1200: keyspan_pda_setbaud(serial, 1200); break;
+		case B2400: keyspan_pda_setbaud(serial, 2400); break;
+		case B4800: keyspan_pda_setbaud(serial, 4800); break;
+		case B9600: keyspan_pda_setbaud(serial, 9600); break;
+		case B19200: keyspan_pda_setbaud(serial, 19200); break;
+		case B38400: keyspan_pda_setbaud(serial, 38400); break;
+		case B57600: keyspan_pda_setbaud(serial, 57600); break;
+		case B115200: keyspan_pda_setbaud(serial, 115200); break;
+		default: dbg("can't handle requested baud rate"); break;
+	}
+}
+
+
+/* modem control pins: DTR and RTS are outputs and can be controlled.
+   DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be
+   read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */
+
+static int keyspan_pda_get_modem_info(struct usb_serial *serial,
+				      unsigned char *value)
+{
+	int rc;
+	unsigned char data;
+	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     3, /* get pins */
+			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
+			     0, 0, &data, 1, 2*HZ);
+	if (rc > 0)
+		*value = data;
+	return rc;
+}
+
+
+static int keyspan_pda_set_modem_info(struct usb_serial *serial,
+				      unsigned char value)
+{
+	int rc;
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     3, /* set pins */
+			     USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT,
+			     value, 0, NULL, 0, 2*HZ);
+	return rc;
+}
+
+
+static int keyspan_pda_ioctl(struct usb_serial_port *port, struct file *file,
+			     unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial *serial = port->serial;
+	int rc;
+	unsigned int value;
+	unsigned char status, mask;
+
+	switch (cmd) {
+	case TIOCMGET: /* get modem pins state */
+		rc = keyspan_pda_get_modem_info(serial, &status);
+		if (rc < 0)
+			return rc;
+		value =
+			((status & (1<<7)) ? TIOCM_DTR : 0) |
+			((status & (1<<6)) ? TIOCM_CAR : 0) |
+			((status & (1<<5)) ? TIOCM_RNG : 0) |
+			((status & (1<<4)) ? TIOCM_DSR : 0) |
+			((status & (1<<3)) ? TIOCM_CTS : 0) |
+			((status & (1<<2)) ? TIOCM_RTS : 0);
+		if (copy_to_user((unsigned int *)arg, &value, sizeof(int)))
+			return -EFAULT;
+		return 0;
+	case TIOCMSET: /* set a state as returned by MGET */
+		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+			return -EFAULT;
+		status =
+			((value & TIOCM_DTR) ? (1<<7) : 0) |
+			((value & TIOCM_CAR) ? (1<<6) : 0) |
+			((value & TIOCM_RNG) ? (1<<5) : 0) |
+			((value & TIOCM_DSR) ? (1<<4) : 0) |
+			((value & TIOCM_CTS) ? (1<<3) : 0) |
+			((value & TIOCM_RTS) ? (1<<2) : 0);
+		rc = keyspan_pda_set_modem_info(serial, status);
+		if (rc < 0)
+			return rc;
+		return 0;
+	case TIOCMBIS: /* set bits in bitmask <arg> */
+	case TIOCMBIC: /* clear bits from bitmask <arg> */
+		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))
+			return -EFAULT;
+		rc = keyspan_pda_get_modem_info(serial, &status);
+		if (rc < 0)
+			return rc;
+		mask =
+			((value & TIOCM_RTS) ? (1<<2) : 0) |
+			((value & TIOCM_DTR) ? (1<<7) : 0);
+		if (cmd == TIOCMBIS)
+			status |= mask;
+		else
+			status &= ~mask;
+		rc = keyspan_pda_set_modem_info(serial, status);
+		if (rc < 0)
+			return rc;
+		return 0;
+	case TIOCMIWAIT:
+		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+		/* TODO */
+	case TIOCGICOUNT:
+		/* return count of modemline transitions */
+		return 0; /* TODO */
+	}
+	
+	return -ENOIOCTLCMD;
+}
+
+static int keyspan_pda_write(struct usb_serial_port *port, int from_user, 
+			     const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+	int request_unthrottle = 0;
+	int rc = 0;
+	struct keyspan_pda_private *priv;
+
+	priv = (struct keyspan_pda_private *)(port->private);
+	/* guess how much room is left in the device's ring buffer, and if we
+	   want to send more than that, check first, updating our notion of
+	   what is left. If our write will result in no room left, ask the
+	   device to give us an interrupt when the room available rises above
+	   a threshold, and hold off all writers (eventually, those using
+	   select() or poll() too) until we receive that unthrottle interrupt.
+	   Block if we can't write anything at all, otherwise write as much as
+	   we can. */
+	dbg("keyspan_pda_write(%d)",count);
+	if (count == 0) {
+		dbg(" write request of 0 bytes");
+		return (0);
+	}
+
+	/* we might block because of:
+	   the TX urb is in-flight (wait until it completes)
+	   the device is full (wait until it says there is room)
+	*/
+	if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) {
+		return( 0 );
+	}
+
+	/* At this point the URB is in our control, nobody else can submit it
+	   again (the only sudden transition was the one from EINPROGRESS to
+	   finished).  Also, the tx process is not throttled. So we are
+	   ready to write. */
+
+	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+	/* Check if we might overrun the Tx buffer.   If so, ask the
+	   device how much room it really has.  This is done only on
+	   scheduler time, since usb_control_msg() sleeps. */
+	if (count > priv->tx_room && !in_interrupt()) {
+		unsigned char room;
+		rc = usb_control_msg(serial->dev, 
+				     usb_rcvctrlpipe(serial->dev, 0),
+				     6, /* write_room */
+				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+				     | USB_DIR_IN,
+				     0, /* value: 0 means "remaining room" */
+				     0, /* index */
+				     &room,
+				     1,
+				     2*HZ);
+		if (rc < 0) {
+			dbg(" roomquery failed");
+			return rc; /* failed */
+		}
+		if (rc == 0) {
+			dbg(" roomquery returned 0 bytes");
+			return -EIO; /* device didn't return any data */
+		}
+		dbg(" roomquery says %d", room);
+		priv->tx_room = room;
+	}
+	if (count > priv->tx_room) {
+		/* we're about to completely fill the Tx buffer, so
+		   we'll be throttled afterwards. */
+		count = priv->tx_room;
+		request_unthrottle = 1;
+	}
+
+	if (count) {
+		/* now transfer data */
+		if (from_user) {
+			if( copy_from_user(port->write_urb->transfer_buffer,
+			buf, count) )
+				return( -EFAULT );
+		}
+		else {
+			memcpy (port->write_urb->transfer_buffer, buf, count);
+		}  
+		/* send the data out the bulk port */
+		port->write_urb->transfer_buffer_length = count;
+		
+		priv->tx_room -= count;
+
+		if (usb_submit_urb(port->write_urb))
+			dbg(" usb_submit_urb(write bulk) failed");
+	}
+	else {
+		/* There wasn't any room left, so we are throttled until
+		   the buffer empties a bit */
+		request_unthrottle = 1;
+	}
+
+	if (request_unthrottle) {
+		priv->tx_throttled = 1; /* block writers */
+		queue_task( &priv->unthrottle_task, &tq_scheduler );
+	}
+
+	return (count);
+}
+
+
+static void keyspan_pda_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial;
+	struct keyspan_pda_private *priv;
+
+	priv = (struct keyspan_pda_private *)(port->private);
+
+	if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {
+		return;
+	}
+	
+	/* queue up a wakeup at scheduler time */
+	queue_task( &priv->wakeup_task, &tq_scheduler );
+
+}
+
+
+static int keyspan_pda_write_room (struct usb_serial_port *port)
+{
+	struct keyspan_pda_private *priv;
+	priv = (struct keyspan_pda_private *)(port->private);
+
+	/* used by n_tty.c for processing of tabs and such. Giving it our
+	   conservative guess is probably good enough, but needs testing by
+	   running a console through the device. */
+
+	return (priv->tx_room);
+}
+
+
+static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
+{
+	struct keyspan_pda_private *priv;
+	priv = (struct keyspan_pda_private *)(port->private);
+	
+	/* when throttled, return at least WAKEUP_CHARS to tell select() (via
+	   n_tty.c:normal_poll() ) that we're not writeable. */
+	if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled )
+		return 256;
+	return 0;
+}
+
+
+static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+	unsigned char room;
+	int rc;
+	struct keyspan_pda_private *priv;
+	priv = (struct keyspan_pda_private *)(port->private);
+
+	if (port->active) {
+		return -EINVAL;
+	}
+	port->active = 1;
+ 
+	/* find out how much room is in the Tx ring */
+	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     6, /* write_room */
+			     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+			     | USB_DIR_IN,
+			     0, /* value */
+			     0, /* index */
+			     &room,
+			     1,
+			     2*HZ);
+	if (rc < 0) {
+		dbg(" roomquery failed");
+		return rc; /* failed */
+	}
+	if (rc == 0) {
+		dbg(" roomquery returned 0 bytes");
+		return -EIO; /* device didn't return any data */
+	}
+	priv->tx_room = room;
+	priv->tx_throttled = room ? 0 : 1;
+
+	/* the normal serial device seems to always turn on DTR and RTS here,
+	   so do the same */
+	if (port->tty->termios->c_cflag & CBAUD)
+		keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
+	else
+		keyspan_pda_set_modem_info(serial, 0);
+
+	/*Start reading from the device*/
+	if (usb_submit_urb(port->interrupt_in_urb))
+		dbg(" usb_submit_urb(read int) failed");
+
+	return (0);
+}
+
+
+static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+
+	/* the normal serial device seems to always shut off DTR and RTS now */
+	if (port->tty->termios->c_cflag & HUPCL)
+		keyspan_pda_set_modem_info(serial, 0);
+
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->interrupt_in_urb);
+	port->active = 0;
+}
+
+
+/* download the firmware to a "fake" device (pre-renumeration) */
+static int keyspan_pda_fake_startup (struct usb_serial *serial)
+{
+	int response;
+	const struct ezusb_hex_record *record;
+
+	/* download the firmware here ... */
+	response = ezusb_set_reset(serial, 1);
+
+	record = &keyspan_pda_firmware[0];
+	while(record->address != 0xffff) {
+		response = ezusb_writememory(serial, record->address,
+					     (unsigned char *)record->data,
+					     record->data_size, 0xa0);
+		if (response < 0) {
+			err("ezusb_writememory failed for Keyspan PDA "
+			    "firmware (%d %04X %p %d)",
+			    response, 
+			    record->address, record->data, record->data_size);
+			break;
+		}
+		record++;
+	}
+	/* bring device out of reset. Renumeration will occur in a moment
+	   and the new device will bind to the real driver */
+	response = ezusb_set_reset(serial, 0);
+
+	/* we want this device to fail to have a driver assigned to it. */
+	return (1);
+}
+
+static int keyspan_pda_startup (struct usb_serial *serial)
+{
+
+	struct keyspan_pda_private *priv;
+
+	/* allocate the private data structures for all ports. Well, for all
+	   one ports. */
+
+	priv = serial->port[0].private
+		= kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL);
+	if (!priv)
+		return (1); /* error */
+	init_waitqueue_head(&serial->port[0].write_wait);
+	priv->wakeup_task.next = NULL;
+	priv->wakeup_task.sync = 0;
+	priv->wakeup_task.routine = (void *)keyspan_pda_wakeup_write;
+	priv->wakeup_task.data = (void *)(&serial->port[0]);
+	priv->unthrottle_task.next = NULL;
+	priv->unthrottle_task.sync = 0;
+	priv->unthrottle_task.routine = (void *)keyspan_pda_request_unthrottle;
+	priv->unthrottle_task.data = (void *)(serial);
+	return (0);
+}
+
+static void keyspan_pda_shutdown (struct usb_serial *serial)
+{
+	kfree(serial->port[0].private);
+}
+
+struct usb_serial_device_type keyspan_pda_fake_device = {
+	name:			"Keyspan PDA - (prerenumeration)",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_pda_fake_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	startup:		keyspan_pda_fake_startup,
+};
+
+struct usb_serial_device_type keyspan_pda_device = {
+	name:			"Keyspan PDA",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_pda_product_id,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		0,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			keyspan_pda_open,
+	close:			keyspan_pda_close,
+	write:			keyspan_pda_write,
+	write_room:		keyspan_pda_write_room,
+	write_bulk_callback: 	keyspan_pda_write_bulk_callback,
+	read_int_callback:	keyspan_pda_rx_interrupt,
+	chars_in_buffer:	keyspan_pda_chars_in_buffer,
+	throttle:		keyspan_pda_rx_throttle,
+	unthrottle:		keyspan_pda_rx_unthrottle,
+	ioctl:			keyspan_pda_ioctl,
+	set_termios:		keyspan_pda_set_termios,
+	break_ctl:		keyspan_pda_break_ctl,
+	startup:		keyspan_pda_startup,
+	shutdown:		keyspan_pda_shutdown,
+};
+
+
+int keyspan_pda_init (void)
+{
+	usb_serial_register (&keyspan_pda_fake_device);
+	usb_serial_register (&keyspan_pda_device);
+	return 0;
+}
+
+
+void keyspan_pda_exit (void)
+{
+	usb_serial_deregister (&keyspan_pda_fake_device);
+	usb_serial_deregister (&keyspan_pda_device);
+}
+
+
+module_init(keyspan_pda_init);
+module_exit(keyspan_pda_exit);
+
+MODULE_AUTHOR("Brian Warner <warner@lothar.com>");
+MODULE_DESCRIPTION("USB Keyspan PDA Converter driver");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_pda_fw.h linux.18p8/drivers/usb/serial/keyspan_pda_fw.h
--- linux.vanilla/drivers/usb/serial/keyspan_pda_fw.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_pda_fw.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,93 @@
+/*
+ * keyspan_pda_fw.h
+ *
+ * Generated from keyspan_pda.s by ezusb_convert.pl
+ * This file is presumed to be under the same copyright as the source file
+ * from which it was derived.
+ */
+
+static const struct ezusb_hex_record keyspan_pda_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x02, 0x00} },
+{ 0x0023,	4,	{0x02, 0x05, 0x5f, 0x00} },
+{ 0x0043,	4,	{0x02, 0x01, 0x00, 0x00} },
+{ 0x0030,	5,	{0x00, 0x00, 0x00, 0x00, 0x00} },
+{ 0x0100,	16,	{0x02, 0x02, 0x96, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00} },
+{ 0x0110,	16,	{0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00} },
+{ 0x0120,	16,	{0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x04, 0x61, 0x00, 0x02, 0x04, 0x89, 0x00} },
+{ 0x0200,	16,	{0x75, 0x81, 0x5e, 0xe4, 0xf5, 0x32, 0xf5, 0x33, 0xf5, 0x30, 0xf5, 0x31, 0xf5, 0x34, 0xc2, 0x00} },
+{ 0x0210,	16,	{0xc2, 0x01, 0xa9, 0x00, 0x74, 0xfe, 0x90, 0x10, 0x00, 0xf0, 0xa3, 0xd9, 0xfc, 0x74, 0xfd, 0x90} },
+{ 0x0220,	16,	{0x11, 0x00, 0xf0, 0xa3, 0xd9, 0xfc, 0x74, 0x02, 0x90, 0x7f, 0x9d, 0xf0, 0x74, 0x00, 0x90, 0x7f} },
+{ 0x0230,	16,	{0x97, 0xf0, 0x74, 0x86, 0x90, 0x7f, 0x9e, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0x03, 0xf0, 0x90, 0x7f} },
+{ 0x0240,	16,	{0xaf, 0xe0, 0xd2, 0xe0, 0xf0, 0x74, 0x01, 0x90, 0x7f, 0xab, 0xf0, 0x90, 0x7f, 0xae, 0xf0, 0x90} },
+{ 0x0250,	16,	{0x7f, 0xac, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xad, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x74} },
+{ 0x0260,	16,	{0x84, 0x90, 0x7f, 0x98, 0xf0, 0x74, 0x00, 0xf5, 0x98, 0x75, 0xc8, 0x30, 0x7b, 0x05, 0x91, 0x20} },
+{ 0x0270,	16,	{0xd2, 0xca, 0x75, 0x98, 0x50, 0xd2, 0xe8, 0xd2, 0xaf, 0xd2, 0xac, 0x74, 0x00, 0xf5, 0x86, 0x90} },
+{ 0x0280,	16,	{0x7f, 0xd6, 0x74, 0x02, 0xf0, 0x79, 0x2e, 0x7a, 0x00, 0x7b, 0x00, 0xdb, 0xfe, 0xda, 0xfa, 0xd9} },
+{ 0x0290,	16,	{0xf6, 0x74, 0x06, 0xf0, 0x80, 0xfe, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x84, 0xc0, 0x85} },
+{ 0x02a0,	16,	{0xc0, 0xe0, 0xe5, 0x91, 0xc2, 0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0x90, 0x7f} },
+{ 0x02b0,	16,	{0xe8, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb, 0xa3, 0xe0, 0xfc, 0xe9, 0x54, 0x60, 0xb4} },
+{ 0x02c0,	16,	{0x00, 0x03, 0x02, 0x03, 0x39, 0xb4, 0x40, 0x6e, 0xba, 0x00, 0x0b, 0x12, 0x04, 0x20, 0x40, 0x03} },
+{ 0x02d0,	16,	{0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0xba, 0x01, 0x03, 0x02, 0x04, 0x0a, 0xba, 0x02, 0x03, 0x02} },
+{ 0x02e0,	16,	{0x04, 0x0a, 0xba, 0x03, 0x03, 0x02, 0x04, 0x44, 0xba, 0x04, 0x1e, 0xbb, 0x00, 0x0a, 0x90, 0x7f} },
+{ 0x02f0,	16,	{0x95, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x04, 0x02, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfd, 0xf0, 0x90} },
+{ 0x0300,	16,	{0x7f, 0x95, 0xe0, 0x54, 0xfd, 0xf0, 0x02, 0x04, 0x02, 0xba, 0x05, 0x03, 0x02, 0x04, 0x0a, 0xba} },
+{ 0x0310,	16,	{0x06, 0x19, 0xbb, 0x00, 0x08, 0xe5, 0x33, 0xd3, 0x95, 0x32, 0x02, 0x03, 0xde, 0xbb, 0x01, 0x08} },
+{ 0x0320,	16,	{0xe5, 0x32, 0xc3, 0x95, 0x33, 0x02, 0x03, 0xde, 0x02, 0x04, 0x0a, 0xba, 0x07, 0x05, 0x8b, 0x34} },
+{ 0x0330,	16,	{0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0x02, 0x04, 0x0a, 0xba, 0x00, 0x20, 0xb9, 0x80, 0x10, 0x90} },
+{ 0x0340,	16,	{0x7f, 0x00, 0xe4, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x04, 0x02, 0xb9} },
+{ 0x0350,	16,	{0x82, 0x02, 0x80, 0xeb, 0xb9, 0x81, 0x02, 0x80, 0xe6, 0x02, 0x04, 0x0a, 0xba, 0x01, 0x0f, 0xbb} },
+{ 0x0360,	16,	{0x00, 0x03, 0x02, 0x04, 0x0a, 0xbb, 0x01, 0x03, 0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0xba, 0x03} },
+{ 0x0370,	16,	{0x0f, 0xbb, 0x00, 0x03, 0x02, 0x04, 0x0a, 0xbb, 0x01, 0x03, 0x02, 0x04, 0x02, 0x02, 0x04, 0x0a} },
+{ 0x0380,	16,	{0xba, 0x06, 0x56, 0xbc, 0x01, 0x0f, 0x90, 0x7f, 0xd4, 0x74, 0x06, 0xf0, 0x90, 0x7f, 0xd5, 0x74} },
+{ 0x0390,	16,	{0x12, 0xf0, 0x02, 0x04, 0x02, 0xbc, 0x02, 0x12, 0xbb, 0x00, 0x6f, 0x90, 0x7f, 0xd4, 0x74, 0x06} },
+{ 0x03a0,	16,	{0xf0, 0x90, 0x7f, 0xd5, 0x74, 0x24, 0xf0, 0x02, 0x04, 0x02, 0xbc, 0x03, 0x29, 0x74, 0x04, 0xc3} },
+{ 0x03b0,	16,	{0x9b, 0x40, 0x57, 0x60, 0x55, 0xeb, 0x2b, 0x90, 0x06, 0x44, 0x25, 0x82, 0xf5, 0x82, 0x74, 0x00} },
+{ 0x03c0,	16,	{0x35, 0x83, 0xf5, 0x83, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0x90, 0x7f, 0xd4, 0xe9, 0xf0, 0x90, 0x7f} },
+{ 0x03d0,	16,	{0xd5, 0xea, 0xf0, 0x02, 0x04, 0x02, 0x02, 0x04, 0x0a, 0xba, 0x08, 0x0f, 0x74, 0x01, 0x90, 0x7f} },
+{ 0x03e0,	16,	{0x00, 0xf0, 0x74, 0x01, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x04, 0x02, 0xba, 0x09, 0x03, 0x02, 0x04} },
+{ 0x03f0,	16,	{0x02, 0xba, 0x0a, 0x05, 0x74, 0x00, 0x02, 0x03, 0xde, 0xba, 0x0b, 0x03, 0x02, 0x04, 0x02, 0x02} },
+{ 0x0400,	16,	{0x04, 0x0a, 0x90, 0x7f, 0xb4, 0x74, 0x02, 0xf0, 0x80, 0x09, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x0410,	16,	{0xf0, 0x80, 0x00, 0xd0, 0xe0, 0xd0, 0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32} },
+{ 0x0420,	16,	{0xeb, 0x20, 0xe7, 0x1e, 0xc3, 0x94, 0x0a, 0x50, 0x19, 0xeb, 0x23, 0x24, 0xfe, 0xf5, 0x82, 0x74} },
+{ 0x0430,	16,	{0x05, 0x34, 0x00, 0xf5, 0x83, 0xe0, 0xf5, 0xcb, 0xf5, 0xcd, 0xa3, 0xe0, 0xf5, 0xca, 0xf5, 0xcc} },
+{ 0x0440,	16,	{0xc3, 0x22, 0xd3, 0x22, 0xb9, 0x41, 0x11, 0xeb, 0x64, 0xff, 0x54, 0x84, 0xfb, 0x90, 0x7f, 0x98} },
+{ 0x0450,	16,	{0xe0, 0x54, 0x7b, 0x4b, 0xf0, 0x02, 0x04, 0x02, 0x90, 0x7f, 0x9b, 0xe0, 0x64, 0xff, 0x02, 0x03} },
+{ 0x0460,	16,	{0xde, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x84, 0xc0, 0x85, 0xc0, 0xe0, 0xe5, 0x91, 0xc2} },
+{ 0x0470,	16,	{0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xa9, 0x74, 0x04, 0xf0, 0x12, 0x05, 0xa0, 0xd0, 0xe0, 0xd0, 0x85} },
+{ 0x0480,	16,	{0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0xc0, 0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0} },
+{ 0x0490,	16,	{0x84, 0xc0, 0x85, 0xc0, 0xe0, 0xe5, 0x91, 0xc2, 0xe4, 0xf5, 0x91, 0x90, 0x7f, 0xaa, 0x74, 0x04} },
+{ 0x04a0,	16,	{0xf0, 0x90, 0x7f, 0xc9, 0xe0, 0xf9, 0xe4, 0xf5, 0x86, 0x90, 0x7d, 0xc0, 0x75, 0x85, 0x10, 0x85} },
+{ 0x04b0,	16,	{0x32, 0x84, 0xe0, 0x05, 0x86, 0x05, 0x84, 0xf0, 0xe5, 0x84, 0xb5, 0x33, 0x02, 0x80, 0x09, 0x05} },
+{ 0x04c0,	16,	{0x32, 0x05, 0x86, 0xa3, 0xd9, 0xec, 0x80, 0x00, 0x90, 0x7f, 0xc9, 0xf0, 0xb1, 0x31, 0xd0, 0xe0} },
+{ 0x04d0,	16,	{0xd0, 0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0xe4, 0xf5, 0x86, 0x90, 0x7f} },
+{ 0x04e0,	16,	{0xbc, 0xe0, 0x20, 0xe1, 0x4b, 0x90, 0x7d, 0x00, 0xe5, 0x32, 0xf0, 0xa3, 0xe5, 0x33, 0xf0, 0xa3} },
+{ 0x04f0,	16,	{0xe5, 0x30, 0xf0, 0xa3, 0xe5, 0x31, 0xf0, 0xa3, 0xe4, 0x30, 0x00, 0x01, 0x04, 0xf0, 0xa3, 0x05} },
+{ 0x0500,	16,	{0x86, 0x90, 0x10, 0x00, 0x79, 0x10, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xd9, 0xf6} },
+{ 0x0510,	16,	{0x05, 0x86, 0x74, 0xfc, 0xf0, 0xa3, 0x05, 0x86, 0x90, 0x11, 0x00, 0x79, 0x10, 0xe0, 0xa3, 0x05} },
+{ 0x0520,	16,	{0x86, 0xf0, 0xa3, 0x05, 0x86, 0xd9, 0xf6, 0xe4, 0xf5, 0x86, 0x90, 0x7f, 0xbd, 0x74, 0x26, 0xf0} },
+{ 0x0530,	16,	{0x22, 0x20, 0x00, 0x13, 0xe5, 0x32, 0xb5, 0x33, 0x01, 0x22, 0x05, 0x33, 0x75, 0x83, 0x10, 0x85} },
+{ 0x0540,	16,	{0x33, 0x82, 0xe0, 0xf5, 0x99, 0xd2, 0x00, 0x74, 0x00, 0xb5, 0x34, 0x01, 0x22, 0xe5, 0x33, 0xd3} },
+{ 0x0550,	16,	{0x95, 0x32, 0xc3, 0x95, 0x34, 0x40, 0xf5, 0x75, 0x34, 0x00, 0xd2, 0x01, 0x02, 0x05, 0xa0, 0xc0} },
+{ 0x0560,	16,	{0x86, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x84, 0xc0, 0x85, 0xc0, 0xe0, 0x30, 0x99, 0x07, 0xc2, 0x99} },
+{ 0x0570,	16,	{0xc2, 0x00, 0x12, 0x05, 0x34, 0x30, 0x98, 0x05, 0x12, 0x05, 0x8a, 0xc2, 0x98, 0xd0, 0xe0, 0xd0} },
+{ 0x0580,	16,	{0x85, 0xd0, 0x84, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0x86, 0x32, 0x75, 0x83, 0x11, 0x85, 0x30, 0x82} },
+{ 0x0590,	16,	{0x05, 0x82, 0xe5, 0x99, 0xf0, 0xe5, 0x82, 0xb5, 0x31, 0x01, 0x22, 0x05, 0x30, 0xb1, 0xa0, 0x22} },
+{ 0x05a0,	16,	{0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x38, 0x20, 0x01, 0x36, 0xe5, 0x30, 0xb5, 0x31, 0x01, 0x22} },
+{ 0x05b0,	16,	{0xe4, 0xf5, 0x86, 0x75, 0x83, 0x11, 0x05, 0x86, 0x90, 0x7e, 0x00, 0xf0, 0xa3, 0x05, 0x86, 0x79} },
+{ 0x05c0,	16,	{0x01, 0xe5, 0x30, 0xb5, 0x31, 0x02, 0x80, 0x10, 0x05, 0x31, 0x85, 0x31, 0x82, 0xe0, 0x05, 0x86} },
+{ 0x05d0,	16,	{0xf0, 0xa3, 0x05, 0x86, 0x09, 0xb9, 0x40, 0xe9, 0x90, 0x7f, 0xb9, 0xe9, 0x60, 0x01, 0xf0, 0x22} },
+{ 0x05e0,	16,	{0xc2, 0x01, 0xe4, 0xf5, 0x86, 0x90, 0x7e, 0x00, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x02, 0xf0, 0x90} },
+{ 0x05f0,	16,	{0x7f, 0xb9, 0xf0, 0x22, 0xc2, 0x99, 0xf5, 0x99, 0x30, 0x99, 0xfd, 0xc2, 0x99, 0x22, 0xe5, 0x5e} },
+{ 0x0600,	16,	{0xf6, 0x3c, 0xfd, 0x8f, 0xfe, 0xc8, 0xff, 0x64, 0xff, 0xb2, 0xff, 0xd9, 0xff, 0xed, 0xff, 0xf3} },
+{ 0x0610,	16,	{0xff, 0xfa, 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40, 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab} },
+{ 0x0620,	16,	{0x01, 0x02, 0x03, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00} },
+{ 0x0630,	16,	{0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01, 0x07, 0x05, 0x02} },
+{ 0x0640,	16,	{0x02, 0x40, 0x00, 0x00, 0x06, 0x4c, 0x06, 0x50, 0x06, 0x72, 0x06, 0xa0, 0x04, 0x03, 0x00, 0x00} },
+{ 0x0650,	16,	{0x22, 0x03, 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00} },
+{ 0x0660,	16,	{0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00} },
+{ 0x0670,	16,	{0x73, 0x00, 0x2e, 0x03, 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00} },
+{ 0x0680,	16,	{0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00} },
+{ 0x0690,	16,	{0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00} },
+{ 0x06a0,	6,	{0x06, 0x03, 0x34, 0x00, 0x37, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa18x_fw.h linux.18p8/drivers/usb/serial/keyspan_usa18x_fw.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa18x_fw.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_usa18x_fw.h	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,406 @@
+/* keyspan_usa18x_fw.h
+  
+   Generated from Keyspan firmware image Wed Jul  5 09:18:29 2000 EST
+   This firmware is for the Keyspan USA-18X Serial Adaptor
+
+   "The firmware contained herein as keyspan_usa18x_fw.h is
+   Copyright (C) 1999-2000 Keyspan, A division of InnoSys Incorporated
+   ("Keyspan"), as an unpublished work.  This notice does not imply
+   unrestricted or public access to this firmware which is a trade secret of
+   Keyspan, and which may not be reproduced, used, sold or transferred to any
+   third party without Keyspan's prior written consent.  All Rights Reserved.
+
+   This firmware may not be modified and may only be used with the Keyspan 
+   USA-18X Serial Adapter.  Distribution and/or Modification of the
+   keyspan.c driver which includes this firmware, in whole or in part,
+   requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa18x_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x0e, 0x9b} },
+{ 0x0003,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} },
+{ 0x0013,	16,	{0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90} },
+{ 0x0023,	15,	{0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x07, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x22} },
+{ 0x0033,	3,	{0x02, 0x13, 0xfc} },
+{ 0x0036,	12,	{0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0043,	3,	{0x02, 0x14, 0x00} },
+{ 0x0046,	16,	{0x30, 0x08, 0x13, 0x12, 0x13, 0xc0, 0xef, 0xc3, 0x95, 0x3c, 0x50, 0x73, 0x90, 0x7f, 0xbf, 0x74} },
+{ 0x0056,	16,	{0x01, 0xf0, 0xc2, 0x08, 0x80, 0x69, 0x30, 0x02, 0x34, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x5f} },
+{ 0x0066,	16,	{0x12, 0x13, 0xc0, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x56, 0x90, 0x7e, 0x40, 0xe0, 0x13, 0x92, 0x08} },
+{ 0x0076,	16,	{0x90, 0x7f, 0xc7, 0xe0, 0x14, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d} },
+{ 0x0086,	16,	{0x41, 0x12, 0x0d, 0x55, 0xc2, 0x02, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x32, 0x90, 0x7f, 0xc8} },
+{ 0x0096,	16,	{0xe0, 0x20, 0xe1, 0x2b, 0x12, 0x13, 0xc0, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x22, 0x90, 0x7d, 0xc0} },
+{ 0x00a6,	16,	{0xe0, 0x13, 0x92, 0x08, 0x90, 0x7f, 0xc9, 0xe0, 0x14, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0xc1, 0x75} },
+{ 0x00b6,	16,	{0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0d, 0x55, 0xd2, 0x02, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0x90} },
+{ 0x00c6,	16,	{0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x53, 0x53, 0x36, 0x80, 0x12, 0x13, 0xcc, 0xef} },
+{ 0x00d6,	16,	{0x42, 0x36, 0x12, 0x12, 0x49, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3a, 0x50, 0x0f, 0x12, 0x13, 0xa8} },
+{ 0x00e6,	16,	{0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0a, 0x61, 0xc2, 0x0a, 0xe5, 0x19} },
+{ 0x00f6,	16,	{0x70, 0x04, 0xf5, 0x36, 0x80, 0x57, 0x12, 0x13, 0xcc, 0xef, 0x42, 0x36, 0xe5, 0x36, 0x30, 0xe7} },
+{ 0x0106,	16,	{0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7e} },
+{ 0x0116,	16,	{0x7f, 0x80, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0xb7, 0xe5, 0x19, 0x25} },
+{ 0x0126,	16,	{0xe0, 0x90, 0x7f, 0xb7, 0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19} },
+{ 0x0136,	16,	{0x3f, 0x85, 0x19, 0x08, 0xe4, 0x90, 0x7e, 0x80, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x0c, 0x7e} },
+{ 0x0146,	16,	{0x75, 0x0d, 0x81, 0x12, 0x0d, 0x7a, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90, 0x7f, 0xce} },
+{ 0x0156,	16,	{0xe0, 0x30, 0xe1, 0x06, 0x20, 0x04, 0x03, 0x02, 0x03, 0xbd, 0xc2, 0x04, 0xe4, 0xf5, 0x18, 0x74} },
+{ 0x0166,	16,	{0x40, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00} },
+{ 0x0176,	16,	{0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0c} },
+{ 0x0186,	16,	{0xe5, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68, 0x90, 0x7e} },
+{ 0x0196,	16,	{0x03, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x24, 0x7f, 0x03, 0x7d, 0xcd, 0x12} },
+{ 0x01a6,	16,	{0x12, 0x24, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46} },
+{ 0x01b6,	16,	{0xf0, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x10, 0xa8} },
+{ 0x01c6,	16,	{0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12, 0x10, 0xce, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12} },
+{ 0x01d6,	16,	{0x12, 0x24, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x24, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x01e6,	16,	{0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40} },
+{ 0x01f6,	16,	{0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x13, 0xe0} },
+{ 0x0206,	16,	{0x70, 0x08, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12} },
+{ 0x0216,	16,	{0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x44, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5} },
+{ 0x0226,	16,	{0x44, 0xf0, 0x90, 0x7e, 0x07, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x42, 0x80, 0x80} },
+{ 0x0236,	16,	{0x03, 0x53, 0x42, 0x7f, 0x53, 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x42, 0x02} },
+{ 0x0246,	16,	{0xa3, 0xe0, 0xff, 0x12, 0x11, 0x1a, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x11, 0x40, 0xaf, 0x42} },
+{ 0x0256,	16,	{0x12, 0x10, 0xf4, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42, 0x12, 0x10} },
+{ 0x0266,	16,	{0xf4, 0x90, 0x7e, 0x0c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x02, 0x80, 0x03} },
+{ 0x0276,	16,	{0x53, 0x46, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90} },
+{ 0x0286,	16,	{0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03, 0x53, 0x46} },
+{ 0x0296,	16,	{0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x12} },
+{ 0x02a6,	16,	{0xe0, 0xf5, 0x3a, 0xa3, 0xe0, 0x13, 0x92, 0x0c, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3, 0xe0, 0x60, 0x05} },
+{ 0x02b6,	16,	{0x43, 0x46, 0x10, 0x80, 0x03, 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0} },
+{ 0x02c6,	16,	{0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90, 0x7f, 0x98} },
+{ 0x02d6,	16,	{0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11} },
+{ 0x02e6,	16,	{0xf0, 0x12, 0x13, 0x9c, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e, 0xfd, 0xe4, 0xff} },
+{ 0x02f6,	16,	{0xad, 0x3e, 0x12, 0x12, 0x24, 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x06, 0x90, 0x7e, 0x17, 0xe0} },
+{ 0x0306,	16,	{0x60, 0x0f, 0x43, 0x3e, 0x02, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x12, 0x24, 0x75, 0x29, 0x01, 0xd2} },
+{ 0x0316,	16,	{0x06, 0x90, 0x7e, 0x18, 0xe0, 0x60, 0x1b, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44} },
+{ 0x0326,	16,	{0x04, 0x90, 0xc0, 0x00, 0xf0, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x02} },
+{ 0x0336,	16,	{0xc2, 0x08, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11, 0x43, 0x44, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x13} },
+{ 0x0346,	16,	{0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f, 0x53} },
+{ 0x0356,	16,	{0x3e, 0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x12, 0x24, 0x75, 0x2b, 0x01, 0xd2, 0x06, 0x90, 0x7e} },
+{ 0x0366,	16,	{0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x12, 0x24, 0xe4, 0xf5} },
+{ 0x0376,	16,	{0x2b, 0xd2, 0x06, 0x90, 0x7e, 0x1c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5} },
+{ 0x0386,	16,	{0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x0a, 0x90} },
+{ 0x0396,	16,	{0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4, 0xf5, 0x38, 0xd2, 0x06, 0x90, 0x7e, 0x1f} },
+{ 0x03a6,	16,	{0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0, 0x74} },
+{ 0x03b6,	16,	{0x35, 0xf0, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30, 0x18, 0x52, 0xe5, 0x38, 0x60, 0x02, 0x15, 0x38} },
+{ 0x03c6,	16,	{0x20, 0x12, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e, 0x75, 0x13} },
+{ 0x03d6,	16,	{0x0a, 0x30, 0x19, 0x02, 0xd2, 0x12, 0x12, 0x13, 0x9c, 0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x2a} },
+{ 0x03e6,	16,	{0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x06, 0x12, 0x13, 0xd8, 0xef, 0x54, 0x80, 0xf5, 0x19, 0x65} },
+{ 0x03f6,	16,	{0x26, 0x60, 0x05, 0x85, 0x19, 0x26, 0xd2, 0x06, 0x30, 0x0c, 0x11, 0x12, 0x13, 0xd8, 0xef, 0x54} },
+{ 0x0406,	16,	{0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05, 0x85, 0x19, 0x25, 0xd2, 0x06, 0x20, 0x19, 0x03, 0x02} },
+{ 0x0416,	16,	{0x07, 0xe4, 0x30, 0x09, 0x13, 0x12, 0x14, 0x2b, 0xef, 0xc3, 0x95, 0x3d, 0x50, 0x73, 0x90, 0x7f} },
+{ 0x0426,	16,	{0xc1, 0x74, 0x01, 0xf0, 0xc2, 0x09, 0x80, 0x69, 0x30, 0x03, 0x34, 0x90, 0x7f, 0xca, 0xe0, 0x20} },
+{ 0x0436,	16,	{0xe1, 0x5f, 0x12, 0x14, 0x2b, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x56, 0x90, 0x7d, 0x40, 0xe0, 0x13} },
+{ 0x0446,	16,	{0x92, 0x09, 0x90, 0x7f, 0xcb, 0xe0, 0x14, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0x41, 0x75, 0x0c, 0x7d} },
+{ 0x0456,	16,	{0x75, 0x0d, 0x41, 0x12, 0x0d, 0x9f, 0xc2, 0x03, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x32, 0x90} },
+{ 0x0466,	16,	{0x7f, 0xcc, 0xe0, 0x20, 0xe1, 0x2b, 0x12, 0x14, 0x2b, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x22, 0x90} },
+{ 0x0476,	16,	{0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x09, 0x90, 0x7f, 0xcd, 0xe0, 0x14, 0xf5, 0x08, 0x7e, 0x7c, 0x7f} },
+{ 0x0486,	16,	{0xc1, 0x75, 0x0c, 0x7c, 0x75, 0x0d, 0xc1, 0x12, 0x0d, 0x9f, 0xd2, 0x03, 0xe4, 0x90, 0x7f, 0xcd} },
+{ 0x0496,	16,	{0xf0, 0x90, 0x7f, 0xba, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x05, 0x25, 0x53, 0x37, 0x80, 0x12, 0x14} },
+{ 0x04a6,	16,	{0x37, 0xef, 0x42, 0x37, 0x12, 0x12, 0x93, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3b, 0x50, 0x0f, 0x12} },
+{ 0x04b6,	16,	{0x14, 0x13, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x37, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x61, 0xc2, 0x0b} },
+{ 0x04c6,	16,	{0xe5, 0x19, 0x70, 0x04, 0xf5, 0x37, 0x80, 0x57, 0x12, 0x14, 0x37, 0xef, 0x42, 0x37, 0xe5, 0x37} },
+{ 0x04d6,	16,	{0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08} },
+{ 0x04e6,	16,	{0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f, 0xf0, 0xe5} },
+{ 0x04f6,	16,	{0x19, 0x25, 0xe0, 0x90, 0x7f, 0xbb, 0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03} },
+{ 0x0506,	16,	{0x75, 0x19, 0x3f, 0x85, 0x19, 0x08, 0xe4, 0x90, 0x7d, 0x80, 0xf0, 0x7e, 0x7d, 0x7f, 0x81, 0x75} },
+{ 0x0516,	16,	{0x0c, 0x7d, 0x75, 0x0d, 0x81, 0x12, 0x0d, 0xc4, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb, 0xf0, 0x90} },
+{ 0x0526,	16,	{0x7f, 0xd0, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x05, 0x03, 0x02, 0x07, 0x8f, 0xc2, 0x05, 0xe4, 0xf5} },
+{ 0x0536,	16,	{0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18} },
+{ 0x0546,	16,	{0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef} },
+{ 0x0556,	16,	{0x12, 0x0c, 0xe5, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68} },
+{ 0x0566,	16,	{0x90, 0x7e, 0x23, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x6e, 0x7f, 0x03, 0x7d} },
+{ 0x0576,	16,	{0xcd, 0x12, 0x12, 0x6e, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00} },
+{ 0x0586,	16,	{0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12} },
+{ 0x0596,	16,	{0x11, 0x8c, 0x90, 0x7e, 0x22, 0xe0, 0xff, 0x12, 0x11, 0xb2, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0} },
+{ 0x05a6,	16,	{0xfd, 0x12, 0x12, 0x6e, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x6e, 0x43, 0x47, 0x80, 0x90, 0x7f} },
+{ 0x05b6,	16,	{0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0} },
+{ 0x05c6,	16,	{0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e} },
+{ 0x05d6,	16,	{0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0} },
+{ 0x05e6,	16,	{0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0} },
+{ 0x05f6,	16,	{0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e, 0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43} },
+{ 0x0606,	16,	{0x80, 0x80, 0x03, 0x53, 0x43, 0x7f, 0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43} },
+{ 0x0616,	16,	{0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x11, 0xd8, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0xfe} },
+{ 0x0626,	16,	{0xaf, 0x43, 0x12, 0x11, 0x66, 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf, 0x43} },
+{ 0x0636,	16,	{0x12, 0x11, 0x66, 0x90, 0x7e, 0x2c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02} },
+{ 0x0646,	16,	{0x80, 0x03, 0x53, 0x47, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47} },
+{ 0x0656,	16,	{0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03} },
+{ 0x0666,	16,	{0x53, 0x47, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90} },
+{ 0x0676,	16,	{0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3, 0xe0, 0x13, 0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0} },
+{ 0x0686,	16,	{0x60, 0x05, 0x43, 0x47, 0x10, 0x80, 0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0} },
+{ 0x0696,	16,	{0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90} },
+{ 0x06a6,	16,	{0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98} },
+{ 0x06b6,	16,	{0x74, 0x09, 0xf0, 0x12, 0x13, 0xf0, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd} },
+{ 0x06c6,	16,	{0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x6e, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x07, 0x90, 0x7e} },
+{ 0x06d6,	16,	{0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x6e, 0x75, 0x32} },
+{ 0x06e6,	16,	{0x01, 0xd2, 0x07, 0x90, 0x7e, 0x38, 0xe0, 0x60, 0x1b, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5} },
+{ 0x06f6,	16,	{0x41, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0x90, 0x7f, 0xcd, 0xf0} },
+{ 0x0706,	16,	{0xd2, 0x03, 0xc2, 0x09, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43, 0x45, 0x40, 0x90, 0x7f, 0x98} },
+{ 0x0716,	16,	{0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3a, 0xe0, 0x60} },
+{ 0x0726,	16,	{0x0f, 0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x6e, 0x75, 0x34, 0x01, 0xd2, 0x07} },
+{ 0x0736,	16,	{0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x6e} },
+{ 0x0746,	16,	{0xe4, 0xf5, 0x34, 0xd2, 0x07, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x0a} },
+{ 0x0756,	16,	{0xf0, 0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3d, 0xe0, 0x60, 0x02, 0xd2} },
+{ 0x0766,	16,	{0x0b, 0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4, 0xf5, 0x39, 0xd2, 0x07, 0x90} },
+{ 0x0776,	16,	{0x7e, 0x3f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x13, 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16} },
+{ 0x0786,	16,	{0xf0, 0x74, 0x36, 0xf0, 0xe4, 0x90, 0x7f, 0xd1, 0xf0, 0x30, 0x18, 0x52, 0xe5, 0x39, 0x60, 0x02} },
+{ 0x0796,	16,	{0x15, 0x39, 0x30, 0x12, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e} },
+{ 0x07a6,	16,	{0x75, 0x13, 0x0a, 0x30, 0x19, 0x02, 0xc2, 0x12, 0x12, 0x13, 0xf0, 0xef, 0x54, 0x01, 0xf5, 0x19} },
+{ 0x07b6,	16,	{0x65, 0x33, 0x60, 0x05, 0x85, 0x19, 0x33, 0xd2, 0x07, 0x12, 0x14, 0x43, 0xef, 0x54, 0x80, 0xf5} },
+{ 0x07c6,	16,	{0x19, 0x65, 0x2f, 0x60, 0x05, 0x85, 0x19, 0x2f, 0xd2, 0x07, 0x30, 0x0d, 0x11, 0x12, 0x14, 0x43} },
+{ 0x07d6,	16,	{0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x2e, 0x60, 0x05, 0x85, 0x19, 0x2e, 0xd2, 0x07, 0x30, 0x18} },
+{ 0x07e6,	16,	{0x2a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5} },
+{ 0x07f6,	16,	{0x15, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x16, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7} },
+{ 0x0806,	16,	{0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30} },
+{ 0x0816,	16,	{0xe1, 0x03, 0x02, 0x09, 0x18, 0xe5, 0x0a, 0x70, 0x40, 0x30, 0x06, 0x39, 0xe5, 0x38, 0x70, 0x35} },
+{ 0x0826,	16,	{0xc2, 0x06, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00} },
+{ 0x0836,	16,	{0xfa, 0x12, 0x0c, 0x9f, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83} },
+{ 0x0846,	16,	{0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75} },
+{ 0x0856,	16,	{0x38, 0x10, 0xe4, 0xf5, 0x2c, 0x75, 0x0a, 0x01, 0x22, 0xe5, 0x0a, 0x64, 0x01, 0x70, 0x40, 0x30} },
+{ 0x0866,	16,	{0x07, 0x39, 0xe5, 0x39, 0x70, 0x35, 0xc2, 0x07, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2d} },
+{ 0x0876,	16,	{0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0c, 0x9f, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5} },
+{ 0x0886,	16,	{0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90} },
+{ 0x0896,	16,	{0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x39, 0x10, 0xe4, 0xf5, 0x35, 0x75, 0x0a, 0x02, 0x22, 0xe5} },
+{ 0x08a6,	16,	{0x0a, 0x64, 0x02, 0x70, 0x36, 0x30, 0x13, 0x2f, 0xc2, 0x13, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00} },
+{ 0x08b6,	16,	{0x74, 0x0e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0c, 0x9f, 0xff, 0x74, 0x80, 0x25} },
+{ 0x08c6,	16,	{0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x05} },
+{ 0x08d6,	16,	{0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x0a, 0x03, 0x22, 0xe5, 0x15, 0x60, 0x30, 0x15} },
+{ 0x08e6,	16,	{0x15, 0xe4, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x14, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00} },
+{ 0x08f6,	16,	{0xfa, 0x12, 0x0c, 0x9f, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83} },
+{ 0x0906,	16,	{0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4} },
+{ 0x0916,	2,	{0xf5, 0x0a} },
+{ 0x0918,	1,	{0x22} },
+{ 0x0919,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0d, 0x2f, 0x09, 0xe9, 0x00, 0x0a, 0x5d, 0x01, 0x0a, 0xc9, 0x03} },
+{ 0x0929,	16,	{0x09, 0x3c, 0x06, 0x09, 0xdc, 0x08, 0x09, 0xd6, 0x09, 0x09, 0xbe, 0x0a, 0x09, 0xcd, 0x0b, 0x00} },
+{ 0x0939,	16,	{0x00, 0x0b, 0x18, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02} },
+{ 0x0949,	16,	{0x70, 0x69, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b} },
+{ 0x0959,	16,	{0x1f, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0f, 0x27, 0x8b, 0x18, 0x8a, 0x19, 0x89, 0x1a, 0xea} },
+{ 0x0969,	16,	{0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5} },
+{ 0x0979,	16,	{0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f} },
+{ 0x0989,	16,	{0xea, 0xe0, 0xff, 0x12, 0x0f, 0x76, 0x8b, 0x18, 0x8a, 0x19, 0x89, 0x1a, 0xea, 0x49, 0x60, 0x11} },
+{ 0x0999,	16,	{0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b} },
+{ 0x09a9,	16,	{0x1f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x09b9,	16,	{0x01, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0x00, 0xe5, 0x09, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01} },
+{ 0x09c9,	16,	{0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x09, 0x02, 0x0b, 0x1f, 0x12, 0x0b, 0x27} },
+{ 0x09d9,	16,	{0x02, 0x0b, 0x1f, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x0b, 0x1f} },
+{ 0x09e9,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
+{ 0x09f9,	16,	{0x0f, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x14, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
+{ 0x0a09,	16,	{0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x1f, 0xe4, 0x90, 0x7f, 0x00} },
+{ 0x0a19,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x0a29,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x0a39,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
+{ 0x0a49,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x0a59,	16,	{0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03} },
+{ 0x0a69,	16,	{0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x0f, 0x02, 0x0b, 0x1f, 0x90} },
+{ 0x0a79,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90} },
+{ 0x0a89,	16,	{0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
+{ 0x0a99,	16,	{0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x0aa9,	16,	{0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7} },
+{ 0x0ab9,	16,	{0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56} },
+{ 0x0ac9,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x0ad9,	16,	{0xb4, 0x01, 0x04, 0xd2, 0x0f, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36} },
+{ 0x0ae9,	16,	{0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54} },
+{ 0x0af9,	16,	{0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
+{ 0x0b09,	16,	{0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90} },
+{ 0x0b19,	13,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0b26,	1,	{0x22} },
+{ 0x0b27,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x18, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} },
+{ 0x0b37,	16,	{0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0b47,	16,	{0x18, 0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4} },
+{ 0x0b57,	16,	{0xf5, 0x24, 0x75, 0x1b, 0x01, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x1b, 0xf9, 0xe4, 0x34, 0x00, 0xfa} },
+{ 0x0b67,	16,	{0xe4, 0x12, 0x0c, 0xe5, 0x05, 0x1b, 0xe5, 0x1b, 0xb4, 0x09, 0xea, 0x75, 0x3a, 0x01, 0xe4, 0xf5} },
+{ 0x0b77,	16,	{0x38, 0xf5, 0x13, 0xf5, 0x36, 0xc2, 0x06, 0xc2, 0x0a, 0xc2, 0x04, 0xc2, 0x08, 0xc2, 0x12, 0xd2} },
+{ 0x0b87,	16,	{0x02, 0xd2, 0x00, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00, 0x74} },
+{ 0x0b97,	16,	{0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x12, 0x24, 0x7f, 0x10, 0x8f, 0x42, 0x12, 0x10, 0xf4} },
+{ 0x0ba7,	16,	{0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x7f, 0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00} },
+{ 0x0bb7,	16,	{0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0} },
+{ 0x0bc7,	16,	{0x0f, 0xe4, 0xfd, 0x12, 0x12, 0x24, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12, 0x12} },
+{ 0x0bd7,	16,	{0x24, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f} },
+{ 0x0be7,	16,	{0x12, 0x12, 0x24, 0x7f, 0x01, 0x12, 0x13, 0x27, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x24, 0x20} },
+{ 0x0bf7,	16,	{0x19, 0x03, 0x02, 0x0c, 0x9c, 0x75, 0x2d, 0x01, 0x75, 0x1b, 0x01, 0x7b, 0x00, 0x74, 0x2d, 0x25} },
+{ 0x0c07,	16,	{0x1b, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0c, 0xe5, 0x05, 0x1b, 0xe5, 0x1b, 0xb4, 0x09} },
+{ 0x0c17,	16,	{0xea, 0x75, 0x3b, 0x01, 0xe4, 0xf5, 0x39, 0xf5, 0x13, 0xf5, 0x37, 0xc2, 0x07, 0xc2, 0x0b, 0xc2} },
+{ 0x0c27,	16,	{0x05, 0xc2, 0x09, 0xc2, 0x12, 0xd2, 0x03, 0xd2, 0x01, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x75} },
+{ 0x0c37,	16,	{0x45, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x12, 0x6e, 0x7f} },
+{ 0x0c47,	16,	{0x10, 0x8f, 0x43, 0x12, 0x11, 0x66, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x7f, 0x01, 0x8f, 0x41} },
+{ 0x0c57,	16,	{0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x75, 0x47, 0x80} },
+{ 0x0c67,	16,	{0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x12, 0x6e, 0xe4, 0xff, 0x7e, 0xa3} },
+{ 0x0c77,	16,	{0xad, 0x06, 0x8d, 0x3f, 0x12, 0x12, 0x6e, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00} },
+{ 0x0c87,	16,	{0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x12, 0x6e, 0x7f, 0x01, 0x12, 0x13, 0x48, 0x7f, 0x03} },
+{ 0x0c97,	7,	{0x7d, 0x07, 0x12, 0x12, 0x6e, 0xd2, 0x11} },
+{ 0x0c9e,	1,	{0x22} },
+{ 0x0c9f,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x0caf,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0cb8,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x0cc8,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x0cd8,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0ce5,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01} },
+{ 0x0cf5,	2,	{0xf3, 0x22} },
+{ 0x0cf7,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x0d07,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x0d17,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x0d27,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x0d2f,	16,	{0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3} },
+{ 0x0d3f,	16,	{0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60} },
+{ 0x0d4f,	6,	{0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf} },
+{ 0x0d55,	16,	{0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83} },
+{ 0x0d65,	16,	{0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86} },
+{ 0x0d75,	16,	{0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5} },
+{ 0x0d85,	16,	{0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0} },
+{ 0x0d95,	16,	{0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0} },
+{ 0x0da5,	16,	{0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0} },
+{ 0x0db5,	16,	{0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90} },
+{ 0x0dc5,	16,	{0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2} },
+{ 0x0dd5,	16,	{0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05} },
+{ 0x0de5,	4,	{0x86, 0xd2, 0xaf, 0x22} },
+{ 0x0de9,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x0df9,	1,	{0x22} },
+{ 0x0dfa,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x0e0a,	16,	{0xd2, 0x17, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92} },
+{ 0x0e1a,	16,	{0x0f, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74} },
+{ 0x0e2a,	16,	{0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0} },
+{ 0x0e3a,	16,	{0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f} },
+{ 0x0e4a,	16,	{0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x18, 0x12, 0x13, 0x02, 0xc2, 0x10, 0xe4, 0xf5} },
+{ 0x0e5a,	16,	{0x0b, 0xf5, 0x13, 0xc2, 0x15, 0xc2, 0x11, 0x90, 0x7f, 0xa1, 0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0} },
+{ 0x0e6a,	16,	{0x65, 0x17, 0x60, 0x10, 0x30, 0x11, 0x05, 0xd2, 0x18, 0x12, 0x00, 0x46, 0x90, 0x7f, 0xd8, 0xe0} },
+{ 0x0e7a,	16,	{0xf5, 0x17, 0x80, 0x08, 0x30, 0x11, 0x05, 0xc2, 0x18, 0x12, 0x00, 0x46, 0x30, 0x10, 0x07, 0xc2} },
+{ 0x0e8a,	16,	{0x10, 0x12, 0x09, 0x19, 0x80, 0xd6, 0x30, 0x16, 0xd3, 0xc2, 0x16, 0x12, 0x14, 0x4f, 0x80, 0xcc} },
+{ 0x0e9a,	1,	{0x22} },
+{ 0x0e9b,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x47, 0x02, 0x0e, 0xe2} },
+{ 0x0ea7,	16,	{0x02, 0x0e, 0x0a, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x0eb7,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x0ec7,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x0ed7,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x13, 0x69, 0xe4, 0x7e} },
+{ 0x0ee7,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x0ef7,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x0f07,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x0f17,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x0f27,	16,	{0xe4, 0xfe, 0x75, 0x1d, 0xff, 0x75, 0x1e, 0x19, 0x75, 0x1f, 0x12, 0xab, 0x1d, 0xaa, 0x1e, 0xa9} },
+{ 0x0f37,	16,	{0x1f, 0x90, 0x00, 0x01, 0x12, 0x0c, 0xb8, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0f47,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x0c, 0xf7, 0x85, 0xf0, 0x1b, 0xf5, 0x1c, 0x62, 0x1b} },
+{ 0x0f57,	16,	{0xe5, 0x1b, 0x62, 0x1c, 0xe5, 0x1c, 0x62, 0x1b, 0x29, 0xfd, 0xe5, 0x1b, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0f67,	14,	{0x1d, 0xff, 0xf5, 0x1e, 0x89, 0x1f, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0f75,	1,	{0x22} },
+{ 0x0f76,	2,	{0x8f, 0x1b} },
+{ 0x0f78,	16,	{0xe4, 0xf5, 0x1c, 0x75, 0x1d, 0xff, 0x75, 0x1e, 0x19, 0x75, 0x1f, 0x86, 0xab, 0x1d, 0xaa, 0x1e} },
+{ 0x0f88,	16,	{0xa9, 0x1f, 0x90, 0x00, 0x01, 0x12, 0x0c, 0xb8, 0xb4, 0x03, 0x1d, 0xaf, 0x1c, 0x05, 0x1c, 0xef} },
+{ 0x0f98,	16,	{0xb5, 0x1b, 0x01, 0x22, 0x12, 0x0c, 0x9f, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x0fa8,	14,	{0x1d, 0xff, 0xf5, 0x1e, 0x89, 0x1f, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0fb6,	1,	{0x22} },
+{ 0x0fb7,	16,	{0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e} },
+{ 0x0fc7,	16,	{0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05} },
+{ 0x0fd7,	16,	{0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13} },
+{ 0x0fe7,	9,	{0xcc, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22} },
+{ 0x0ff0,	16,	{0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e} },
+{ 0x1000,	16,	{0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x13, 0xe4, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05} },
+{ 0x1010,	16,	{0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x14} },
+{ 0x1020,	9,	{0x37, 0x8f, 0x1a, 0xef, 0x42, 0x37, 0x80, 0xca, 0x22} },
+{ 0x1029,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30} },
+{ 0x1039,	16,	{0x1a, 0x04, 0xc2, 0x1a, 0x80, 0x02, 0xd2, 0x16, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x1049,	14,	{0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1057,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90} },
+{ 0x1067,	16,	{0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0} },
+{ 0x1077,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1081,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2} },
+{ 0x1091,	16,	{0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85} },
+{ 0x10a1,	7,	{0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x10a8,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x10b8,	16,	{0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x10c8,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x10ce,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x10de,	16,	{0x11, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x10ee,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x10f4,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1104,	16,	{0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x1114,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x111a,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x112a,	16,	{0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x113a,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x1140,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1150,	16,	{0x16, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x1160,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x1166,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1176,	16,	{0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x1186,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x118c,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x119c,	16,	{0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x11ac,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x11b2,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x11c2,	16,	{0x09, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x11d2,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x11d8,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x11e8,	16,	{0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x11f8,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x11fe,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x120e,	16,	{0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x121e,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x1224,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f} },
+{ 0x1234,	16,	{0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90} },
+{ 0x1244,	5,	{0xc0, 0x00, 0xed, 0xf0, 0x22} },
+{ 0x1249,	16,	{0x12, 0x13, 0xb4, 0x8f, 0x1a, 0x12, 0x13, 0xb4, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12} },
+{ 0x1259,	16,	{0x12, 0x13, 0xb4, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0xb4, 0x8f, 0x1b} },
+{ 0x1269,	4,	{0x80, 0xe8, 0xaf, 0x1a} },
+{ 0x126d,	1,	{0x22} },
+{ 0x126e,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f} },
+{ 0x127e,	16,	{0x98, 0x74, 0x0f, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90} },
+{ 0x128e,	5,	{0xc0, 0x00, 0xed, 0xf0, 0x22} },
+{ 0x1293,	16,	{0x12, 0x14, 0x1f, 0x8f, 0x1a, 0x12, 0x14, 0x1f, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12} },
+{ 0x12a3,	16,	{0x12, 0x14, 0x1f, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x14, 0x1f, 0x8f, 0x1b} },
+{ 0x12b3,	4,	{0x80, 0xe8, 0xaf, 0x1a} },
+{ 0x12b7,	1,	{0x22} },
+{ 0x12b8,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x12c8,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x12d8,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x12dd,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x12ed,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x12fd,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1302,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x18, 0x04, 0xe0, 0x44} },
+{ 0x1312,	16,	{0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x13, 0x85, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x1322,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x1327,	16,	{0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3e, 0x54, 0x7f, 0xfd, 0x12, 0x12, 0x24, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1337,	16,	{0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3e, 0x44, 0x80, 0xfd, 0x12, 0x12, 0x24} },
+{ 0x1347,	1,	{0x22} },
+{ 0x1348,	16,	{0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3f, 0x54, 0x7f, 0xfd, 0x12, 0x12, 0x6e, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1358,	16,	{0x09, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3f, 0x44, 0x80, 0xfd, 0x12, 0x12, 0x6e} },
+{ 0x1368,	1,	{0x22} },
+{ 0x1369,	16,	{0x05, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x03, 0x00, 0x00, 0xc1, 0x10, 0xc1, 0x16} },
+{ 0x1379,	7,	{0xc1, 0x0f, 0xc1, 0x94, 0x01, 0x0a, 0x00} },
+{ 0x1380,	2,	{0xc1, 0x19} },
+{ 0x1382,	2,	{0xc1, 0x9a} },
+{ 0x1384,	1,	{0x00} },
+{ 0x1385,	16,	{0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18, 0x70, 0x02, 0x15, 0x18, 0x4e, 0x60} },
+{ 0x1395,	7,	{0x05, 0x12, 0x0d, 0xe9, 0x80, 0xee, 0x22} },
+{ 0x139c,	12,	{0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13a8,	12,	{0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13b4,	12,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13c0,	12,	{0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13cc,	12,	{0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13d8,	12,	{0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13e4,	12,	{0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13f0,	12,	{0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13fc,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x1400,	16,	{0x02, 0x10, 0x81, 0x00, 0x02, 0x12, 0xb8, 0x00, 0x02, 0x10, 0x57, 0x00, 0x02, 0x10, 0x29, 0x00} },
+{ 0x1410,	3,	{0x02, 0x12, 0xdd} },
+{ 0x1413,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x141f,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x142b,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x1437,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x1443,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x144f,	10,	{0x12, 0x00, 0x03, 0x12, 0x0d, 0xfa, 0x12, 0x0b, 0x27, 0x22} },
+{ 0x1900,	16,	{0x12, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x12, 0x01, 0x00, 0x00, 0x01, 0x02} },
+{ 0x1910,	16,	{0x00, 0x01, 0x09, 0x02, 0x74, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e} },
+{ 0x1920,	16,	{0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1930,	16,	{0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1940,	16,	{0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1950,	16,	{0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02} },
+{ 0x1960,	16,	{0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00} },
+{ 0x1970,	16,	{0x00, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x07} },
+{ 0x1980,	16,	{0x05, 0x87, 0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00} },
+{ 0x1990,	16,	{0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00} },
+{ 0x19a0,	16,	{0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00} },
+{ 0x19b0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00} },
+{ 0x19c0,	16,	{0x6f, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x19d0,	16,	{0x2e, 0x00, 0x36, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00} },
+{ 0x19e0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00} },
+{ 0x19f0,	16,	{0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00} },
+{ 0x1a00,	10,	{0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa19_fw.h linux.18p8/drivers/usb/serial/keyspan_usa19_fw.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa19_fw.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_usa19_fw.h	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,299 @@
+/* keyspan_usa19_fw.h
+  
+   Generated from Keyspan firmware image Wed Jul  5 09:18:29 2000 EST
+   This firmware is for the Keyspan USA-19 Serial Adaptor
+
+   "The firmware contained herein as keyspan_usa19_fw.h is
+   Copyright (C) 1999-2000 Keyspan, A division of InnoSys Incorporated
+   ("Keyspan"), as an unpublished work.  This notice does not imply
+   unrestricted or public access to this firmware which is a trade secret of
+   Keyspan, and which may not be reproduced, used, sold or transferred to any
+   third party without Keyspan's prior written consent.  All Rights Reserved.
+
+   This firmware may not be modified and may only be used with the Keyspan 
+   USA-19 Serial Adapter.  Distribution and/or Modification of the
+   keyspan.c driver which includes this firmware, in whole or in part,
+   requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa19_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x0b, 0x82} },
+{ 0x0003,	16,	{0x8e, 0x13, 0x8f, 0x14, 0xe5, 0x14, 0x15, 0x14, 0xae, 0x13, 0x70, 0x02, 0x15, 0x13, 0x4e, 0x60} },
+{ 0x0013,	7,	{0x05, 0x12, 0x0f, 0x38, 0x80, 0xee, 0x22} },
+{ 0x001a,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x0023,	3,	{0x02, 0x00, 0x46} },
+{ 0x0026,	10,	{0x12, 0x0d, 0xac, 0x12, 0x0f, 0x49, 0x12, 0x0d, 0x08, 0x22} },
+{ 0x0033,	3,	{0x02, 0x00, 0x1a} },
+{ 0x0043,	3,	{0x02, 0x0f, 0x00} },
+{ 0x0046,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0, 0xd0, 0x75, 0xd0, 0x08} },
+{ 0x0056,	16,	{0x30, 0x99, 0x0e, 0x30, 0x06, 0x07, 0xa2, 0x09, 0x92, 0x9b, 0x85, 0x35, 0x99, 0xc2, 0x99, 0xd2} },
+{ 0x0066,	16,	{0x0d, 0x20, 0x0d, 0x03, 0x02, 0x04, 0x25, 0xc2, 0x0d, 0x20, 0x01, 0x03, 0x02, 0x02, 0x50, 0x20} },
+{ 0x0076,	16,	{0x06, 0x03, 0x02, 0x01, 0x27, 0xe5, 0x37, 0xc3, 0x95, 0x50, 0x50, 0x3e, 0x20, 0x07, 0x36, 0x20} },
+{ 0x0086,	16,	{0x04, 0x33, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe3, 0x03, 0x20, 0x0c, 0x29, 0x30, 0x0b, 0x12, 0xaf} },
+{ 0x0096,	16,	{0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92} },
+{ 0x00a6,	16,	{0x09, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0} },
+{ 0x00b6,	16,	{0xf5, 0x35, 0x02, 0x04, 0x23, 0xc2, 0x06, 0x02, 0x04, 0x23, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0xc2} },
+{ 0x00c6,	16,	{0x01, 0x30, 0x08, 0x0c, 0xc2, 0x08, 0x90, 0x7f, 0xbb, 0x04, 0xf0, 0xc2, 0x06, 0x02, 0x04, 0x23} },
+{ 0x00d6,	16,	{0x90, 0x7f, 0xc8, 0xe0, 0x30, 0xe1, 0x05, 0xc2, 0x06, 0x02, 0x04, 0x23, 0x90, 0x7f, 0xc9, 0xe0} },
+{ 0x00e6,	16,	{0xf5, 0x50, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x08, 0x20, 0x07, 0x2d, 0x20, 0x04, 0x2a, 0x90} },
+{ 0x00f6,	16,	{0x7f, 0x9b, 0xe0, 0x30, 0xe3, 0x03, 0x20, 0x0c, 0x20, 0x30, 0x0b, 0x11, 0x90, 0x7d, 0xc1, 0xe0} },
+{ 0x0106,	16,	{0x13, 0x92, 0x09, 0xa3, 0xe0, 0xf5, 0x35, 0x75, 0x37, 0x03, 0x02, 0x04, 0x23, 0x75, 0x37, 0x02} },
+{ 0x0116,	16,	{0x90, 0x7d, 0xc1, 0xe0, 0xf5, 0x35, 0x02, 0x04, 0x23, 0x75, 0x37, 0x01, 0xc2, 0x06, 0x02, 0x04} },
+{ 0x0126,	16,	{0x23, 0xe5, 0x37, 0xc3, 0x95, 0x50, 0x50, 0x03, 0x02, 0x01, 0xc9, 0x90, 0x7f, 0xc6, 0xe0, 0x30} },
+{ 0x0136,	16,	{0xe1, 0x07, 0xc2, 0x0f, 0xd2, 0x0e, 0x02, 0x04, 0x23, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x50, 0x90} },
+{ 0x0146,	16,	{0x7e, 0x40, 0xe0, 0x13, 0x92, 0x08, 0x20, 0x07, 0x72, 0x20, 0x04, 0x6f, 0x90, 0x7f, 0x9b, 0xe0} },
+{ 0x0156,	16,	{0x30, 0xe3, 0x03, 0x20, 0x0c, 0x65, 0x30, 0x0b, 0x10, 0x90, 0x7e, 0x41, 0xe0, 0x13, 0x92, 0x9b} },
+{ 0x0166,	16,	{0xa3, 0xe0, 0xf5, 0x99, 0x75, 0x37, 0x03, 0x80, 0x09, 0x90, 0x7e, 0x41, 0xe0, 0xf5, 0x99, 0x75} },
+{ 0x0176,	16,	{0x37, 0x02, 0xe5, 0x37, 0xc3, 0x95, 0x50, 0x40, 0x17, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0xc2, 0x01} },
+{ 0x0186,	16,	{0x20, 0x08, 0x03, 0x02, 0x04, 0x23, 0xc2, 0x08, 0x90, 0x7f, 0xbb, 0x04, 0xf0, 0x02, 0x04, 0x23} },
+{ 0x0196,	16,	{0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5} },
+{ 0x01a6,	16,	{0x83, 0xe0, 0x13, 0x92, 0x09, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x01b6,	16,	{0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x35, 0xd2, 0x06, 0x02, 0x04, 0x23, 0x75, 0x37, 0x01, 0xc2, 0x0f} },
+{ 0x01c6,	16,	{0x02, 0x04, 0x23, 0x30, 0x07, 0x03, 0x02, 0x02, 0x4b, 0x20, 0x04, 0x79, 0x90, 0x7f, 0x9b, 0xe0} },
+{ 0x01d6,	16,	{0x30, 0xe3, 0x03, 0x20, 0x0c, 0x6f, 0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f} },
+{ 0x01e6,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x9b, 0xaf, 0x37, 0x05, 0x37, 0x74} },
+{ 0x01f6,	16,	{0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x99, 0xe5, 0x37, 0xc3, 0x95} },
+{ 0x0206,	16,	{0x50, 0x40, 0x17, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0xc2, 0x01, 0x20, 0x08, 0x03, 0x02, 0x04, 0x23} },
+{ 0x0216,	16,	{0xc2, 0x08, 0x90, 0x7f, 0xbb, 0x04, 0xf0, 0x02, 0x04, 0x23, 0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05} },
+{ 0x0226,	16,	{0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x09, 0xaf} },
+{ 0x0236,	16,	{0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x35} },
+{ 0x0246,	16,	{0xd2, 0x06, 0x02, 0x04, 0x23, 0xc2, 0x0f, 0x02, 0x04, 0x23, 0x20, 0x06, 0x03, 0x02, 0x03, 0x02} },
+{ 0x0256,	16,	{0xe5, 0x37, 0xc3, 0x95, 0x50, 0x50, 0x3e, 0x20, 0x07, 0x36, 0x20, 0x04, 0x33, 0x90, 0x7f, 0x9b} },
+{ 0x0266,	16,	{0xe0, 0x30, 0xe3, 0x03, 0x20, 0x0c, 0x29, 0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0} },
+{ 0x0276,	16,	{0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x09, 0xaf, 0x37, 0x05, 0x37} },
+{ 0x0286,	16,	{0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x35, 0x02, 0x04, 0x23} },
+{ 0x0296,	16,	{0xc2, 0x06, 0x02, 0x04, 0x23, 0x90, 0x7f, 0xc9, 0xe4, 0xf0, 0xd2, 0x01, 0x30, 0x08, 0x0c, 0xc2} },
+{ 0x02a6,	16,	{0x08, 0x90, 0x7f, 0xbb, 0x04, 0xf0, 0xc2, 0x06, 0x02, 0x04, 0x23, 0x90, 0x7f, 0xc6, 0xe0, 0x30} },
+{ 0x02b6,	16,	{0xe1, 0x05, 0xc2, 0x06, 0x02, 0x04, 0x23, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x50, 0x90, 0x7e, 0x40} },
+{ 0x02c6,	16,	{0xe0, 0x13, 0x92, 0x08, 0x20, 0x07, 0x2d, 0x20, 0x04, 0x2a, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe3} },
+{ 0x02d6,	16,	{0x03, 0x20, 0x0c, 0x20, 0x30, 0x0b, 0x11, 0x90, 0x7e, 0x41, 0xe0, 0x13, 0x92, 0x09, 0xa3, 0xe0} },
+{ 0x02e6,	16,	{0xf5, 0x35, 0x75, 0x37, 0x03, 0x02, 0x04, 0x23, 0x75, 0x37, 0x02, 0x90, 0x7e, 0x41, 0xe0, 0xf5} },
+{ 0x02f6,	16,	{0x35, 0x02, 0x04, 0x23, 0x75, 0x37, 0x01, 0xc2, 0x06, 0x02, 0x04, 0x23, 0xe5, 0x37, 0xc3, 0x95} },
+{ 0x0306,	16,	{0x50, 0x50, 0x03, 0x02, 0x03, 0xa4, 0x90, 0x7f, 0xc8, 0xe0, 0x30, 0xe1, 0x07, 0xc2, 0x0f, 0xd2} },
+{ 0x0316,	16,	{0x0e, 0x02, 0x04, 0x23, 0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x50, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92} },
+{ 0x0326,	16,	{0x08, 0x20, 0x07, 0x72, 0x20, 0x04, 0x6f, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe3, 0x03, 0x20, 0x0c} },
+{ 0x0336,	16,	{0x65, 0x30, 0x0b, 0x10, 0x90, 0x7d, 0xc1, 0xe0, 0x13, 0x92, 0x9b, 0xa3, 0xe0, 0xf5, 0x99, 0x75} },
+{ 0x0346,	16,	{0x37, 0x03, 0x80, 0x09, 0x90, 0x7d, 0xc1, 0xe0, 0xf5, 0x99, 0x75, 0x37, 0x02, 0xe5, 0x37, 0xc3} },
+{ 0x0356,	16,	{0x95, 0x50, 0x40, 0x17, 0x90, 0x7f, 0xc9, 0xe4, 0xf0, 0xd2, 0x01, 0x20, 0x08, 0x03, 0x02, 0x04} },
+{ 0x0366,	16,	{0x23, 0xc2, 0x08, 0x90, 0x7f, 0xbb, 0x04, 0xf0, 0x02, 0x04, 0x23, 0x30, 0x0b, 0x12, 0xaf, 0x37} },
+{ 0x0376,	16,	{0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x09} },
+{ 0x0386,	16,	{0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5} },
+{ 0x0396,	16,	{0x35, 0xd2, 0x06, 0x02, 0x04, 0x23, 0x75, 0x37, 0x01, 0xc2, 0x0f, 0x02, 0x04, 0x23, 0x30, 0x07} },
+{ 0x03a6,	16,	{0x03, 0x02, 0x04, 0x21, 0x20, 0x04, 0x74, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe3, 0x03, 0x20, 0x0c} },
+{ 0x03b6,	16,	{0x6a, 0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d} },
+{ 0x03c6,	16,	{0xf5, 0x83, 0xe0, 0x13, 0x92, 0x9b, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4} },
+{ 0x03d6,	16,	{0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x99, 0xe5, 0x37, 0xc3, 0x95, 0x50, 0x40, 0x13, 0x90, 0x7f} },
+{ 0x03e6,	16,	{0xc9, 0xe4, 0xf0, 0xd2, 0x01, 0x30, 0x08, 0x35, 0xc2, 0x08, 0x90, 0x7f, 0xbb, 0x04, 0xf0, 0x80} },
+{ 0x03f6,	16,	{0x2c, 0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d} },
+{ 0x0406,	16,	{0xf5, 0x83, 0xe0, 0x13, 0x92, 0x09, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4} },
+{ 0x0416,	16,	{0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x35, 0xd2, 0x06, 0x80, 0x02, 0xc2, 0x0f, 0xd2, 0x11, 0x20} },
+{ 0x0426,	5,	{0x98, 0x03, 0x02, 0x05, 0x61} },
+{ 0x042b,	16,	{0xc2, 0x98, 0x20, 0x00, 0x03, 0x02, 0x04, 0xce, 0x20, 0x10, 0x27, 0xaf, 0x36, 0x05, 0x36, 0x74} },
+{ 0x043b,	16,	{0x80, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x99, 0xf0, 0x30, 0x0b, 0x4d, 0xaf} },
+{ 0x044b,	16,	{0x36, 0x05, 0x36, 0x74, 0x80, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0} },
+{ 0x045b,	16,	{0x80, 0x3a, 0x85, 0x99, 0x10, 0xe5, 0x10, 0xb5, 0x44, 0x04, 0xd2, 0x04, 0x80, 0x2e, 0xe5, 0x10} },
+{ 0x046b,	16,	{0xb5, 0x43, 0x04, 0xc2, 0x04, 0x80, 0x25, 0xaf, 0x36, 0x05, 0x36, 0x74, 0x80, 0x2f, 0xf5, 0x82} },
+{ 0x047b,	16,	{0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x10, 0xf0, 0x30, 0x0b, 0x11, 0xaf, 0x36, 0x05, 0x36, 0x74} },
+{ 0x048b,	16,	{0x80, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0xd2, 0x0a, 0xe5, 0x36} },
+{ 0x049b,	16,	{0xc3, 0x95, 0x40, 0x50, 0x03, 0x02, 0x05, 0x5f, 0x90, 0x7f, 0xb8, 0xe0, 0x30, 0xe1, 0x16, 0xe5} },
+{ 0x04ab,	16,	{0x36, 0xc3, 0x94, 0x40, 0x50, 0x03, 0x02, 0x05, 0x5f, 0x15, 0x36, 0x15, 0x36, 0x05, 0x2b, 0x43} },
+{ 0x04bb,	16,	{0x33, 0x01, 0x02, 0x05, 0x5f, 0x90, 0x7f, 0xb7, 0xe5, 0x36, 0xf0, 0x75, 0x36, 0x00, 0xc2, 0x00} },
+{ 0x04cb,	16,	{0x02, 0x05, 0x5f, 0x20, 0x10, 0x27, 0xaf, 0x36, 0x05, 0x36, 0x74, 0x00, 0x2f, 0xf5, 0x82, 0xe4} },
+{ 0x04db,	16,	{0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x99, 0xf0, 0x30, 0x0b, 0x4d, 0xaf, 0x36, 0x05, 0x36, 0x74, 0x00} },
+{ 0x04eb,	16,	{0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0x80, 0x3a, 0x85, 0x99, 0x10} },
+{ 0x04fb,	16,	{0xe5, 0x10, 0xb5, 0x44, 0x04, 0xd2, 0x04, 0x80, 0x2e, 0xe5, 0x10, 0xb5, 0x43, 0x04, 0xc2, 0x04} },
+{ 0x050b,	16,	{0x80, 0x25, 0xaf, 0x36, 0x05, 0x36, 0x74, 0x00, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83} },
+{ 0x051b,	16,	{0xe5, 0x10, 0xf0, 0x30, 0x0b, 0x11, 0xaf, 0x36, 0x05, 0x36, 0x74, 0x00, 0x2f, 0xf5, 0x82, 0xe4} },
+{ 0x052b,	16,	{0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0xd2, 0x0a, 0xe5, 0x36, 0xc3, 0x95, 0x40, 0x40, 0x24} },
+{ 0x053b,	16,	{0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x12, 0xe5, 0x36, 0xc3, 0x94, 0x40, 0x40, 0x16, 0x15, 0x36} },
+{ 0x054b,	16,	{0x15, 0x36, 0x05, 0x2b, 0x43, 0x33, 0x01, 0x80, 0x0b, 0x90, 0x7f, 0xb9, 0xe5, 0x36, 0xf0, 0x75} },
+{ 0x055b,	6,	{0x36, 0x00, 0xd2, 0x00, 0xd2, 0x11} },
+{ 0x0561,	16,	{0x30, 0x11, 0x05, 0xc2, 0x11, 0x02, 0x00, 0x56, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x82, 0xd0, 0x83} },
+{ 0x0571,	3,	{0xd0, 0xe0, 0x32} },
+{ 0x0574,	16,	{0x90, 0x7f, 0xca, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x06, 0xa5, 0xe4, 0xf5, 0x13, 0x74, 0x40, 0x25} },
+{ 0x0584,	16,	{0x13, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x13, 0x7c, 0x00, 0x7b, 0x00} },
+{ 0x0594,	16,	{0x24, 0x38, 0xf9, 0xec, 0x34, 0x00, 0xfa, 0xef, 0x12, 0x0c, 0x54, 0x05, 0x13, 0xe5, 0x13, 0xb4} },
+{ 0x05a4,	16,	{0x18, 0xdb, 0xe5, 0x38, 0x60, 0x0c, 0x75, 0xc9, 0x20, 0x75, 0xc8, 0x34, 0x85, 0x39, 0xca, 0x85} },
+{ 0x05b4,	16,	{0x3a, 0xcb, 0xe5, 0x3b, 0x13, 0x92, 0x0b, 0x92, 0x9f, 0xe5, 0x3c, 0x13, 0x92, 0x0c, 0xe5, 0x3d} },
+{ 0x05c4,	16,	{0x13, 0x92, 0x10, 0xe5, 0x3e, 0x60, 0x09, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfb, 0xf0, 0x80, 0x07} },
+{ 0x05d4,	16,	{0x90, 0x7f, 0x98, 0xe0, 0x44, 0x04, 0xf0, 0xe5, 0x3f, 0x60, 0x09, 0x90, 0x7f, 0x98, 0xe0, 0x54} },
+{ 0x05e4,	16,	{0x7f, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0x98, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x45, 0x60, 0x0b, 0xc2} },
+{ 0x05f4,	16,	{0x07, 0xc2, 0x04, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x46, 0x60, 0x0c, 0xd2, 0x04} },
+{ 0x0604,	16,	{0x43, 0x33, 0x01, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x47, 0x60, 0x17, 0xc2, 0xaf} },
+{ 0x0614,	16,	{0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0xc2, 0x06, 0xd2, 0x01, 0xc2, 0x08, 0xf5} },
+{ 0x0624,	16,	{0x50, 0xf5, 0x37, 0xd2, 0xaf, 0xe5, 0x48, 0x60, 0x05, 0x30, 0x10, 0x02, 0xd2, 0x04, 0xe5, 0x49} },
+{ 0x0634,	16,	{0x60, 0x15, 0x90, 0x7f, 0x95, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0x9e, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0644,	16,	{0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x4a, 0x60, 0x0a, 0xd2, 0x9c, 0xc2, 0x98, 0x75} },
+{ 0x0654,	16,	{0x2c, 0x01, 0x75, 0x31, 0x1e, 0xe5, 0x4b, 0x60, 0x07, 0xc2, 0x9c, 0xe4, 0xf5, 0x36, 0xf5, 0x2c} },
+{ 0x0664,	16,	{0xe5, 0x4c, 0x60, 0x03, 0xe4, 0xf5, 0x36, 0xe5, 0x4d, 0x60, 0x02, 0xd2, 0x02, 0xe5, 0x4e, 0x60} },
+{ 0x0674,	16,	{0x0a, 0xe5, 0x4a, 0x70, 0x02, 0xf5, 0x31, 0xe5, 0x4e, 0x42, 0x33, 0xe5, 0x4f, 0x60, 0x1b, 0x90} },
+{ 0x0684,	16,	{0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x12, 0xf0, 0x74, 0x32, 0xf0, 0x74, 0x13} },
+{ 0x0694,	16,	{0xf0, 0x74, 0x33, 0xf0, 0x74, 0x14, 0xf0, 0x74, 0x34, 0xf0, 0xd2, 0x03, 0xe4, 0x90, 0x7f, 0xcb} },
+{ 0x06a4,	16,	{0xf0, 0xa2, 0x07, 0xe4, 0x33, 0xff, 0x65, 0x29, 0x60, 0x05, 0x8f, 0x29, 0x43, 0x33, 0x01, 0xa2} },
+{ 0x06b4,	16,	{0x04, 0xe4, 0x33, 0xff, 0x65, 0x2a, 0x60, 0x05, 0x8f, 0x2a, 0x43, 0x33, 0x01, 0x90, 0x7f, 0x9b} },
+{ 0x06c4,	16,	{0xe0, 0x54, 0x08, 0xb5, 0x25, 0x0a, 0xe0, 0x54, 0x08, 0x64, 0x08, 0xf5, 0x25, 0x43, 0x33, 0x01} },
+{ 0x06d4,	16,	{0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x10, 0xb5, 0x26, 0x0a, 0xe0, 0x54, 0x10, 0x64, 0x10, 0xf5, 0x26} },
+{ 0x06e4,	16,	{0x43, 0x33, 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x40, 0xb5, 0x27, 0x0a, 0xe0, 0x54, 0x40, 0x64} },
+{ 0x06f4,	16,	{0x40, 0xf5, 0x27, 0x43, 0x33, 0x01, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x20, 0xb5, 0x28, 0x0a, 0xe0} },
+{ 0x0704,	16,	{0x54, 0x20, 0x64, 0x20, 0xf5, 0x28, 0x43, 0x33, 0x01, 0x30, 0x02, 0x35, 0xc2, 0xaf, 0x30, 0x00} },
+{ 0x0714,	16,	{0x18, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0xe5, 0x36, 0x60, 0x09, 0x90, 0x7f, 0xb7, 0xf0} },
+{ 0x0724,	16,	{0xe4, 0xf5, 0x36, 0xc2, 0x00, 0xc2, 0x02, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x0f} },
+{ 0x0734,	16,	{0xe5, 0x36, 0x60, 0x09, 0x90, 0x7f, 0xb9, 0xf0, 0xe4, 0xf5, 0x36, 0xd2, 0x00, 0xc2, 0x02, 0xd2} },
+{ 0x0744,	16,	{0xaf, 0x30, 0x0e, 0x37, 0x30, 0x01, 0x1b, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x2d, 0x90, 0x7e} },
+{ 0x0754,	16,	{0x40, 0xe0, 0x13, 0x92, 0x08, 0x75, 0x37, 0x01, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x50, 0xc2, 0x0e} },
+{ 0x0764,	16,	{0x80, 0x19, 0x90, 0x7f, 0xc8, 0xe0, 0x20, 0xe1, 0x12, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x08} },
+{ 0x0774,	16,	{0x75, 0x37, 0x01, 0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x50, 0xc2, 0x0e, 0x30, 0x0f, 0x03, 0x02, 0x08} },
+{ 0x0784,	16,	{0x87, 0x30, 0x0e, 0x03, 0x02, 0x08, 0x87, 0x30, 0x0c, 0x0a, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe3} },
+{ 0x0794,	16,	{0x03, 0x02, 0x08, 0x87, 0x30, 0x04, 0x03, 0x02, 0x08, 0x87, 0x30, 0x07, 0x03, 0x02, 0x08, 0x87} },
+{ 0x07a4,	16,	{0x30, 0x01, 0x62, 0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4} },
+{ 0x07b4,	16,	{0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x18, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5} },
+{ 0x07c4,	16,	{0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x14, 0xe5, 0x37, 0xc3, 0x95, 0x50, 0x50, 0x2a} },
+{ 0x07d4,	16,	{0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5} },
+{ 0x07e4,	16,	{0x83, 0xe0, 0x13, 0x92, 0x09, 0xaf, 0x37, 0x05, 0x37, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x07f4,	16,	{0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x35, 0xd2, 0x06, 0x80, 0x6b, 0xc2, 0x06, 0xe4, 0x90, 0x7f, 0xc7} },
+{ 0x0804,	16,	{0xf0, 0xc2, 0x01, 0x80, 0x60, 0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5} },
+{ 0x0814,	16,	{0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x18, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0} },
+{ 0x0824,	16,	{0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x14, 0xe5, 0x37, 0xc3, 0x95, 0x50} },
+{ 0x0834,	16,	{0x50, 0x2a, 0x30, 0x0b, 0x12, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0844,	16,	{0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x09, 0xaf, 0x37, 0x05, 0x37, 0x74, 0xc0, 0x2f, 0xf5, 0x82} },
+{ 0x0854,	16,	{0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x35, 0xd2, 0x06, 0x80, 0x09, 0xc2, 0x06, 0xe4, 0x90} },
+{ 0x0864,	16,	{0x7f, 0xc9, 0xf0, 0xd2, 0x01, 0x30, 0x0b, 0x04, 0xa2, 0x18, 0x92, 0x9b, 0xd2, 0x0f, 0xc2, 0xaf} },
+{ 0x0874,	16,	{0x85, 0x14, 0x99, 0x20, 0x06, 0x0b, 0x30, 0x08, 0x08, 0xc2, 0x08, 0x90, 0x7f, 0xbb, 0x74, 0x01} },
+{ 0x0884,	16,	{0xf0, 0xd2, 0xaf, 0x90, 0x7f, 0xbc, 0xe0, 0x20, 0xe1, 0x51, 0xe5, 0x33, 0x60, 0x4d, 0xe5, 0x31} },
+{ 0x0894,	16,	{0x70, 0x49, 0xe5, 0x33, 0x30, 0xe1, 0x08, 0xe4, 0xf5, 0x2f, 0x75, 0x33, 0x01, 0x80, 0x0b, 0xa2} },
+{ 0x08a4,	16,	{0x03, 0xe4, 0x33, 0xf5, 0x2f, 0xc2, 0x03, 0xe4, 0xf5, 0x33, 0xe4, 0xf5, 0x13, 0x7e, 0x00, 0x7b} },
+{ 0x08b4,	16,	{0x00, 0x74, 0x24, 0x25, 0x13, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0c, 0x0e, 0xff, 0x74, 0x00} },
+{ 0x08c4,	16,	{0x25, 0x13, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x13, 0xe5, 0x13, 0xb4} },
+{ 0x08d4,	11,	{0x0c, 0xdb, 0x90, 0x7f, 0xbd, 0x74, 0x0c, 0xf0, 0x75, 0x31, 0x10} },
+{ 0x08df,	1,	{0x22} },
+{ 0x08e0,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0c, 0x66, 0x09, 0xb1, 0x00, 0x0a, 0x25, 0x01, 0x0a, 0x91, 0x03} },
+{ 0x08f0,	16,	{0x09, 0x03, 0x06, 0x09, 0xa4, 0x08, 0x09, 0x9e, 0x09, 0x09, 0x86, 0x0a, 0x09, 0x95, 0x0b, 0x00} },
+{ 0x0900,	16,	{0x00, 0x0a, 0xe0, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x4b, 0x24, 0x02} },
+{ 0x0910,	16,	{0x70, 0x6a, 0x74, 0x0f, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x64, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0a} },
+{ 0x0920,	16,	{0xe7, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x04, 0x7f, 0x02, 0x80, 0x02, 0x7f, 0x03, 0x75, 0x82, 0xb5} },
+{ 0x0930,	16,	{0x75, 0x83, 0x0f, 0xef, 0xf0, 0x75, 0x82, 0xae, 0x75, 0x83, 0x0f, 0xf0, 0x75, 0x82, 0xa7, 0x75} },
+{ 0x0940,	16,	{0x83, 0x0f, 0xf0, 0x75, 0x82, 0xa0, 0x75, 0x83, 0x0f, 0xf0, 0x74, 0x0f, 0x90, 0x7f, 0xd4, 0xf0} },
+{ 0x0950,	16,	{0x74, 0x76, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0d} },
+{ 0x0960,	16,	{0xf1, 0xea, 0x49, 0x60, 0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02} },
+{ 0x0970,	16,	{0x0a, 0xe7, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0980,	16,	{0x44, 0x01, 0xf0, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0x00, 0xe5, 0x18, 0xf0, 0x90, 0x7f, 0xb5, 0x74} },
+{ 0x0990,	16,	{0x01, 0xf0, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x18, 0x02, 0x0a, 0xe7, 0x12, 0x0d} },
+{ 0x09a0,	16,	{0x08, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x0a} },
+{ 0x09b0,	16,	{0xe7, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b} },
+{ 0x09c0,	16,	{0xa2, 0x12, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x15, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00} },
+{ 0x09d0,	16,	{0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0a, 0xe7, 0xe4, 0x90, 0x7f} },
+{ 0x09e0,	16,	{0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0xec} },
+{ 0x09f0,	16,	{0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24} },
+{ 0x0a00,	16,	{0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4} },
+{ 0x0a10,	16,	{0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x0a20,	16,	{0x01, 0xf0, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60} },
+{ 0x0a30,	16,	{0x03, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x12, 0x02, 0x0a, 0xe7} },
+{ 0x0a40,	16,	{0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0a, 0xe7, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38} },
+{ 0x0a50,	16,	{0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f} },
+{ 0x0a60,	16,	{0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec} },
+{ 0x0a70,	16,	{0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f} },
+{ 0x0a80,	16,	{0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80} },
+{ 0x0a90,	16,	{0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea} },
+{ 0x0aa0,	16,	{0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x12, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80} },
+{ 0x0ab0,	16,	{0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4} },
+{ 0x0ac0,	16,	{0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f} },
+{ 0x0ad0,	16,	{0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07} },
+{ 0x0ae0,	14,	{0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0aee,	1,	{0x22} },
+{ 0x0aef,	16,	{0x20, 0x14, 0x03, 0x02, 0x0b, 0x81, 0xe5, 0x31, 0x60, 0x02, 0x15, 0x31, 0xe5, 0x36, 0x60, 0x4f} },
+{ 0x0aff,	16,	{0x65, 0x34, 0x70, 0x45, 0xe5, 0x32, 0xf4, 0x60, 0x02, 0x05, 0x32, 0xe5, 0x32, 0xc3, 0x95, 0x41} },
+{ 0x0b0f,	16,	{0x40, 0x3d, 0xc2, 0xaf, 0x30, 0x00, 0x18, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0x90, 0x7f} },
+{ 0x0b1f,	16,	{0xb7, 0xe5, 0x36, 0xf0, 0xc2, 0x00, 0xe4, 0xf5, 0x36, 0xf5, 0x32, 0xf5, 0x34, 0x80, 0x16, 0x90} },
+{ 0x0b2f,	16,	{0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x0f, 0x90, 0x7f, 0xb9, 0xe5, 0x36, 0xf0, 0xd2, 0x00, 0xe4, 0xf5} },
+{ 0x0b3f,	16,	{0x36, 0xf5, 0x32, 0xf5, 0x34, 0xd2, 0xaf, 0x80, 0x06, 0x85, 0x36, 0x34, 0xe4, 0xf5, 0x32, 0xe5} },
+{ 0x0b4f,	16,	{0x2c, 0x60, 0x2f, 0x20, 0x0a, 0x07, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe0, 0x0f, 0xe5, 0x2d, 0x60} },
+{ 0x0b5f,	16,	{0x06, 0xe4, 0xf5, 0x2d, 0x43, 0x33, 0x01, 0xe4, 0xf5, 0x30, 0x80, 0x14, 0xe5, 0x30, 0xd3, 0x95} },
+{ 0x0b6f,	16,	{0x42, 0x50, 0x0d, 0xe5, 0x30, 0xb5, 0x42, 0x06, 0x75, 0x2d, 0x01, 0x43, 0x33, 0x01, 0x05, 0x30} },
+{ 0x0b7f,	3,	{0xc2, 0x0a, 0x22} },
+{ 0x0b82,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x50, 0x02, 0x0b, 0xc9} },
+{ 0x0b8e,	16,	{0x02, 0x0c, 0x8c, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x0b9e,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x0bae,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x0bbe,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0d, 0x5c, 0xe4, 0x7e} },
+{ 0x0bce,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x0bde,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x0bee,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x0bfe,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x0c0e,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x0c1e,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0c27,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x0c37,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x0c47,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0c54,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01} },
+{ 0x0c64,	2,	{0xf3, 0x22} },
+{ 0x0c66,	16,	{0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3} },
+{ 0x0c76,	16,	{0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60} },
+{ 0x0c86,	6,	{0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf} },
+{ 0x0c8c,	16,	{0x75, 0x12, 0x01, 0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3} },
+{ 0x0c9c,	16,	{0x92, 0x12, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde} },
+{ 0x0cac,	16,	{0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9} },
+{ 0x0cbc,	16,	{0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90} },
+{ 0x0ccc,	16,	{0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0xbc, 0xd2, 0x18, 0x12, 0x0f, 0x13, 0xc2} },
+{ 0x0cdc,	16,	{0x13, 0x30, 0x14, 0x03, 0x12, 0x05, 0x74, 0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x11, 0x60, 0x08, 0xe0} },
+{ 0x0cec,	16,	{0xf5, 0x11, 0x12, 0x0a, 0xef, 0x80, 0xea, 0x30, 0x13, 0x07, 0xc2, 0x13, 0x12, 0x08, 0xe0, 0x80} },
+{ 0x0cfc,	11,	{0xe0, 0x30, 0x16, 0xdd, 0xc2, 0x16, 0x12, 0x00, 0x26, 0x80, 0xd6} },
+{ 0x0d07,	1,	{0x22} },
+{ 0x0d08,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x96, 0x74, 0x10} },
+{ 0x0d18,	16,	{0xf0, 0x90, 0x7f, 0x94, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0x9d, 0x04, 0xf0, 0x90, 0x7f, 0x97, 0x74} },
+{ 0x0d28,	16,	{0x20, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0x03, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x84, 0xf0, 0xe4, 0x90} },
+{ 0x0d38,	16,	{0x7f, 0x98, 0xf0, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x90, 0x7f, 0xcb, 0xf0, 0x75} },
+{ 0x0d48,	16,	{0x98, 0x40, 0x43, 0xa8, 0x10, 0x90, 0x7f, 0xde, 0x74, 0x1f, 0xf0, 0x90, 0x7f, 0xdf, 0x74, 0x0f} },
+{ 0x0d58,	4,	{0xf0, 0xd2, 0x14, 0x22} },
+{ 0x0d5c,	12,	{0xc1, 0x13, 0xc1, 0x16, 0xc1, 0x12, 0xc1, 0x95, 0xc1, 0x14, 0xc1, 0x11} },
+{ 0x0d68,	16,	{0x0c, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30} },
+{ 0x0d78,	16,	{0x00, 0x01, 0x33, 0x01, 0x01, 0x32, 0x00, 0x01, 0x37, 0x00, 0x01, 0x50, 0x00, 0x01, 0x36, 0x00} },
+{ 0x0d88,	16,	{0x01, 0x34, 0x00, 0xc1, 0x03, 0xc1, 0x0a, 0xc1, 0x8e, 0xc1, 0x0d, 0xc1, 0x02, 0xc1, 0x0c, 0xc1} },
+{ 0x0d98,	16,	{0x10, 0xc1, 0x08, 0xc1, 0x0f, 0xc1, 0x06, 0xc1, 0x07, 0xc1, 0x04, 0xc1, 0x0b, 0xc1, 0x80, 0xc1} },
+{ 0x0da8,	1,	{0x81} },
+{ 0x0da9,	2,	{0xc1, 0x97} },
+{ 0x0dab,	1,	{0x00} },
+{ 0x0dac,	16,	{0xe4, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9d} },
+{ 0x0dbc,	16,	{0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0x97, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x54} },
+{ 0x0dcc,	16,	{0xfd, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x20, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0, 0x90, 0x7f, 0x9d} },
+{ 0x0ddc,	16,	{0xe0, 0x44, 0xfd, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0, 0xe4} },
+{ 0x0dec,	5,	{0x90, 0x7f, 0x98, 0xf0, 0x22} },
+{ 0x0df1,	2,	{0x8f, 0x13} },
+{ 0x0df3,	16,	{0xe4, 0xf5, 0x14, 0x75, 0x15, 0xff, 0x75, 0x16, 0x0f, 0x75, 0x17, 0xb9, 0xab, 0x15, 0xaa, 0x16} },
+{ 0x0e03,	16,	{0xa9, 0x17, 0x90, 0x00, 0x01, 0x12, 0x0c, 0x27, 0xb4, 0x03, 0x1d, 0xaf, 0x14, 0x05, 0x14, 0xef} },
+{ 0x0e13,	16,	{0xb5, 0x13, 0x01, 0x22, 0x12, 0x0c, 0x0e, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x0e23,	14,	{0x15, 0xff, 0xf5, 0x16, 0x89, 0x17, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0e31,	1,	{0x22} },
+{ 0x0e32,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30} },
+{ 0x0e42,	16,	{0x17, 0x04, 0xc2, 0x17, 0x80, 0x02, 0xd2, 0x16, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x0e52,	14,	{0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e60,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90} },
+{ 0x0e70,	16,	{0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0} },
+{ 0x0e80,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e8a,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2} },
+{ 0x0e9a,	16,	{0x13, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85} },
+{ 0x0eaa,	7,	{0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0eb1,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x0ec1,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x0ed1,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ed6,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x0ee6,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x0ef6,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0f00,	16,	{0x02, 0x0e, 0x8a, 0x00, 0x02, 0x0e, 0xb1, 0x00, 0x02, 0x0e, 0x60, 0x00, 0x02, 0x0e, 0x32, 0x00} },
+{ 0x0f10,	3,	{0x02, 0x0e, 0xd6} },
+{ 0x0f13,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x18, 0x04, 0xe0, 0x44} },
+{ 0x0f23,	16,	{0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x00, 0x03, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x0f33,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x0f38,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x0f48,	1,	{0x22} },
+{ 0x0f49,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x0f64,	16,	{0x12, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x07, 0x01, 0x01, 0x00, 0x01, 0x02} },
+{ 0x0f74,	16,	{0x00, 0x01, 0x09, 0x02, 0x43, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x07} },
+{ 0x0f84,	16,	{0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x0f94,	16,	{0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00} },
+{ 0x0fa4,	16,	{0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x0fb4,	16,	{0x84, 0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x10, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79} },
+{ 0x0fc4,	16,	{0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x0e, 0x03, 0x53, 0x00, 0x65, 0x00, 0x72} },
+{ 0x0fd4,	9,	{0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x00, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa19w_fw.h linux.18p8/drivers/usb/serial/keyspan_usa19w_fw.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa19w_fw.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_usa19w_fw.h	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,304 @@
+/* keyspan_usa19w_fw.h
+  
+   Generated from Keyspan firmware image Wed Jul  5 09:18:29 2000 EST
+   This firmware is for the Keyspan USA-19W Serial Adaptor
+
+   "The firmware contained herein as keyspan_usa19w_fw.h is
+   Copyright (C) 1999-2000 Keyspan, A division of InnoSys Incorporated
+   ("Keyspan"), as an unpublished work.  This notice does not imply
+   unrestricted or public access to this firmware which is a trade secret of
+   Keyspan, and which may not be reproduced, used, sold or transferred to any
+   third party without Keyspan's prior written consent.  All Rights Reserved.
+
+   This firmware may not be modified and may only be used with the Keyspan 
+   USA-19W Serial Adapter.  Distribution and/or Modification of the
+   keyspan.c driver which includes this firmware, in whole or in part,
+   requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa19w_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x09, 0x60} },
+{ 0x0003,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} },
+{ 0x0013,	16,	{0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90} },
+{ 0x0023,	15,	{0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x17, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x22} },
+{ 0x0033,	3,	{0x02, 0x0e, 0x43} },
+{ 0x0036,	12,	{0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0043,	3,	{0x02, 0x0e, 0x00} },
+{ 0x0046,	16,	{0x30, 0x0d, 0x13, 0x12, 0x0e, 0x1f, 0xef, 0xc3, 0x95, 0x14, 0x50, 0x73, 0x90, 0x7f, 0xbf, 0x74} },
+{ 0x0056,	16,	{0x01, 0xf0, 0xc2, 0x0d, 0x80, 0x69, 0x30, 0x0a, 0x34, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x5f} },
+{ 0x0066,	16,	{0x12, 0x0e, 0x1f, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x56, 0x90, 0x7e, 0x40, 0xe0, 0x13, 0x92, 0x0d} },
+{ 0x0076,	16,	{0x90, 0x7f, 0xc7, 0xe0, 0x14, 0xf5, 0x23, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x27, 0x7e, 0x75, 0x28} },
+{ 0x0086,	16,	{0x41, 0x12, 0x08, 0xab, 0xc2, 0x0a, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x32, 0x90, 0x7f, 0xc8} },
+{ 0x0096,	16,	{0xe0, 0x20, 0xe1, 0x2b, 0x12, 0x0e, 0x1f, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x22, 0x90, 0x7d, 0xc0} },
+{ 0x00a6,	16,	{0xe0, 0x13, 0x92, 0x0d, 0x90, 0x7f, 0xc9, 0xe0, 0x14, 0xf5, 0x23, 0x7e, 0x7d, 0x7f, 0xc1, 0x75} },
+{ 0x00b6,	16,	{0x27, 0x7d, 0x75, 0x28, 0xc1, 0x12, 0x08, 0xab, 0xd2, 0x0a, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0x90} },
+{ 0x00c6,	16,	{0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x4d, 0x53, 0x11, 0x80, 0x12, 0x0e, 0x2b, 0xef} },
+{ 0x00d6,	16,	{0x42, 0x11, 0x12, 0x0c, 0xc8, 0x8f, 0x34, 0xef, 0xc3, 0x95, 0x13, 0x50, 0x0f, 0x12, 0x0d, 0xf1} },
+{ 0x00e6,	16,	{0xef, 0x30, 0xe0, 0x08, 0xe5, 0x11, 0x20, 0xe7, 0x03, 0x30, 0x10, 0x5b, 0xc2, 0x10, 0xe5, 0x34} },
+{ 0x00f6,	16,	{0x70, 0x04, 0xf5, 0x11, 0x80, 0x51, 0xe5, 0x11, 0x30, 0xe7, 0x26, 0xe5, 0x34, 0xd3, 0x94, 0x20} },
+{ 0x0106,	16,	{0x40, 0x03, 0x75, 0x34, 0x20, 0x85, 0x34, 0x23, 0x7e, 0x7e, 0x7f, 0x80, 0x75, 0x27, 0x7e, 0x75} },
+{ 0x0116,	16,	{0x28, 0x80, 0xaf, 0x11, 0x12, 0x0b, 0x01, 0xe5, 0x34, 0x25, 0xe0, 0x90, 0x7f, 0xb7, 0xf0, 0x80} },
+{ 0x0126,	16,	{0x26, 0xe5, 0x34, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x34, 0x3f, 0x85, 0x34, 0x23, 0xe4, 0x90} },
+{ 0x0136,	16,	{0x7e, 0x80, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x27, 0x7e, 0x75, 0x28, 0x81, 0x12, 0x08, 0xd0} },
+{ 0x0146,	16,	{0xe5, 0x34, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90, 0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x0b} },
+{ 0x0156,	16,	{0x03, 0x02, 0x03, 0xb2, 0xe4, 0xf5, 0x33, 0x74, 0x40, 0x25, 0x33, 0xf5, 0x82, 0xe4, 0x34, 0x7c} },
+{ 0x0166,	16,	{0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x33, 0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x00, 0x24, 0x00} },
+{ 0x0176,	16,	{0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x08, 0x3b, 0x05, 0x33, 0xe5, 0x33, 0xb4, 0x20, 0xd7} },
+{ 0x0186,	16,	{0x90, 0x7e, 0x00, 0xe0, 0x60, 0x6e, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12, 0x0c, 0xa3} },
+{ 0x0196,	16,	{0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x0b, 0xe5, 0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12, 0x0c, 0x0b} },
+{ 0x01a6,	16,	{0xd2, 0x0e, 0xd2, 0x0f, 0x75, 0x34, 0x04, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x05, 0xc2, 0x0f, 0x43} },
+{ 0x01b6,	16,	{0x34, 0xc0, 0x90, 0x7e, 0x04, 0xe0, 0xb4, 0x01, 0x07, 0xc2, 0x0f, 0x43, 0x34, 0x0b, 0x80, 0x10} },
+{ 0x01c6,	16,	{0x90, 0x7e, 0x04, 0xe0, 0x60, 0x07, 0xc2, 0x0e, 0x43, 0x34, 0x09, 0x80, 0x03, 0x43, 0x34, 0x02} },
+{ 0x01d6,	16,	{0x7f, 0x03, 0xad, 0x34, 0x12, 0x0c, 0xa3, 0x43, 0x19, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0} },
+{ 0x01e6,	16,	{0x90, 0xc0, 0x00, 0xe5, 0x19, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x16, 0x44, 0x06} },
+{ 0x01f6,	16,	{0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x18} },
+{ 0x0206,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x18, 0xf0, 0x90, 0x7e, 0x07, 0xe0} },
+{ 0x0216,	16,	{0x60, 0x42, 0x90, 0x7e, 0x13, 0xe0, 0x60, 0x05, 0x43, 0x15, 0x04, 0x80, 0x03, 0x53, 0x15, 0xfb} },
+{ 0x0226,	16,	{0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0xa3, 0x90, 0x7e, 0x08, 0xe0, 0x60, 0x05, 0x43, 0x17, 0x80} },
+{ 0x0236,	16,	{0x80, 0x03, 0x53, 0x17, 0x7f, 0x53, 0x17, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x17} },
+{ 0x0246,	16,	{0x02, 0xa3, 0xe0, 0xff, 0x12, 0x0c, 0x57, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x0c, 0x7d, 0xaf} },
+{ 0x0256,	16,	{0x17, 0x12, 0x0c, 0x31, 0x90, 0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x19} },
+{ 0x0266,	16,	{0x01, 0x80, 0x03, 0x53, 0x19, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5} },
+{ 0x0276,	16,	{0x19, 0xf0, 0x90, 0x7e, 0x0c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x19, 0x02, 0x80} },
+{ 0x0286,	16,	{0x03, 0x53, 0x19, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x19, 0xf0} },
+{ 0x0296,	16,	{0x90, 0x7e, 0x12, 0xe0, 0xf5, 0x13, 0xa3, 0xe0, 0x13, 0x92, 0x11, 0xa3, 0xe0, 0xf5, 0x14, 0xa3} },
+{ 0x02a6,	16,	{0xe0, 0x60, 0x05, 0x43, 0x19, 0x10, 0x80, 0x03, 0x53, 0x19, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14} },
+{ 0x02b6,	16,	{0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x19, 0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x18, 0xbf} },
+{ 0x02c6,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f} },
+{ 0x02d6,	16,	{0x98, 0x74, 0x11, 0xf0, 0x12, 0x0d, 0xe5, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x15} },
+{ 0x02e6,	16,	{0xfd, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0xa3, 0xe4, 0xf5, 0x0e, 0xf5, 0x0d, 0xd2, 0x0c, 0x90} },
+{ 0x02f6,	16,	{0x7e, 0x17, 0xe0, 0x60, 0x0f, 0x43, 0x15, 0x02, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0xa3, 0x75} },
+{ 0x0306,	16,	{0x0d, 0x01, 0xd2, 0x0c, 0x90, 0x7e, 0x18, 0xe0, 0x60, 0x1b, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0} },
+{ 0x0316,	16,	{0xe5, 0x16, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9} },
+{ 0x0326,	16,	{0xf0, 0xd2, 0x0a, 0xc2, 0x0d, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11, 0x43, 0x18, 0x40, 0x90, 0x7f} },
+{ 0x0336,	16,	{0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0} },
+{ 0x0346,	16,	{0x60, 0x0f, 0x53, 0x15, 0xfe, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c, 0xa3, 0x75, 0x0f, 0x01, 0xd2} },
+{ 0x0356,	16,	{0x0c, 0x90, 0x7e, 0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x15, 0x01, 0xe4, 0xff, 0xad, 0x15, 0x12, 0x0c} },
+{ 0x0366,	16,	{0xa3, 0xe4, 0xf5, 0x0f, 0xd2, 0x0c, 0x90, 0x7e, 0x1c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0376,	16,	{0x12, 0xf0, 0xe5, 0x16, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02} },
+{ 0x0386,	16,	{0xd2, 0x10, 0x90, 0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x10, 0x01, 0xe4, 0xf5, 0x12, 0xd2, 0x0c} },
+{ 0x0396,	16,	{0x90, 0x7e, 0x1f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74} },
+{ 0x03a6,	16,	{0x15, 0xf0, 0x74, 0x35, 0xf0, 0xc2, 0x0b, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30, 0x13, 0x71, 0xe5} },
+{ 0x03b6,	16,	{0x12, 0x60, 0x02, 0x15, 0x12, 0xe5, 0x2e, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x2e, 0x80, 0x60} },
+{ 0x03c6,	16,	{0x75, 0x2e, 0x0a, 0x12, 0x0d, 0xe5, 0xef, 0x54, 0x01, 0xf5, 0x34, 0x65, 0x0e, 0x60, 0x07, 0x85} },
+{ 0x03d6,	16,	{0x34, 0x0e, 0xd2, 0x0c, 0x80, 0x11, 0x12, 0x0e, 0x37, 0xef, 0x54, 0x10, 0xf5, 0x34, 0x65, 0x09} },
+{ 0x03e6,	16,	{0x60, 0x05, 0x85, 0x34, 0x09, 0xd2, 0x0c, 0x12, 0x0e, 0x37, 0xef, 0x54, 0x80, 0xf5, 0x34, 0x65} },
+{ 0x03f6,	16,	{0x0a, 0x60, 0x05, 0x85, 0x34, 0x0a, 0xd2, 0x0c, 0x12, 0x0e, 0x37, 0xef, 0x54, 0x20, 0xf5, 0x34} },
+{ 0x0406,	16,	{0x65, 0x0b, 0x60, 0x08, 0x85, 0x34, 0x0b, 0x30, 0x0e, 0x02, 0xd2, 0x0c, 0x12, 0x0e, 0x37, 0xef} },
+{ 0x0416,	16,	{0x54, 0x40, 0xf5, 0x34, 0x65, 0x0c, 0x60, 0x08, 0x85, 0x34, 0x0c, 0x30, 0x0f, 0x02, 0xd2, 0x0c} },
+{ 0x0426,	16,	{0x30, 0x13, 0x2a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09} },
+{ 0x0436,	16,	{0xe0, 0xf5, 0x30, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x31, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90} },
+{ 0x0446,	16,	{0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f, 0xc2} },
+{ 0x0456,	16,	{0xe0, 0x30, 0xe1, 0x03, 0x02, 0x05, 0x17, 0xe5, 0x25, 0x70, 0x40, 0x30, 0x0c, 0x39, 0xe5, 0x12} },
+{ 0x0466,	16,	{0x70, 0x35, 0xc2, 0x0c, 0xf5, 0x33, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x08, 0x25, 0x33, 0xf9, 0xee} },
+{ 0x0476,	16,	{0x34, 0x00, 0xfa, 0x12, 0x07, 0xf5, 0xff, 0x74, 0x80, 0x25, 0x33, 0xf5, 0x82, 0xe4, 0x34, 0x7b} },
+{ 0x0486,	16,	{0xf5, 0x83, 0xef, 0xf0, 0x05, 0x33, 0xe5, 0x33, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09} },
+{ 0x0496,	16,	{0xf0, 0x75, 0x12, 0x10, 0xe4, 0xf5, 0x10, 0x75, 0x25, 0x02, 0x22, 0xe5, 0x25, 0x64, 0x02, 0x70} },
+{ 0x04a6,	16,	{0x36, 0x30, 0x05, 0x2f, 0xc2, 0x05, 0xf5, 0x33, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x29, 0x25, 0x33} },
+{ 0x04b6,	16,	{0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x07, 0xf5, 0xff, 0x74, 0x80, 0x25, 0x33, 0xf5, 0x82, 0xe4} },
+{ 0x04c6,	16,	{0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x33, 0xe5, 0x33, 0xb4, 0x05, 0xdb, 0x90, 0x7f, 0xc3} },
+{ 0x04d6,	16,	{0x74, 0x05, 0xf0, 0x75, 0x25, 0x03, 0x22, 0xe5, 0x30, 0x60, 0x33, 0x75, 0x2f, 0x03, 0x15, 0x30} },
+{ 0x04e6,	16,	{0xe4, 0xf5, 0x33, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2f, 0x25, 0x33, 0xf9, 0xee, 0x34, 0x00, 0xfa} },
+{ 0x04f6,	16,	{0x12, 0x07, 0xf5, 0xff, 0x74, 0x80, 0x25, 0x33, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef} },
+{ 0x0506,	16,	{0xf0, 0x05, 0x33, 0xe5, 0x33, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4, 0xf5} },
+{ 0x0516,	1,	{0x25} },
+{ 0x0517,	1,	{0x22} },
+{ 0x0518,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x08, 0x85, 0x05, 0xe8, 0x00, 0x06, 0x5c, 0x01, 0x06, 0xc9, 0x03} },
+{ 0x0528,	16,	{0x05, 0x3b, 0x06, 0x05, 0xdb, 0x08, 0x05, 0xd5, 0x09, 0x05, 0xbd, 0x0a, 0x05, 0xcc, 0x0b, 0x00} },
+{ 0x0538,	16,	{0x00, 0x07, 0x19, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02} },
+{ 0x0548,	16,	{0x70, 0x69, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x07} },
+{ 0x0558,	16,	{0x20, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0a, 0x71, 0x8b, 0x33, 0x8a, 0x34, 0x89, 0x35, 0xea} },
+{ 0x0568,	16,	{0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5} },
+{ 0x0578,	16,	{0xf0, 0x02, 0x07, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x07, 0x20, 0x90, 0x7f} },
+{ 0x0588,	16,	{0xea, 0xe0, 0xff, 0x12, 0x0a, 0xc0, 0x8b, 0x33, 0x8a, 0x34, 0x89, 0x35, 0xea, 0x49, 0x60, 0x11} },
+{ 0x0598,	16,	{0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x07} },
+{ 0x05a8,	16,	{0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x07, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x05b8,	16,	{0x01, 0xf0, 0x02, 0x07, 0x20, 0x90, 0x7f, 0x00, 0xe5, 0x24, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01} },
+{ 0x05c8,	16,	{0xf0, 0x02, 0x07, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x24, 0x02, 0x07, 0x20, 0x12, 0x07, 0x28} },
+{ 0x05d8,	16,	{0x02, 0x07, 0x20, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x07, 0x20} },
+{ 0x05e8,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
+{ 0x05f8,	16,	{0x01, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x06, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
+{ 0x0608,	16,	{0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x07, 0x20, 0xe4, 0x90, 0x7f, 0x00} },
+{ 0x0618,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x07, 0x20, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x0628,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x0638,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
+{ 0x0648,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x07, 0x20, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x0658,	16,	{0xf0, 0x02, 0x07, 0x20, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1e, 0x24, 0x02, 0x60, 0x03} },
+{ 0x0668,	16,	{0x02, 0x07, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x06, 0x12, 0x0e, 0x47, 0x02, 0x07, 0x20} },
+{ 0x0678,	16,	{0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x07, 0x20, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38} },
+{ 0x0688,	16,	{0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f} },
+{ 0x0698,	16,	{0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec} },
+{ 0x06a8,	16,	{0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f} },
+{ 0x06b8,	16,	{0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x60, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80} },
+{ 0x06c8,	16,	{0x57, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x24, 0x02, 0x70, 0x4b, 0x90, 0x7f, 0xea} },
+{ 0x06d8,	16,	{0xe0, 0xb4, 0x01, 0x05, 0x12, 0x0d, 0xfd, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0} },
+{ 0x06e8,	16,	{0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff} },
+{ 0x06f8,	16,	{0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0708,	16,	{0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80} },
+{ 0x0718,	15,	{0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0727,	1,	{0x22} },
+{ 0x0728,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} },
+{ 0x0738,	16,	{0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0748,	16,	{0x18, 0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4} },
+{ 0x0758,	16,	{0xf5, 0x08, 0x7f, 0x01, 0x7b, 0x00, 0x74, 0x08, 0x2f, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12} },
+{ 0x0768,	16,	{0x08, 0x3b, 0x0f, 0xbf, 0x09, 0xee, 0x75, 0x13, 0x01, 0xe4, 0xf5, 0x12, 0xf5, 0x2e, 0xf5, 0x11} },
+{ 0x0778,	16,	{0xc2, 0x0c, 0xc2, 0x10, 0xc2, 0x0b, 0xc2, 0x0d, 0xc2, 0x04, 0xd2, 0x0a, 0xd2, 0x09, 0x90, 0x7f} },
+{ 0x0788,	16,	{0x98, 0x74, 0x13, 0xf0, 0x75, 0x18, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4} },
+{ 0x0798,	16,	{0xfd, 0x12, 0x0c, 0xa3, 0x7f, 0x10, 0x8f, 0x17, 0x12, 0x0c, 0x31, 0x90, 0x7f, 0x98, 0x74, 0x12} },
+{ 0x07a8,	16,	{0xf0, 0x7f, 0x01, 0x8f, 0x16, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x07b8,	16,	{0x14, 0xf0, 0x75, 0x19, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x0c} },
+{ 0x07c8,	16,	{0xa3, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x15, 0x12, 0x0c, 0xa3, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x07d8,	16,	{0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x0c, 0xa3, 0x7f, 0x01} },
+{ 0x07e8,	12,	{0x12, 0x0d, 0x7d, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x0c, 0xa3, 0xd2, 0x03} },
+{ 0x07f4,	1,	{0x22} },
+{ 0x07f5,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x0805,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x080e,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x081e,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x082e,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x083b,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01} },
+{ 0x084b,	2,	{0xf3, 0x22} },
+{ 0x084d,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x085d,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x086d,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x087d,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x0885,	16,	{0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3} },
+{ 0x0895,	16,	{0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60} },
+{ 0x08a5,	6,	{0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf} },
+{ 0x08ab,	16,	{0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x23, 0xe5, 0x28, 0xf5, 0x82, 0xe5, 0x27, 0xf5, 0x83} },
+{ 0x08bb,	16,	{0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86} },
+{ 0x08cb,	16,	{0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x23, 0xe5, 0x28, 0xf5} },
+{ 0x08db,	16,	{0x82, 0xe5, 0x27, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0} },
+{ 0x08eb,	16,	{0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0} },
+{ 0x08fb,	16,	{0xaf, 0x23, 0xe5, 0x28, 0xf5, 0x82, 0xe5, 0x27, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0} },
+{ 0x090b,	16,	{0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90} },
+{ 0x091b,	16,	{0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x23, 0xe5, 0x28, 0xf5, 0x82, 0xe5, 0x27, 0xf5, 0x83, 0xc2} },
+{ 0x092b,	16,	{0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05} },
+{ 0x093b,	4,	{0x86, 0xd2, 0xaf, 0x22} },
+{ 0x093f,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x094f,	1,	{0x22} },
+{ 0x0950,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x0960,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x3a, 0x02, 0x09, 0xa7} },
+{ 0x096c,	16,	{0x02, 0x09, 0xec, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x097c,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x098c,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x099c,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0d, 0x9e, 0xe4, 0x7e} },
+{ 0x09ac,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x09bc,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x09cc,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x09dc,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x09ec,	16,	{0xd2, 0x12, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x0e, 0x47, 0xd2, 0xe8, 0x43, 0xd8} },
+{ 0x09fc,	16,	{0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff} },
+{ 0x0a0c,	16,	{0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0} },
+{ 0x0a1c,	16,	{0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x13, 0x12, 0x0d, 0x37} },
+{ 0x0a2c,	16,	{0xc2, 0x02, 0xe4, 0xf5, 0x26, 0xf5, 0x2e, 0xc2, 0x07, 0xc2, 0x03, 0x90, 0x7f, 0xa1, 0x04, 0xf0} },
+{ 0x0a3c,	16,	{0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x32, 0x60, 0x10, 0x30, 0x03, 0x05, 0xd2, 0x13, 0x12, 0x00, 0x46} },
+{ 0x0a4c,	16,	{0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x32, 0x80, 0x08, 0x30, 0x03, 0x05, 0xc2, 0x13, 0x12, 0x00, 0x46} },
+{ 0x0a5c,	16,	{0x30, 0x02, 0x07, 0xc2, 0x02, 0x12, 0x05, 0x18, 0x80, 0xd6, 0x30, 0x08, 0xd3, 0xc2, 0x08, 0x12} },
+{ 0x0a6c,	4,	{0x0b, 0x68, 0x80, 0xcc} },
+{ 0x0a70,	1,	{0x22} },
+{ 0x0a71,	16,	{0xe4, 0xfe, 0x75, 0x38, 0xff, 0x75, 0x39, 0x19, 0x75, 0x3a, 0x12, 0xab, 0x38, 0xaa, 0x39, 0xa9} },
+{ 0x0a81,	16,	{0x3a, 0x90, 0x00, 0x01, 0x12, 0x08, 0x0e, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0a91,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x08, 0x4d, 0x85, 0xf0, 0x36, 0xf5, 0x37, 0x62, 0x36} },
+{ 0x0aa1,	16,	{0xe5, 0x36, 0x62, 0x37, 0xe5, 0x37, 0x62, 0x36, 0x29, 0xfd, 0xe5, 0x36, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0ab1,	14,	{0x38, 0xff, 0xf5, 0x39, 0x89, 0x3a, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0abf,	1,	{0x22} },
+{ 0x0ac0,	2,	{0x8f, 0x36} },
+{ 0x0ac2,	16,	{0xe4, 0xf5, 0x37, 0x75, 0x38, 0xff, 0x75, 0x39, 0x19, 0x75, 0x3a, 0x86, 0xab, 0x38, 0xaa, 0x39} },
+{ 0x0ad2,	16,	{0xa9, 0x3a, 0x90, 0x00, 0x01, 0x12, 0x08, 0x0e, 0xb4, 0x03, 0x1d, 0xaf, 0x37, 0x05, 0x37, 0xef} },
+{ 0x0ae2,	16,	{0xb5, 0x36, 0x01, 0x22, 0x12, 0x07, 0xf5, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x0af2,	14,	{0x38, 0xff, 0xf5, 0x39, 0x89, 0x3a, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0b00,	1,	{0x22} },
+{ 0x0b01,	16,	{0x8f, 0x35, 0x05, 0x28, 0xe5, 0x28, 0xae, 0x27, 0x70, 0x02, 0x05, 0x27, 0x14, 0xf5, 0x82, 0x8e} },
+{ 0x0b11,	16,	{0x83, 0xe5, 0x35, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x28, 0xe5, 0x28, 0xac, 0x27, 0x70, 0x02, 0x05} },
+{ 0x0b21,	16,	{0x27, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x23, 0xe5, 0x23, 0x60, 0x0a, 0x12, 0x0e} },
+{ 0x0b31,	9,	{0x2b, 0x8f, 0x35, 0xef, 0x42, 0x11, 0x80, 0xca, 0x22} },
+{ 0x0b3a,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30} },
+{ 0x0b4a,	16,	{0x14, 0x04, 0xc2, 0x14, 0x80, 0x02, 0xd2, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x0b5a,	14,	{0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0b68,	16,	{0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x33, 0x12, 0x00, 0x03, 0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0} },
+{ 0x0b78,	16,	{0x12, 0x09, 0x50, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x0e, 0x30, 0x01, 0x05, 0x12, 0x0d, 0xcf} },
+{ 0x0b88,	11,	{0x80, 0x06, 0x12, 0x0d, 0x5c, 0xef, 0x60, 0xe1, 0x12, 0x07, 0x28} },
+{ 0x0b93,	1,	{0x22} },
+{ 0x0b94,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90} },
+{ 0x0ba4,	16,	{0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0} },
+{ 0x0bb4,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bbe,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2} },
+{ 0x0bce,	16,	{0x02, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85} },
+{ 0x0bde,	7,	{0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0be5,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0bf5,	16,	{0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54} },
+{ 0x0c05,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x0c0b,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0c1b,	16,	{0x11, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54} },
+{ 0x0c2b,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x0c31,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0c41,	16,	{0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54} },
+{ 0x0c51,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x0c57,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0c67,	16,	{0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54} },
+{ 0x0c77,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x0c7d,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0c8d,	16,	{0x16, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54} },
+{ 0x0c9d,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x0ca3,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x18, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f} },
+{ 0x0cb3,	16,	{0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90} },
+{ 0x0cc3,	5,	{0xc0, 0x00, 0xed, 0xf0, 0x22} },
+{ 0x0cc8,	16,	{0x12, 0x0e, 0x13, 0x8f, 0x35, 0x12, 0x0e, 0x13, 0x8f, 0x36, 0xe5, 0x35, 0x65, 0x36, 0x60, 0x12} },
+{ 0x0cd8,	16,	{0x12, 0x0e, 0x13, 0x8f, 0x35, 0xe5, 0x35, 0x65, 0x36, 0x60, 0x07, 0x12, 0x0e, 0x13, 0x8f, 0x36} },
+{ 0x0ce8,	4,	{0x80, 0xe8, 0xaf, 0x35} },
+{ 0x0cec,	1,	{0x22} },
+{ 0x0ced,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x0cfd,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x0d0d,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d12,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x0d22,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x0d32,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d37,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x13, 0x04, 0xe0, 0x44} },
+{ 0x0d47,	16,	{0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0d, 0xb8, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x0d57,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x0d5c,	16,	{0x90, 0x7f, 0xd8, 0xe0, 0xf5, 0x34, 0x12, 0x07, 0x28, 0x12, 0x0e, 0x37, 0xef, 0x30, 0xe6, 0x0b} },
+{ 0x0d6c,	16,	{0x90, 0x7f, 0xd8, 0xe0, 0x65, 0x34, 0x60, 0xf1, 0x7f, 0x01, 0x22, 0x12, 0x00, 0x03, 0x7f, 0x00} },
+{ 0x0d7c,	1,	{0x22} },
+{ 0x0d7d,	16,	{0xae, 0x07, 0xe4, 0xff, 0xe5, 0x15, 0x54, 0x7f, 0xfd, 0x12, 0x0c, 0xa3, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0d8d,	16,	{0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x15, 0x44, 0x80, 0xfd, 0x12, 0x0c, 0xa3} },
+{ 0x0d9d,	1,	{0x22} },
+{ 0x0d9e,	16,	{0x05, 0x29, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x2f, 0x03, 0x00, 0x00, 0xc1, 0x02, 0xc1, 0x08} },
+{ 0x0dae,	7,	{0xc1, 0x01, 0xc1, 0x86, 0x01, 0x25, 0x00} },
+{ 0x0db5,	2,	{0xc1, 0x94} },
+{ 0x0db7,	1,	{0x00} },
+{ 0x0db8,	16,	{0x8e, 0x34, 0x8f, 0x35, 0xe5, 0x35, 0x15, 0x35, 0xae, 0x34, 0x70, 0x02, 0x15, 0x34, 0x4e, 0x60} },
+{ 0x0dc8,	7,	{0x05, 0x12, 0x09, 0x3f, 0x80, 0xee, 0x22} },
+{ 0x0dcf,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e, 0x00, 0x12, 0x0d, 0xb8, 0x90, 0x7f} },
+{ 0x0ddf,	6,	{0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x0de5,	12,	{0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0df1,	12,	{0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0dfd,	3,	{0xd2, 0x01, 0x22} },
+{ 0x0e00,	16,	{0x02, 0x0b, 0xbe, 0x00, 0x02, 0x0c, 0xed, 0x00, 0x02, 0x0b, 0x94, 0x00, 0x02, 0x0b, 0x3a, 0x00} },
+{ 0x0e10,	3,	{0x02, 0x0d, 0x12} },
+{ 0x0e13,	12,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0e1f,	12,	{0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0e2b,	12,	{0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0e37,	12,	{0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0e43,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x0e47,	3,	{0xc2, 0x01, 0x22} },
+{ 0x1900,	16,	{0x12, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x08, 0x01, 0x00, 0x00, 0x01, 0x02} },
+{ 0x1910,	16,	{0x00, 0x01, 0x09, 0x02, 0x74, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e} },
+{ 0x1920,	16,	{0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1930,	16,	{0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1940,	16,	{0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1950,	16,	{0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02} },
+{ 0x1960,	16,	{0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00} },
+{ 0x1970,	16,	{0x00, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x07} },
+{ 0x1980,	16,	{0x05, 0x87, 0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00} },
+{ 0x1990,	16,	{0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00} },
+{ 0x19a0,	16,	{0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00} },
+{ 0x19b0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00} },
+{ 0x19c0,	16,	{0x6f, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x19d0,	16,	{0x2e, 0x00, 0x36, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00} },
+{ 0x19e0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00} },
+{ 0x19f0,	16,	{0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00} },
+{ 0x1a00,	10,	{0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa26msg.h linux.18p8/drivers/usb/serial/keyspan_usa26msg.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa26msg.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_usa26msg.h	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,248 @@
+/*
+	usa26msg.h
+
+	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+	This file is available under a BSD-style copyright
+
+	Keyspan USB Async Firmware to run on Anchor EZ-USB
+
+	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 this licence text
+   	without modification, this list of conditions, and the following
+   	disclaimer.  The following copyright notice must appear immediately at
+   	the beginning of all source files:
+
+        	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+
+        	This file is available under a BSD-style copyright
+
+	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 InnoSys Incorprated may not be used to endorse or promote
+   	products derived from this software without specific prior written
+   	permission.
+
+	THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``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 OR CONTRIBUTORS 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.    
+
+	Third revision: USA28X version (aka USA26)
+
+	Buffer formats for RX/TX data messages are not defined by
+	a structure, but are described here:
+
+	USB OUT (host -> USA26, transmit) messages contain a 
+	REQUEST_ACK indicator (set to 0xff to request an ACK at the 
+	completion of transmit; 0x00 otherwise), followed by data:
+
+		RQSTACK DAT DAT DAT ...
+
+	with a total data length of 63.
+
+	USB IN (USA26 -> host, receive) messages contain either a zero
+	flag (indicating no error in any data bytes):
+
+		00 DAT DAT DAT ...
+
+	for a total of 63 data bytes, or a non-zero status flag (indicating 
+	that all data bytes will be preceded by status flag):
+
+		STAT DAT STAT DAT STAT DAT ...
+
+	for a total of 32 data bytes.  The valid bits in the STAT bytes are:
+
+		OVERRUN	0x02
+		PARITY	0x04
+		FRAMING	0x08
+		BREAK	0x10
+
+	Note: a "no status" RX data message (first byte zero) can serve as
+	a "break off" indicator.
+
+	revision history:
+
+	1999feb10	add reportHskiaChanges to allow us to ignore them
+	1999feb10	add txAckThreshold for fast+loose throughput enhancement
+	1999mar30	beef up support for RX error reporting
+	1999apr14	add resetDataToggle to control message
+	2000jan04	merge with usa17msg.h
+	2000jun01	add extended BSD-style copyright text
+
+	Note on shared names:
+
+	In the case of fields which have been merged between the USA17
+	and USA26 definitions, the USA26 definition is the first part
+	of the name and the USA17 definition is the second part of the
+	name; both meanings are described below.
+*/
+
+#ifndef	__USA26MSG__
+#define	__USA26MSG__
+
+#ifndef __stubs__
+#include "datadefs.h"
+#endif
+
+typedef struct txAckMessage
+{
+	u8	dummy;
+} txAckMessage;
+
+typedef struct portControlMessage
+{
+	/*
+		there are three types of "commands" sent in the control message:
+
+		1.	configuration changes which must be requested by setting
+			the corresponding "set" flag (and should only be requested
+			when necessary, to reduce overhead on the USA26):
+	*/
+	u8	setClocking,	// BOTH: host requests baud rate be set
+		baudLo,			// BOTH: host does baud divisor calculation
+		baudHi,			// BOTH: baudHi is only used for first port (gives lower rates)
+		externalClock_txClocking,
+						// USA26: 0=internal, other=external
+						// USA17: 0=internal, other=external/RI
+		rxClocking,		// USA17: 0=internal, 1=external/RI, other=external/DSR
+
+
+		setLcr,			// BOTH: host requests lcr be set
+		lcr,			// BOTH: use PARITY, STOPBITS, DATABITS below
+
+		setFlowControl,	// BOTH: host requests flow control be set
+		ctsFlowControl,	// BOTH: 1=use CTS flow control, 0=don't
+		xonFlowControl,	// BOTH: 1=use XON/XOFF flow control, 0=don't
+		xonChar,		// BOTH: specified in current character format
+		xoffChar,		// BOTH: specified in current character format
+
+		setTxTriState_setRts,
+						// USA26: host requests TX tri-state be set
+						// USA17: host requests RTS output be set
+		txTriState_rts,	// BOTH: 1=active (normal), 0=tristate (off)
+
+		setHskoa_setDtr,
+						// USA26: host requests HSKOA output be set
+						// USA17: host requests DTR output be set
+		hskoa_dtr,		// BOTH: 1=on, 0=off
+
+		setPrescaler,	// USA26: host requests prescalar be set (default: 13)
+		prescaler;		// BOTH: specified as N/8; values 8-ff are valid
+						// must be set any time internal baud rate is set;
+						// must not be set when external clocking is used
+						// note: in USA17, prescaler is applied whenever
+						// setClocking is requested
+
+	/*
+		3.	configuration data which is simply used as is (no overhead,
+			but must be specified correctly in every host message).
+	*/
+	u8	forwardingLength,  // BOTH: forward when this number of chars available
+		reportHskiaChanges_dsrFlowControl,
+						// USA26: 1=normal; 0=ignore external clock
+						// USA17: 1=use DSR flow control, 0=don't
+		txAckThreshold,	// BOTH: 0=not allowed, 1=normal, 2-255 deliver ACK faster
+		loopbackMode;	// BOTH: 0=no loopback, 1=loopback enabled
+
+	/*
+		4.	commands which are flags only; these are processed in order
+			(so that, e.g., if both _txOn and _txOff flags are set, the
+			port ends in a TX_OFF state); any non-zero value is respected
+	*/
+	u8	_txOn,			// BOTH: enable transmitting (and continue if there's data)
+		_txOff,			// BOTH: stop transmitting
+		txFlush,		// BOTH: toss outbound data
+		txBreak,		// BOTH: turn on break (cleared by _txOn)
+		rxOn,			// BOTH: turn on receiver
+		rxOff,			// BOTH: turn off receiver
+		rxFlush,		// BOTH: toss inbound data
+		rxForward,		// BOTH: forward all inbound data, NOW (as if fwdLen==1)
+		returnStatus,	// BOTH: return current status (even if it hasn't changed)
+		resetDataToggle;// BOTH: reset data toggle state to DATA0
+	
+} portControlMessage;
+
+// defines for bits in lcr
+#define	USA_DATABITS_5		0x00
+#define	USA_DATABITS_6		0x01
+#define	USA_DATABITS_7		0x02
+#define	USA_DATABITS_8		0x03
+#define	STOPBITS_5678_1	0x00	// 1 stop bit for all byte sizes
+#define	STOPBITS_5_1p5	0x04	// 1.5 stop bits for 5-bit byte
+#define	STOPBITS_678_2	0x04	// 2 stop bits for 6/7/8-bit byte
+#define	USA_PARITY_NONE		0x00
+#define	USA_PARITY_ODD		0x08
+#define	USA_PARITY_EVEN		0x18
+#define	PARITY_1		0x28
+#define	PARITY_0		0x38
+
+// all things called "StatusMessage" are sent on the status endpoint
+
+typedef struct portStatusMessage	// one for each port
+{
+	u8	port,			// BOTH: 0=first, 1=second, other=see below
+		hskia_cts,		// USA26: reports HSKIA pin
+						// USA17: reports CTS pin
+		gpia_dcd,		// USA26: reports GPIA pin
+						// USA17: reports DCD pin
+		dsr,			// USA17: reports DSR pin
+		ri,				// USA17: reports RI pin
+		_txOff,			// port has been disabled (by host)
+		_txXoff,		// port is in XOFF state (either host or RX XOFF)
+		rxEnabled,		// as configured by rxOn/rxOff 1=on, 0=off
+		controlResponse;// 1=a control message has been processed
+} portStatusMessage;
+
+// bits in RX data message when STAT byte is included
+#define	RXERROR_OVERRUN	0x02
+#define	RXERROR_PARITY	0x04
+#define	RXERROR_FRAMING	0x08
+#define	RXERROR_BREAK	0x10
+
+typedef struct globalControlMessage
+{
+	u8	sendGlobalStatus,	// 2=request for two status responses
+		resetStatusToggle,	// 1=reset global status toggle
+		resetStatusCount;	// a cycling value
+} globalControlMessage;
+
+typedef struct globalStatusMessage
+{
+	u8	port,				// 3
+		sendGlobalStatus,	// from request, decremented
+		resetStatusCount;	// as in request
+} globalStatusMessage;
+
+typedef struct globalDebugMessage
+{
+	u8	port,				// 2
+		a,
+		b,
+		c,
+		d;
+} globalDebugMessage;
+
+// ie: the maximum length of an EZUSB endpoint buffer
+#define	MAX_DATA_LEN			64
+
+// update status approx. 60 times a second (16.6666 ms)
+#define	STATUS_UPDATE_INTERVAL	16
+
+// status rationing tuning value (each port gets checked each n ms)
+#define	STATUS_RATION	10
+
+#endif
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa28_fw.h linux.18p8/drivers/usb/serial/keyspan_usa28_fw.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa28_fw.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_usa28_fw.h	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,462 @@
+/* keyspan_usa28_fw.h
+  
+   Generated from Keyspan firmware image Wed Jul  5 09:18:29 2000 EST
+   This firmware is for the Keyspan USA-28 Serial Adaptor
+
+   "The firmware contained herein as keyspan_usa28_fw.h is
+   Copyright (C) 1999-2000 Keyspan, A division of InnoSys Incorporated
+   ("Keyspan"), as an unpublished work.  This notice does not imply
+   unrestricted or public access to this firmware which is a trade secret of
+   Keyspan, and which may not be reproduced, used, sold or transferred to any
+   third party without Keyspan's prior written consent.  All Rights Reserved.
+
+   This firmware may not be modified and may only be used with the Keyspan 
+   USA-28 Serial Adapter.  Distribution and/or Modification of the
+   keyspan.c driver which includes this firmware, in whole or in part,
+   requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa28_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x15, 0xc5} },
+{ 0x0003,	3,	{0x02, 0x00, 0x46} },
+{ 0x0006,	16,	{0x8e, 0x12, 0x8f, 0x13, 0xe5, 0x13, 0x15, 0x13, 0xae, 0x12, 0x70, 0x02, 0x15, 0x12, 0x4e, 0x60} },
+{ 0x0016,	7,	{0x05, 0x12, 0x18, 0x7d, 0x80, 0xee, 0x22} },
+{ 0x001d,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x0023,	3,	{0x02, 0x00, 0x46} },
+{ 0x0026,	10,	{0x12, 0x17, 0x91, 0x12, 0x18, 0x8e, 0x12, 0x14, 0x47, 0x22} },
+{ 0x0033,	3,	{0x02, 0x00, 0x1d} },
+{ 0x003b,	3,	{0x02, 0x00, 0x46} },
+{ 0x0043,	3,	{0x02, 0x1b, 0x00} },
+{ 0x0046,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0, 0xd0, 0x75, 0xd0, 0x08} },
+{ 0x0056,	16,	{0x30, 0x99, 0x0e, 0x30, 0x0e, 0x07, 0xa2, 0x14, 0x92, 0x9b, 0x85, 0x46, 0x99, 0xc2, 0x99, 0xd2} },
+{ 0x0066,	16,	{0x1c, 0x30, 0xc1, 0x0e, 0x30, 0x0f, 0x07, 0xa2, 0x15, 0x92, 0xc3, 0x85, 0x47, 0xc1, 0xc2, 0xc1} },
+{ 0x0076,	16,	{0xd2, 0x1d, 0x20, 0x1c, 0x03, 0x02, 0x04, 0x36, 0xc2, 0x1c, 0x20, 0x02, 0x03, 0x02, 0x02, 0x61} },
+{ 0x0086,	16,	{0x20, 0x0e, 0x03, 0x02, 0x01, 0x38, 0xe5, 0x4a, 0xc3, 0x95, 0x7c, 0x50, 0x3e, 0x20, 0x10, 0x36} },
+{ 0x0096,	16,	{0x20, 0x08, 0x33, 0x90, 0x7f, 0x9b, 0xe0, 0x20, 0xe3, 0x03, 0x20, 0x19, 0x29, 0x30, 0x18, 0x12} },
+{ 0x00a6,	16,	{0xae, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13} },
+{ 0x00b6,	16,	{0x92, 0x14, 0xae, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83} },
+{ 0x00c6,	16,	{0xe0, 0xf5, 0x46, 0x02, 0x04, 0x34, 0xc2, 0x0e, 0x02, 0x04, 0x34, 0x90, 0x7f, 0xc7, 0xe4, 0xf0} },
+{ 0x00d6,	16,	{0xc2, 0x02, 0x30, 0x12, 0x0c, 0xc2, 0x12, 0x90, 0x7f, 0xbf, 0x04, 0xf0, 0xc2, 0x0e, 0x02, 0x04} },
+{ 0x00e6,	16,	{0x34, 0x90, 0x7f, 0xc8, 0xe0, 0x30, 0xe1, 0x05, 0xc2, 0x0e, 0x02, 0x04, 0x34, 0x90, 0x7f, 0xc9} },
+{ 0x00f6,	16,	{0xe0, 0xf5, 0x7c, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x12, 0x20, 0x10, 0x2d, 0x20, 0x08, 0x2a} },
+{ 0x0106,	16,	{0x90, 0x7f, 0x9b, 0xe0, 0x20, 0xe3, 0x03, 0x20, 0x19, 0x20, 0x30, 0x18, 0x11, 0x90, 0x7d, 0xc1} },
+{ 0x0116,	16,	{0xe0, 0x13, 0x92, 0x14, 0xa3, 0xe0, 0xf5, 0x46, 0x75, 0x4a, 0x03, 0x02, 0x04, 0x34, 0x75, 0x4a} },
+{ 0x0126,	16,	{0x02, 0x90, 0x7d, 0xc1, 0xe0, 0xf5, 0x46, 0x02, 0x04, 0x34, 0x75, 0x4a, 0x01, 0xc2, 0x0e, 0x02} },
+{ 0x0136,	16,	{0x04, 0x34, 0xe5, 0x4a, 0xc3, 0x95, 0x7c, 0x50, 0x03, 0x02, 0x01, 0xda, 0x90, 0x7f, 0xc6, 0xe0} },
+{ 0x0146,	16,	{0x30, 0xe1, 0x07, 0xc2, 0x20, 0xd2, 0x1e, 0x02, 0x04, 0x34, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x7c} },
+{ 0x0156,	16,	{0x90, 0x7e, 0x40, 0xe0, 0x13, 0x92, 0x12, 0x20, 0x10, 0x72, 0x20, 0x08, 0x6f, 0x90, 0x7f, 0x9b} },
+{ 0x0166,	16,	{0xe0, 0x20, 0xe3, 0x03, 0x20, 0x19, 0x65, 0x30, 0x18, 0x10, 0x90, 0x7e, 0x41, 0xe0, 0x13, 0x92} },
+{ 0x0176,	16,	{0x9b, 0xa3, 0xe0, 0xf5, 0x99, 0x75, 0x4a, 0x03, 0x80, 0x09, 0x90, 0x7e, 0x41, 0xe0, 0xf5, 0x99} },
+{ 0x0186,	16,	{0x75, 0x4a, 0x02, 0xe5, 0x4a, 0xc3, 0x95, 0x7c, 0x40, 0x17, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0xc2} },
+{ 0x0196,	16,	{0x02, 0x20, 0x12, 0x03, 0x02, 0x04, 0x34, 0xc2, 0x12, 0x90, 0x7f, 0xbf, 0x04, 0xf0, 0x02, 0x04} },
+{ 0x01a6,	16,	{0x34, 0x30, 0x18, 0x12, 0xae, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e} },
+{ 0x01b6,	16,	{0xf5, 0x83, 0xe0, 0x13, 0x92, 0x14, 0xae, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4} },
+{ 0x01c6,	16,	{0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x46, 0xd2, 0x0e, 0x02, 0x04, 0x34, 0x75, 0x4a, 0x01, 0xc2} },
+{ 0x01d6,	16,	{0x20, 0x02, 0x04, 0x34, 0x30, 0x10, 0x03, 0x02, 0x02, 0x5c, 0x20, 0x08, 0x79, 0x90, 0x7f, 0x9b} },
+{ 0x01e6,	16,	{0xe0, 0x20, 0xe3, 0x03, 0x20, 0x19, 0x6f, 0x30, 0x18, 0x12, 0xae, 0x4a, 0x05, 0x4a, 0x74, 0x40} },
+{ 0x01f6,	16,	{0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x9b, 0xae, 0x4a, 0x05, 0x4a} },
+{ 0x0206,	16,	{0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5, 0x99, 0xe5, 0x4a, 0xc3} },
+{ 0x0216,	16,	{0x95, 0x7c, 0x40, 0x17, 0x90, 0x7f, 0xc7, 0xe4, 0xf0, 0xc2, 0x02, 0x20, 0x12, 0x03, 0x02, 0x04} },
+{ 0x0226,	16,	{0x34, 0xc2, 0x12, 0x90, 0x7f, 0xbf, 0x04, 0xf0, 0x02, 0x04, 0x34, 0x30, 0x18, 0x12, 0xae, 0x4a} },
+{ 0x0236,	16,	{0x05, 0x4a, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x14} },
+{ 0x0246,	16,	{0xae, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xf5} },
+{ 0x0256,	16,	{0x46, 0xd2, 0x0e, 0x02, 0x04, 0x34, 0xc2, 0x20, 0x02, 0x04, 0x34, 0x20, 0x0e, 0x03, 0x02, 0x03} },
+{ 0x0266,	16,	{0x13, 0xe5, 0x4a, 0xc3, 0x95, 0x7c, 0x50, 0x3e, 0x20, 0x10, 0x36, 0x20, 0x08, 0x33, 0x90, 0x7f} },
+{ 0x0276,	16,	{0x9b, 0xe0, 0x20, 0xe3, 0x03, 0x20, 0x19, 0x29, 0x30, 0x18, 0x12, 0xae, 0x4a, 0x05, 0x4a, 0x74} },
+{ 0x0286,	16,	{0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x14, 0xae, 0x4a, 0x05} },
+{ 0x0296,	16,	{0x4a, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x46, 0x02, 0x04} },
+{ 0x02a6,	16,	{0x34, 0xc2, 0x0e, 0x02, 0x04, 0x34, 0x90, 0x7f, 0xc9, 0xe4, 0xf0, 0xd2, 0x02, 0x30, 0x12, 0x0c} },
+{ 0x02b6,	16,	{0xc2, 0x12, 0x90, 0x7f, 0xbf, 0x04, 0xf0, 0xc2, 0x0e, 0x02, 0x04, 0x34, 0x90, 0x7f, 0xc6, 0xe0} },
+{ 0x02c6,	16,	{0x30, 0xe1, 0x05, 0xc2, 0x0e, 0x02, 0x04, 0x34, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x7c, 0x90, 0x7e} },
+{ 0x02d6,	16,	{0x40, 0xe0, 0x13, 0x92, 0x12, 0x20, 0x10, 0x2d, 0x20, 0x08, 0x2a, 0x90, 0x7f, 0x9b, 0xe0, 0x20} },
+{ 0x02e6,	16,	{0xe3, 0x03, 0x20, 0x19, 0x20, 0x30, 0x18, 0x11, 0x90, 0x7e, 0x41, 0xe0, 0x13, 0x92, 0x14, 0xa3} },
+{ 0x02f6,	16,	{0xe0, 0xf5, 0x46, 0x75, 0x4a, 0x03, 0x02, 0x04, 0x34, 0x75, 0x4a, 0x02, 0x90, 0x7e, 0x41, 0xe0} },
+{ 0x0306,	16,	{0xf5, 0x46, 0x02, 0x04, 0x34, 0x75, 0x4a, 0x01, 0xc2, 0x0e, 0x02, 0x04, 0x34, 0xe5, 0x4a, 0xc3} },
+{ 0x0316,	16,	{0x95, 0x7c, 0x50, 0x03, 0x02, 0x03, 0xb5, 0x90, 0x7f, 0xc8, 0xe0, 0x30, 0xe1, 0x07, 0xc2, 0x20} },
+{ 0x0326,	16,	{0xd2, 0x1e, 0x02, 0x04, 0x34, 0x90, 0x7f, 0xc9, 0xe0, 0xf5, 0x7c, 0x90, 0x7d, 0xc0, 0xe0, 0x13} },
+{ 0x0336,	16,	{0x92, 0x12, 0x20, 0x10, 0x72, 0x20, 0x08, 0x6f, 0x90, 0x7f, 0x9b, 0xe0, 0x20, 0xe3, 0x03, 0x20} },
+{ 0x0346,	16,	{0x19, 0x65, 0x30, 0x18, 0x10, 0x90, 0x7d, 0xc1, 0xe0, 0x13, 0x92, 0x9b, 0xa3, 0xe0, 0xf5, 0x99} },
+{ 0x0356,	16,	{0x75, 0x4a, 0x03, 0x80, 0x09, 0x90, 0x7d, 0xc1, 0xe0, 0xf5, 0x99, 0x75, 0x4a, 0x02, 0xe5, 0x4a} },
+{ 0x0366,	16,	{0xc3, 0x95, 0x7c, 0x40, 0x17, 0x90, 0x7f, 0xc9, 0xe4, 0xf0, 0xd2, 0x02, 0x20, 0x12, 0x03, 0x02} },
+{ 0x0376,	16,	{0x04, 0x34, 0xc2, 0x12, 0x90, 0x7f, 0xbf, 0x04, 0xf0, 0x02, 0x04, 0x34, 0x30, 0x18, 0x12, 0xae} },
+{ 0x0386,	16,	{0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92} },
+{ 0x0396,	16,	{0x14, 0xae, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0} },
+{ 0x03a6,	16,	{0xf5, 0x46, 0xd2, 0x0e, 0x02, 0x04, 0x34, 0x75, 0x4a, 0x01, 0xc2, 0x20, 0x02, 0x04, 0x34, 0x30} },
+{ 0x03b6,	16,	{0x10, 0x03, 0x02, 0x04, 0x32, 0x20, 0x08, 0x74, 0x90, 0x7f, 0x9b, 0xe0, 0x20, 0xe3, 0x03, 0x20} },
+{ 0x03c6,	16,	{0x19, 0x6a, 0x30, 0x18, 0x12, 0xae, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x03d6,	16,	{0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x9b, 0xae, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2e, 0xf5, 0x82} },
+{ 0x03e6,	16,	{0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x99, 0xe5, 0x4a, 0xc3, 0x95, 0x7c, 0x40, 0x13, 0x90} },
+{ 0x03f6,	16,	{0x7f, 0xc9, 0xe4, 0xf0, 0xd2, 0x02, 0x30, 0x12, 0x35, 0xc2, 0x12, 0x90, 0x7f, 0xbf, 0x04, 0xf0} },
+{ 0x0406,	16,	{0x80, 0x2c, 0x30, 0x18, 0x12, 0xae, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0416,	16,	{0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x14, 0xae, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2e, 0xf5, 0x82} },
+{ 0x0426,	16,	{0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x46, 0xd2, 0x0e, 0x80, 0x02, 0xc2, 0x20, 0xd2, 0x24} },
+{ 0x0436,	16,	{0x20, 0x1d, 0x03, 0x02, 0x07, 0xf4, 0xc2, 0x1d, 0x20, 0x03, 0x03, 0x02, 0x06, 0x1f, 0x20, 0x0f} },
+{ 0x0446,	16,	{0x03, 0x02, 0x04, 0xf6, 0xe5, 0x4b, 0xc3, 0x95, 0x7d, 0x50, 0x3e, 0x20, 0x11, 0x36, 0x20, 0x0a} },
+{ 0x0456,	16,	{0x33, 0x90, 0x7f, 0x9a, 0xe0, 0x20, 0xe5, 0x03, 0x20, 0x1b, 0x29, 0x30, 0x1a, 0x12, 0xae, 0x4b} },
+{ 0x0466,	16,	{0x05, 0x4b, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x15} },
+{ 0x0476,	16,	{0xae, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5} },
+{ 0x0486,	16,	{0x47, 0x02, 0x07, 0xf2, 0xc2, 0x0f, 0x02, 0x07, 0xf2, 0x90, 0x7f, 0xcb, 0xe4, 0xf0, 0xc2, 0x03} },
+{ 0x0496,	16,	{0x30, 0x13, 0x0c, 0xc2, 0x13, 0x90, 0x7f, 0xc1, 0x04, 0xf0, 0xc2, 0x0f, 0x02, 0x07, 0xf2, 0x90} },
+{ 0x04a6,	16,	{0x7f, 0xcc, 0xe0, 0x30, 0xe1, 0x05, 0xc2, 0x0f, 0x02, 0x07, 0xf2, 0x90, 0x7f, 0xcd, 0xe0, 0xf5} },
+{ 0x04b6,	16,	{0x7d, 0x90, 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x13, 0x20, 0x11, 0x2d, 0x20, 0x0a, 0x2a, 0x90, 0x7f} },
+{ 0x04c6,	16,	{0x9a, 0xe0, 0x20, 0xe5, 0x03, 0x20, 0x1b, 0x20, 0x30, 0x1a, 0x11, 0x90, 0x7c, 0xc1, 0xe0, 0x13} },
+{ 0x04d6,	16,	{0x92, 0x15, 0xa3, 0xe0, 0xf5, 0x47, 0x75, 0x4b, 0x03, 0x02, 0x07, 0xf2, 0x75, 0x4b, 0x02, 0x90} },
+{ 0x04e6,	16,	{0x7c, 0xc1, 0xe0, 0xf5, 0x47, 0x02, 0x07, 0xf2, 0x75, 0x4b, 0x01, 0xc2, 0x0f, 0x02, 0x07, 0xf2} },
+{ 0x04f6,	16,	{0xe5, 0x4b, 0xc3, 0x95, 0x7d, 0x50, 0x03, 0x02, 0x05, 0x98, 0x90, 0x7f, 0xca, 0xe0, 0x30, 0xe1} },
+{ 0x0506,	16,	{0x07, 0xc2, 0x21, 0xd2, 0x1f, 0x02, 0x07, 0xf2, 0x90, 0x7f, 0xcb, 0xe0, 0xf5, 0x7d, 0x90, 0x7d} },
+{ 0x0516,	16,	{0x40, 0xe0, 0x13, 0x92, 0x13, 0x20, 0x11, 0x72, 0x20, 0x0a, 0x6f, 0x90, 0x7f, 0x9a, 0xe0, 0x20} },
+{ 0x0526,	16,	{0xe5, 0x03, 0x20, 0x1b, 0x65, 0x30, 0x1a, 0x10, 0x90, 0x7d, 0x41, 0xe0, 0x13, 0x92, 0xc3, 0xa3} },
+{ 0x0536,	16,	{0xe0, 0xf5, 0xc1, 0x75, 0x4b, 0x03, 0x80, 0x09, 0x90, 0x7d, 0x41, 0xe0, 0xf5, 0xc1, 0x75, 0x4b} },
+{ 0x0546,	16,	{0x02, 0xe5, 0x4b, 0xc3, 0x95, 0x7d, 0x40, 0x17, 0x90, 0x7f, 0xcb, 0xe4, 0xf0, 0xc2, 0x03, 0x20} },
+{ 0x0556,	16,	{0x13, 0x03, 0x02, 0x07, 0xf2, 0xc2, 0x13, 0x90, 0x7f, 0xc1, 0x04, 0xf0, 0x02, 0x07, 0xf2, 0x30} },
+{ 0x0566,	16,	{0x1a, 0x12, 0xae, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83} },
+{ 0x0576,	16,	{0xe0, 0x13, 0x92, 0x15, 0xae, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d} },
+{ 0x0586,	16,	{0xf5, 0x83, 0xe0, 0xf5, 0x47, 0xd2, 0x0f, 0x02, 0x07, 0xf2, 0x75, 0x4b, 0x01, 0xc2, 0x21, 0x02} },
+{ 0x0596,	16,	{0x07, 0xf2, 0x30, 0x11, 0x03, 0x02, 0x06, 0x1a, 0x20, 0x0a, 0x79, 0x90, 0x7f, 0x9a, 0xe0, 0x20} },
+{ 0x05a6,	16,	{0xe5, 0x03, 0x20, 0x1b, 0x6f, 0x30, 0x1a, 0x12, 0xae, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2e, 0xf5} },
+{ 0x05b6,	16,	{0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0xc3, 0xae, 0x4b, 0x05, 0x4b, 0x74, 0x40} },
+{ 0x05c6,	16,	{0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0xc1, 0xe5, 0x4b, 0xc3, 0x95, 0x7d} },
+{ 0x05d6,	16,	{0x40, 0x17, 0x90, 0x7f, 0xcb, 0xe4, 0xf0, 0xc2, 0x03, 0x20, 0x13, 0x03, 0x02, 0x07, 0xf2, 0xc2} },
+{ 0x05e6,	16,	{0x13, 0x90, 0x7f, 0xc1, 0x04, 0xf0, 0x02, 0x07, 0xf2, 0x30, 0x1a, 0x12, 0xae, 0x4b, 0x05, 0x4b} },
+{ 0x05f6,	16,	{0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x15, 0xae, 0x4b} },
+{ 0x0606,	16,	{0x05, 0x4b, 0x74, 0x40, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x47, 0xd2} },
+{ 0x0616,	16,	{0x0f, 0x02, 0x07, 0xf2, 0xc2, 0x21, 0x02, 0x07, 0xf2, 0x20, 0x0f, 0x03, 0x02, 0x06, 0xd1, 0xe5} },
+{ 0x0626,	16,	{0x4b, 0xc3, 0x95, 0x7d, 0x50, 0x3e, 0x20, 0x11, 0x36, 0x20, 0x0a, 0x33, 0x90, 0x7f, 0x9a, 0xe0} },
+{ 0x0636,	16,	{0x20, 0xe5, 0x03, 0x20, 0x1b, 0x29, 0x30, 0x1a, 0x12, 0xae, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2e} },
+{ 0x0646,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x15, 0xae, 0x4b, 0x05, 0x4b, 0x74} },
+{ 0x0656,	16,	{0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xf5, 0x47, 0x02, 0x07, 0xf2, 0xc2} },
+{ 0x0666,	16,	{0x0f, 0x02, 0x07, 0xf2, 0x90, 0x7f, 0xcd, 0xe4, 0xf0, 0xd2, 0x03, 0x30, 0x13, 0x0c, 0xc2, 0x13} },
+{ 0x0676,	16,	{0x90, 0x7f, 0xc1, 0x04, 0xf0, 0xc2, 0x0f, 0x02, 0x07, 0xf2, 0x90, 0x7f, 0xca, 0xe0, 0x30, 0xe1} },
+{ 0x0686,	16,	{0x05, 0xc2, 0x0f, 0x02, 0x07, 0xf2, 0x90, 0x7f, 0xcb, 0xe0, 0xf5, 0x7d, 0x90, 0x7d, 0x40, 0xe0} },
+{ 0x0696,	16,	{0x13, 0x92, 0x13, 0x20, 0x11, 0x2d, 0x20, 0x0a, 0x2a, 0x90, 0x7f, 0x9a, 0xe0, 0x20, 0xe5, 0x03} },
+{ 0x06a6,	16,	{0x20, 0x1b, 0x20, 0x30, 0x1a, 0x11, 0x90, 0x7d, 0x41, 0xe0, 0x13, 0x92, 0x15, 0xa3, 0xe0, 0xf5} },
+{ 0x06b6,	16,	{0x47, 0x75, 0x4b, 0x03, 0x02, 0x07, 0xf2, 0x75, 0x4b, 0x02, 0x90, 0x7d, 0x41, 0xe0, 0xf5, 0x47} },
+{ 0x06c6,	16,	{0x02, 0x07, 0xf2, 0x75, 0x4b, 0x01, 0xc2, 0x0f, 0x02, 0x07, 0xf2, 0xe5, 0x4b, 0xc3, 0x95, 0x7d} },
+{ 0x06d6,	16,	{0x50, 0x03, 0x02, 0x07, 0x73, 0x90, 0x7f, 0xcc, 0xe0, 0x30, 0xe1, 0x07, 0xc2, 0x21, 0xd2, 0x1f} },
+{ 0x06e6,	16,	{0x02, 0x07, 0xf2, 0x90, 0x7f, 0xcd, 0xe0, 0xf5, 0x7d, 0x90, 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x13} },
+{ 0x06f6,	16,	{0x20, 0x11, 0x72, 0x20, 0x0a, 0x6f, 0x90, 0x7f, 0x9a, 0xe0, 0x20, 0xe5, 0x03, 0x20, 0x1b, 0x65} },
+{ 0x0706,	16,	{0x30, 0x1a, 0x10, 0x90, 0x7c, 0xc1, 0xe0, 0x13, 0x92, 0xc3, 0xa3, 0xe0, 0xf5, 0xc1, 0x75, 0x4b} },
+{ 0x0716,	16,	{0x03, 0x80, 0x09, 0x90, 0x7c, 0xc1, 0xe0, 0xf5, 0xc1, 0x75, 0x4b, 0x02, 0xe5, 0x4b, 0xc3, 0x95} },
+{ 0x0726,	16,	{0x7d, 0x40, 0x17, 0x90, 0x7f, 0xcd, 0xe4, 0xf0, 0xd2, 0x03, 0x20, 0x13, 0x03, 0x02, 0x07, 0xf2} },
+{ 0x0736,	16,	{0xc2, 0x13, 0x90, 0x7f, 0xc1, 0x04, 0xf0, 0x02, 0x07, 0xf2, 0x30, 0x1a, 0x12, 0xae, 0x4b, 0x05} },
+{ 0x0746,	16,	{0x4b, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x15, 0xae} },
+{ 0x0756,	16,	{0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xf5, 0x47} },
+{ 0x0766,	16,	{0xd2, 0x0f, 0x02, 0x07, 0xf2, 0x75, 0x4b, 0x01, 0xc2, 0x21, 0x02, 0x07, 0xf2, 0x30, 0x11, 0x03} },
+{ 0x0776,	16,	{0x02, 0x07, 0xf0, 0x20, 0x0a, 0x74, 0x90, 0x7f, 0x9a, 0xe0, 0x20, 0xe5, 0x03, 0x20, 0x1b, 0x6a} },
+{ 0x0786,	16,	{0x30, 0x1a, 0x12, 0xae, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5} },
+{ 0x0796,	16,	{0x83, 0xe0, 0x13, 0x92, 0xc3, 0xae, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x07a6,	16,	{0x7c, 0xf5, 0x83, 0xe0, 0xf5, 0xc1, 0xe5, 0x4b, 0xc3, 0x95, 0x7d, 0x40, 0x13, 0x90, 0x7f, 0xcd} },
+{ 0x07b6,	16,	{0xe4, 0xf0, 0xd2, 0x03, 0x30, 0x13, 0x35, 0xc2, 0x13, 0x90, 0x7f, 0xc1, 0x04, 0xf0, 0x80, 0x2c} },
+{ 0x07c6,	16,	{0x30, 0x1a, 0x12, 0xae, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5} },
+{ 0x07d6,	16,	{0x83, 0xe0, 0x13, 0x92, 0x15, 0xae, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2e, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x07e6,	16,	{0x7c, 0xf5, 0x83, 0xe0, 0xf5, 0x47, 0xd2, 0x0f, 0x80, 0x02, 0xc2, 0x21, 0xd2, 0x24, 0x20, 0x98} },
+{ 0x07f6,	16,	{0x03, 0x02, 0x09, 0x26, 0xc2, 0x98, 0x20, 0x00, 0x03, 0x02, 0x08, 0x98, 0x20, 0x22, 0x27, 0xae} },
+{ 0x0806,	16,	{0x48, 0x05, 0x48, 0x74, 0x80, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x99, 0xf0} },
+{ 0x0816,	16,	{0x30, 0x18, 0x49, 0xae, 0x48, 0x05, 0x48, 0x74, 0x80, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5} },
+{ 0x0826,	16,	{0x83, 0xe5, 0x98, 0xf0, 0x80, 0x36, 0xaf, 0x99, 0xef, 0xb5, 0x58, 0x04, 0xd2, 0x08, 0x80, 0x2c} },
+{ 0x0836,	3,	{0xef, 0xb5, 0x57} },
+{ 0x0839,	16,	{0x04, 0xc2, 0x08, 0x80, 0x24, 0xae, 0x48, 0x05, 0x48, 0x74, 0x80, 0x2e, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0849,	16,	{0x7e, 0xf5, 0x83, 0xef, 0xf0, 0x30, 0x18, 0x11, 0xae, 0x48, 0x05, 0x48, 0x74, 0x80, 0x2e, 0xf5} },
+{ 0x0859,	16,	{0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0xd2, 0x16, 0xe5, 0x48, 0xc3, 0x95, 0x54} },
+{ 0x0869,	16,	{0x50, 0x03, 0x02, 0x09, 0x24, 0x90, 0x7f, 0xb8, 0xe0, 0x30, 0xe1, 0x15, 0xe5, 0x48, 0xc3, 0x94} },
+{ 0x0879,	16,	{0x40, 0x50, 0x03, 0x02, 0x09, 0x24, 0x15, 0x48, 0x15, 0x48, 0x05, 0x2d, 0xd2, 0x09, 0x02, 0x09} },
+{ 0x0889,	16,	{0x24, 0x90, 0x7f, 0xb7, 0xe5, 0x48, 0xf0, 0x75, 0x48, 0x00, 0xc2, 0x00, 0x02, 0x09, 0x24, 0x20} },
+{ 0x0899,	16,	{0x22, 0x27, 0xae, 0x48, 0x05, 0x48, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83} },
+{ 0x08a9,	16,	{0xe5, 0x99, 0xf0, 0x30, 0x18, 0x49, 0xae, 0x48, 0x05, 0x48, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4} },
+{ 0x08b9,	16,	{0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0x80, 0x36, 0xaf, 0x99, 0xef, 0xb5, 0x58, 0x04, 0xd2} },
+{ 0x08c9,	16,	{0x08, 0x80, 0x2c, 0xef, 0xb5, 0x57, 0x04, 0xc2, 0x08, 0x80, 0x24, 0xae, 0x48, 0x05, 0x48, 0x74} },
+{ 0x08d9,	16,	{0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xef, 0xf0, 0x30, 0x18, 0x11, 0xae, 0x48} },
+{ 0x08e9,	16,	{0x05, 0x48, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe5, 0x98, 0xf0, 0xd2} },
+{ 0x08f9,	16,	{0x16, 0xe5, 0x48, 0xc3, 0x95, 0x54, 0x40, 0x23, 0x90, 0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x11, 0xe5} },
+{ 0x0909,	16,	{0x48, 0xc3, 0x94, 0x40, 0x40, 0x15, 0x15, 0x48, 0x15, 0x48, 0x05, 0x2d, 0xd2, 0x09, 0x80, 0x0b} },
+{ 0x0919,	16,	{0x90, 0x7f, 0xb9, 0xe5, 0x48, 0xf0, 0x75, 0x48, 0x00, 0xd2, 0x00, 0xd2, 0x24, 0x20, 0xc0, 0x03} },
+{ 0x0929,	16,	{0x02, 0x0a, 0x58, 0xc2, 0xc0, 0x20, 0x01, 0x03, 0x02, 0x09, 0xca, 0x20, 0x23, 0x27, 0xae, 0x49} },
+{ 0x0939,	16,	{0x05, 0x49, 0x74, 0x80, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe5, 0xc1, 0xf0, 0x30} },
+{ 0x0949,	16,	{0x1a, 0x49, 0xae, 0x49, 0x05, 0x49, 0x74, 0x80, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83} },
+{ 0x0959,	16,	{0xe5, 0xc0, 0xf0, 0x80, 0x36, 0xaf, 0xc1, 0xef, 0xb5, 0x70, 0x04, 0xd2, 0x0a, 0x80, 0x2c, 0xef} },
+{ 0x0969,	16,	{0xb5, 0x6f, 0x04, 0xc2, 0x0a, 0x80, 0x24, 0xae, 0x49, 0x05, 0x49, 0x74, 0x80, 0x2e, 0xf5, 0x82} },
+{ 0x0979,	16,	{0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xef, 0xf0, 0x30, 0x1a, 0x11, 0xae, 0x49, 0x05, 0x49, 0x74, 0x80} },
+{ 0x0989,	16,	{0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe5, 0xc0, 0xf0, 0xd2, 0x17, 0xe5, 0x49, 0xc3} },
+{ 0x0999,	16,	{0x95, 0x6c, 0x50, 0x03, 0x02, 0x0a, 0x56, 0x90, 0x7f, 0xbc, 0xe0, 0x30, 0xe1, 0x15, 0xe5, 0x49} },
+{ 0x09a9,	16,	{0xc3, 0x94, 0x40, 0x50, 0x03, 0x02, 0x0a, 0x56, 0x15, 0x49, 0x15, 0x49, 0x05, 0x39, 0xd2, 0x0b} },
+{ 0x09b9,	16,	{0x02, 0x0a, 0x56, 0x90, 0x7f, 0xbb, 0xe5, 0x49, 0xf0, 0x75, 0x49, 0x00, 0xc2, 0x01, 0x02, 0x0a} },
+{ 0x09c9,	16,	{0x56, 0x20, 0x23, 0x27, 0xae, 0x49, 0x05, 0x49, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d} },
+{ 0x09d9,	16,	{0xf5, 0x83, 0xe5, 0xc1, 0xf0, 0x30, 0x1a, 0x49, 0xae, 0x49, 0x05, 0x49, 0x74, 0x00, 0x2e, 0xf5} },
+{ 0x09e9,	16,	{0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe5, 0xc0, 0xf0, 0x80, 0x36, 0xaf, 0xc1, 0xef, 0xb5, 0x70} },
+{ 0x09f9,	16,	{0x04, 0xd2, 0x0a, 0x80, 0x2c, 0xef, 0xb5, 0x6f, 0x04, 0xc2, 0x0a, 0x80, 0x24, 0xae, 0x49, 0x05} },
+{ 0x0a09,	16,	{0x49, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xef, 0xf0, 0x30, 0x1a, 0x11} },
+{ 0x0a19,	16,	{0xae, 0x49, 0x05, 0x49, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe5, 0xc0} },
+{ 0x0a29,	16,	{0xf0, 0xd2, 0x17, 0xe5, 0x49, 0xc3, 0x95, 0x6c, 0x40, 0x23, 0x90, 0x7f, 0xba, 0xe0, 0x30, 0xe1} },
+{ 0x0a39,	16,	{0x11, 0xe5, 0x49, 0xc3, 0x94, 0x40, 0x40, 0x15, 0x15, 0x49, 0x15, 0x49, 0x05, 0x39, 0xd2, 0x0b} },
+{ 0x0a49,	16,	{0x80, 0x0b, 0x90, 0x7f, 0xbd, 0xe5, 0x49, 0xf0, 0x75, 0x49, 0x00, 0xd2, 0x01, 0xd2, 0x24, 0x30} },
+{ 0x0a59,	7,	{0x24, 0x05, 0xc2, 0x24, 0x02, 0x00, 0x56} },
+{ 0x0a60,	11,	{0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0a6b,	16,	{0x90, 0x7f, 0xce, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x0b, 0x93, 0xe4, 0xf5, 0x12, 0x74, 0x40, 0x25} },
+{ 0x0a7b,	16,	{0x12, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x12, 0x7c, 0x00, 0x7b, 0x00} },
+{ 0x0a8b,	16,	{0x24, 0x4c, 0xf9, 0xec, 0x34, 0x00, 0xfa, 0xef, 0x12, 0x15, 0x55, 0x05, 0x12, 0xe5, 0x12, 0xb4} },
+{ 0x0a9b,	16,	{0x18, 0xdb, 0xe5, 0x4c, 0x60, 0x0c, 0x75, 0xc9, 0x20, 0x75, 0xc8, 0x36, 0x85, 0x4d, 0xca, 0x85} },
+{ 0x0aab,	16,	{0x4e, 0xcb, 0xe5, 0x4f, 0x13, 0x92, 0x18, 0x92, 0x9f, 0xe5, 0x50, 0x13, 0x92, 0x19, 0xe5, 0x51} },
+{ 0x0abb,	16,	{0x13, 0x92, 0x22, 0xe5, 0x52, 0x60, 0x09, 0x90, 0x7f, 0x98, 0xe0, 0x54, 0xfb, 0xf0, 0x80, 0x07} },
+{ 0x0acb,	16,	{0x90, 0x7f, 0x98, 0xe0, 0x44, 0x04, 0xf0, 0xe5, 0x53, 0x60, 0x09, 0x90, 0x7f, 0x98, 0xe0, 0x54} },
+{ 0x0adb,	16,	{0x7f, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0x98, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x59, 0x60, 0x0b, 0xc2} },
+{ 0x0aeb,	16,	{0x10, 0xc2, 0x08, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x5a, 0x60, 0x0b, 0xd2, 0x08} },
+{ 0x0afb,	16,	{0xd2, 0x09, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x5b, 0x60, 0x17, 0xc2, 0xaf, 0xe4} },
+{ 0x0b0b,	16,	{0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0xc2, 0x0e, 0xd2, 0x02, 0xc2, 0x12, 0xf5, 0x7c} },
+{ 0x0b1b,	16,	{0xf5, 0x4a, 0xd2, 0xaf, 0xe5, 0x5c, 0x60, 0x05, 0x30, 0x22, 0x02, 0xd2, 0x08, 0xe5, 0x5d, 0x60} },
+{ 0x0b2b,	16,	{0x15, 0x90, 0x7f, 0x95, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0x9e, 0xe0, 0x44, 0x02, 0xf0, 0x90} },
+{ 0x0b3b,	16,	{0x7f, 0x98, 0xe0, 0x54, 0xfd, 0xf0, 0xe5, 0x5e, 0x60, 0x0a, 0xd2, 0x9c, 0xc2, 0x98, 0x75, 0x2e} },
+{ 0x0b4b,	16,	{0x01, 0x75, 0x40, 0x28, 0xe5, 0x5f, 0x60, 0x07, 0xc2, 0x9c, 0xe4, 0xf5, 0x48, 0xf5, 0x2e, 0xe5} },
+{ 0x0b5b,	16,	{0x60, 0x60, 0x03, 0xe4, 0xf5, 0x48, 0xe5, 0x61, 0x60, 0x02, 0xd2, 0x04, 0xe5, 0x62, 0x60, 0x08} },
+{ 0x0b6b,	16,	{0xe5, 0x5e, 0x70, 0x02, 0xf5, 0x40, 0xd2, 0x09, 0xe5, 0x63, 0x60, 0x15, 0x90, 0x7f, 0xd7, 0x74} },
+{ 0x0b7b,	16,	{0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x12, 0xf0, 0x74, 0x32, 0xf0, 0x74, 0x15, 0xf0, 0x74, 0x35} },
+{ 0x0b8b,	16,	{0xf0, 0xd2, 0x06, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0xa2, 0x10, 0xe4, 0x33, 0xff, 0x65, 0x2b, 0x60} },
+{ 0x0b9b,	16,	{0x04, 0x8f, 0x2b, 0xd2, 0x09, 0xa2, 0x08, 0xe4, 0x33, 0xff, 0x65, 0x2c, 0x60, 0x04, 0x8f, 0x2c} },
+{ 0x0bab,	16,	{0xd2, 0x09, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x08, 0x65, 0x27, 0x60, 0x07, 0xe0, 0x54, 0x08, 0xf5} },
+{ 0x0bbb,	16,	{0x27, 0xd2, 0x09, 0x90, 0x7f, 0x9b, 0xe0, 0x54, 0x40, 0xb5, 0x29, 0x09, 0xe0, 0x54, 0x40, 0x64} },
+{ 0x0bcb,	16,	{0x40, 0xf5, 0x29, 0xd2, 0x09, 0x30, 0x04, 0x35, 0xc2, 0xaf, 0x30, 0x00, 0x18, 0x90, 0x7f, 0xb8} },
+{ 0x0bdb,	16,	{0xe0, 0x20, 0xe1, 0x27, 0xe5, 0x48, 0x60, 0x09, 0x90, 0x7f, 0xb7, 0xf0, 0xe4, 0xf5, 0x48, 0xc2} },
+{ 0x0beb,	16,	{0x00, 0xc2, 0x04, 0x80, 0x16, 0x90, 0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x0f, 0xe5, 0x48, 0x60, 0x09} },
+{ 0x0bfb,	16,	{0x90, 0x7f, 0xb9, 0xf0, 0xe4, 0xf5, 0x48, 0xd2, 0x00, 0xc2, 0x04, 0xd2, 0xaf, 0x30, 0x1e, 0x37} },
+{ 0x0c0b,	16,	{0x30, 0x02, 0x1b, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x2d, 0x90, 0x7e, 0x40, 0xe0, 0x13, 0x92} },
+{ 0x0c1b,	16,	{0x12, 0x75, 0x4a, 0x01, 0x90, 0x7f, 0xc7, 0xe0, 0xf5, 0x7c, 0xc2, 0x1e, 0x80, 0x19, 0x90, 0x7f} },
+{ 0x0c2b,	16,	{0xc8, 0xe0, 0x20, 0xe1, 0x12, 0x90, 0x7d, 0xc0, 0xe0, 0x13, 0x92, 0x12, 0x75, 0x4a, 0x01, 0x90} },
+{ 0x0c3b,	16,	{0x7f, 0xc9, 0xe0, 0xf5, 0x7c, 0xc2, 0x1e, 0x30, 0x20, 0x03, 0x02, 0x0d, 0x4a, 0x30, 0x1e, 0x03} },
+{ 0x0c4b,	16,	{0x02, 0x0d, 0x4a, 0x30, 0x19, 0x0a, 0x90, 0x7f, 0x9b, 0xe0, 0x20, 0xe3, 0x03, 0x02, 0x0d, 0x4a} },
+{ 0x0c5b,	16,	{0x30, 0x08, 0x03, 0x02, 0x0d, 0x4a, 0x30, 0x10, 0x03, 0x02, 0x0d, 0x4a, 0x30, 0x02, 0x62, 0x30} },
+{ 0x0c6b,	16,	{0x18, 0x12, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83} },
+{ 0x0c7b,	16,	{0xe0, 0x13, 0x92, 0x2c, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e} },
+{ 0x0c8b,	16,	{0xf5, 0x83, 0xe0, 0xf5, 0x13, 0xe5, 0x4a, 0xc3, 0x95, 0x7c, 0x50, 0x2a, 0x30, 0x18, 0x12, 0xaf} },
+{ 0x0c9b,	16,	{0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0x13, 0x92} },
+{ 0x0cab,	16,	{0x14, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0} },
+{ 0x0cbb,	16,	{0xf5, 0x46, 0xd2, 0x0e, 0x80, 0x6b, 0xc2, 0x0e, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0xc2, 0x02, 0x80} },
+{ 0x0ccb,	16,	{0x60, 0x30, 0x18, 0x12, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d} },
+{ 0x0cdb,	16,	{0xf5, 0x83, 0xe0, 0x13, 0x92, 0x2c, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4} },
+{ 0x0ceb,	16,	{0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x13, 0xe5, 0x4a, 0xc3, 0x95, 0x7c, 0x50, 0x2a, 0x30, 0x18} },
+{ 0x0cfb,	16,	{0x12, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0} },
+{ 0x0d0b,	16,	{0x13, 0x92, 0x14, 0xaf, 0x4a, 0x05, 0x4a, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5} },
+{ 0x0d1b,	16,	{0x83, 0xe0, 0xf5, 0x46, 0xd2, 0x0e, 0x80, 0x09, 0xc2, 0x0e, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0xd2} },
+{ 0x0d2b,	16,	{0x02, 0x30, 0x18, 0x04, 0xa2, 0x2c, 0x92, 0x9b, 0xd2, 0x20, 0xc2, 0xaf, 0x85, 0x13, 0x99, 0x20} },
+{ 0x0d3b,	16,	{0x0e, 0x0b, 0x30, 0x12, 0x08, 0xc2, 0x12, 0x90, 0x7f, 0xbf, 0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x90} },
+{ 0x0d4b,	16,	{0x7f, 0xd0, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x0e, 0x71, 0xe4, 0xf5, 0x12, 0x74, 0xc0, 0x25, 0x12} },
+{ 0x0d5b,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x12, 0x7c, 0x00, 0x7b, 0x00, 0x24} },
+{ 0x0d6b,	16,	{0x64, 0xf9, 0xec, 0x34, 0x00, 0xfa, 0xef, 0x12, 0x15, 0x55, 0x05, 0x12, 0xe5, 0x12, 0xb4, 0x18} },
+{ 0x0d7b,	16,	{0xdb, 0xe5, 0x64, 0x60, 0x0b, 0x75, 0x89, 0x60, 0x75, 0x88, 0x40, 0xd2, 0xdf, 0x85, 0x65, 0x8d} },
+{ 0x0d8b,	16,	{0xe5, 0x67, 0x13, 0x92, 0x1a, 0x92, 0xc7, 0xe5, 0x68, 0x13, 0x92, 0x1b, 0xe5, 0x69, 0x13, 0x92} },
+{ 0x0d9b,	16,	{0x23, 0xe5, 0x6a, 0x60, 0x09, 0x90, 0x7f, 0x97, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0x7f} },
+{ 0x0dab,	16,	{0x97, 0xe0, 0x44, 0x10, 0xf0, 0xe5, 0x6b, 0x60, 0x09, 0x90, 0x7f, 0x97, 0xe0, 0x54, 0x7f, 0xf0} },
+{ 0x0dbb,	16,	{0x80, 0x07, 0x90, 0x7f, 0x97, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x71, 0x60, 0x0b, 0xc2, 0x11, 0xc2} },
+{ 0x0dcb,	16,	{0x0a, 0x90, 0x7f, 0x94, 0xe0, 0x44, 0x08, 0xf0, 0xe5, 0x72, 0x60, 0x0b, 0xd2, 0x0a, 0xd2, 0x0b} },
+{ 0x0ddb,	16,	{0x90, 0x7f, 0x94, 0xe0, 0x44, 0x08, 0xf0, 0xe5, 0x73, 0x60, 0x17, 0xc2, 0xaf, 0xe4, 0x90, 0x7f} },
+{ 0x0deb,	16,	{0xcb, 0xf0, 0x90, 0x7f, 0xcd, 0xf0, 0xc2, 0x0f, 0xd2, 0x03, 0xc2, 0x13, 0xf5, 0x7d, 0xf5, 0x4b} },
+{ 0x0dfb,	16,	{0xd2, 0xaf, 0xe5, 0x74, 0x60, 0x05, 0x30, 0x23, 0x02, 0xd2, 0x0a, 0xe5, 0x75, 0x60, 0x15, 0x90} },
+{ 0x0e0b,	16,	{0x7f, 0x94, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x9d, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f, 0x97} },
+{ 0x0e1b,	16,	{0xe0, 0x54, 0xf7, 0xf0, 0xe5, 0x76, 0x60, 0x0a, 0xd2, 0xc4, 0xc2, 0xc0, 0x75, 0x3a, 0x01, 0x75} },
+{ 0x0e2b,	16,	{0x41, 0x28, 0xe5, 0x77, 0x60, 0x07, 0xc2, 0xc4, 0xe4, 0xf5, 0x49, 0xf5, 0x3a, 0xe5, 0x78, 0x60} },
+{ 0x0e3b,	16,	{0x03, 0xe4, 0xf5, 0x49, 0xe5, 0x79, 0x60, 0x02, 0xd2, 0x05, 0xe5, 0x7a, 0x60, 0x08, 0xe5, 0x76} },
+{ 0x0e4b,	16,	{0x70, 0x02, 0xf5, 0x41, 0xd2, 0x0b, 0xe5, 0x7b, 0x60, 0x15, 0x90, 0x7f, 0xd7, 0x74, 0x13, 0xf0} },
+{ 0x0e5b,	16,	{0x74, 0x33, 0xf0, 0x74, 0x14, 0xf0, 0x74, 0x34, 0xf0, 0x74, 0x16, 0xf0, 0x74, 0x36, 0xf0, 0xd2} },
+{ 0x0e6b,	16,	{0x07, 0xe4, 0x90, 0x7f, 0xd1, 0xf0, 0xa2, 0x11, 0xe4, 0x33, 0xff, 0x65, 0x37, 0x60, 0x04, 0x8f} },
+{ 0x0e7b,	16,	{0x37, 0xd2, 0x0b, 0xa2, 0x0a, 0xe4, 0x33, 0xff, 0x65, 0x38, 0x60, 0x04, 0x8f, 0x38, 0xd2, 0x0b} },
+{ 0x0e8b,	16,	{0x90, 0x7f, 0x9a, 0xe0, 0x54, 0x20, 0x65, 0x33, 0x60, 0x07, 0xe0, 0x54, 0x20, 0xf5, 0x33, 0xd2} },
+{ 0x0e9b,	16,	{0x0b, 0x90, 0x7f, 0x9a, 0xe0, 0x54, 0x40, 0xb5, 0x35, 0x09, 0xe0, 0x54, 0x40, 0x64, 0x40, 0xf5} },
+{ 0x0eab,	16,	{0x35, 0xd2, 0x0b, 0x30, 0x05, 0x35, 0xc2, 0xaf, 0x30, 0x01, 0x18, 0x90, 0x7f, 0xbc, 0xe0, 0x20} },
+{ 0x0ebb,	16,	{0xe1, 0x27, 0xe5, 0x49, 0x60, 0x09, 0x90, 0x7f, 0xbb, 0xf0, 0xe4, 0xf5, 0x49, 0xc2, 0x01, 0xc2} },
+{ 0x0ecb,	16,	{0x05, 0x80, 0x16, 0x90, 0x7f, 0xba, 0xe0, 0x20, 0xe1, 0x0f, 0xe5, 0x49, 0x60, 0x09, 0x90, 0x7f} },
+{ 0x0edb,	16,	{0xbd, 0xf0, 0xe4, 0xf5, 0x49, 0xd2, 0x01, 0xc2, 0x05, 0xd2, 0xaf, 0x30, 0x1f, 0x37, 0x30, 0x03} },
+{ 0x0eeb,	16,	{0x1b, 0x90, 0x7f, 0xca, 0xe0, 0x20, 0xe1, 0x2d, 0x90, 0x7d, 0x40, 0xe0, 0x13, 0x92, 0x13, 0x75} },
+{ 0x0efb,	16,	{0x4b, 0x01, 0x90, 0x7f, 0xcb, 0xe0, 0xf5, 0x7d, 0xc2, 0x1f, 0x80, 0x19, 0x90, 0x7f, 0xcc, 0xe0} },
+{ 0x0f0b,	16,	{0x20, 0xe1, 0x12, 0x90, 0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x13, 0x75, 0x4b, 0x01, 0x90, 0x7f, 0xcd} },
+{ 0x0f1b,	16,	{0xe0, 0xf5, 0x7d, 0xc2, 0x1f, 0x30, 0x21, 0x03, 0x02, 0x10, 0x28, 0x30, 0x1f, 0x03, 0x02, 0x10} },
+{ 0x0f2b,	16,	{0x28, 0x30, 0x1b, 0x0a, 0x90, 0x7f, 0x9a, 0xe0, 0x20, 0xe5, 0x03, 0x02, 0x10, 0x28, 0x30, 0x0a} },
+{ 0x0f3b,	16,	{0x03, 0x02, 0x10, 0x28, 0x30, 0x11, 0x03, 0x02, 0x10, 0x28, 0x30, 0x03, 0x62, 0x30, 0x1a, 0x12} },
+{ 0x0f4b,	16,	{0xaf, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13} },
+{ 0x0f5b,	16,	{0x92, 0x2c, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83} },
+{ 0x0f6b,	16,	{0xe0, 0xf5, 0x13, 0xe5, 0x4b, 0xc3, 0x95, 0x7d, 0x50, 0x2a, 0x30, 0x1a, 0x12, 0xaf, 0x4b, 0x05} },
+{ 0x0f7b,	16,	{0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0x13, 0x92, 0x15, 0xaf} },
+{ 0x0f8b,	16,	{0x4b, 0x05, 0x4b, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7d, 0xf5, 0x83, 0xe0, 0xf5, 0x47} },
+{ 0x0f9b,	16,	{0xd2, 0x0f, 0x80, 0x6b, 0xc2, 0x0f, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0xc2, 0x03, 0x80, 0x60, 0x30} },
+{ 0x0fab,	16,	{0x1a, 0x12, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83} },
+{ 0x0fbb,	16,	{0xe0, 0x13, 0x92, 0x2c, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7c} },
+{ 0x0fcb,	16,	{0xf5, 0x83, 0xe0, 0xf5, 0x13, 0xe5, 0x4b, 0xc3, 0x95, 0x7d, 0x50, 0x2a, 0x30, 0x1a, 0x12, 0xaf} },
+{ 0x0fdb,	16,	{0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0x13, 0x92} },
+{ 0x0feb,	16,	{0x15, 0xaf, 0x4b, 0x05, 0x4b, 0x74, 0xc0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0} },
+{ 0x0ffb,	16,	{0xf5, 0x47, 0xd2, 0x0f, 0x80, 0x09, 0xc2, 0x0f, 0xe4, 0x90, 0x7f, 0xcd, 0xf0, 0xd2, 0x03, 0x30} },
+{ 0x100b,	16,	{0x1a, 0x04, 0xa2, 0x2c, 0x92, 0xc3, 0xd2, 0x21, 0xc2, 0xaf, 0x85, 0x13, 0xc1, 0x20, 0x0f, 0x0b} },
+{ 0x101b,	16,	{0x30, 0x13, 0x08, 0xc2, 0x13, 0x90, 0x7f, 0xc1, 0x74, 0x01, 0xf0, 0xd2, 0xaf, 0x90, 0x7f, 0xc2} },
+{ 0x102b,	16,	{0xe0, 0x30, 0xe1, 0x03, 0x02, 0x10, 0xfe, 0xe5, 0x1a, 0x70, 0x46, 0x30, 0x09, 0x3f, 0xe5, 0x40} },
+{ 0x103b,	16,	{0x70, 0x3b, 0xa2, 0x06, 0x33, 0xf5, 0x31, 0xc2, 0x06, 0xc2, 0x09, 0xe4, 0xf5, 0x12, 0x7e, 0x00} },
+{ 0x104b,	16,	{0x7b, 0x00, 0x74, 0x26, 0x25, 0x12, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x15, 0x0f, 0xff, 0x74} },
+{ 0x105b,	16,	{0x80, 0x25, 0x12, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x12, 0xe5, 0x12} },
+{ 0x106b,	16,	{0xb4, 0x0c, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x0c, 0xf0, 0x75, 0x40, 0x10, 0x22, 0x75, 0x1a, 0x01} },
+{ 0x107b,	16,	{0x22, 0xe5, 0x1a, 0x64, 0x01, 0x70, 0x45, 0x30, 0x0b, 0x3e, 0xe5, 0x41, 0x70, 0x3a, 0xa2, 0x07} },
+{ 0x108b,	16,	{0x33, 0xf5, 0x3d, 0xc2, 0x07, 0xc2, 0x0b, 0xe4, 0xf5, 0x12, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x32} },
+{ 0x109b,	16,	{0x25, 0x12, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x15, 0x0f, 0xff, 0x74, 0x80, 0x25, 0x12, 0xf5} },
+{ 0x10ab,	16,	{0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x12, 0xe5, 0x12, 0xb4, 0x0c, 0xdb, 0x90} },
+{ 0x10bb,	16,	{0x7f, 0xc3, 0x74, 0x0c, 0xf0, 0x75, 0x41, 0x10, 0x75, 0x1a, 0x02, 0x22, 0xe5, 0x1c, 0x60, 0x30} },
+{ 0x10cb,	16,	{0x15, 0x1c, 0xe4, 0xf5, 0x12, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x1b, 0x25, 0x12, 0xf9, 0xee, 0x34} },
+{ 0x10db,	16,	{0x00, 0xfa, 0x12, 0x15, 0x0f, 0xff, 0x74, 0x80, 0x25, 0x12, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5} },
+{ 0x10eb,	16,	{0x83, 0xef, 0xf0, 0x05, 0x12, 0xe5, 0x12, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0} },
+{ 0x10fb,	3,	{0xe4, 0xf5, 0x1a} },
+{ 0x10fe,	1,	{0x22} },
+{ 0x10ff,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x15, 0x9f, 0x11, 0xc4, 0x00, 0x12, 0x38, 0x01, 0x12, 0xa4, 0x03} },
+{ 0x110f,	16,	{0x11, 0x22, 0x06, 0x11, 0xb7, 0x08, 0x11, 0xb1, 0x09, 0x11, 0xa4, 0x0a, 0x12, 0xfa, 0x0b, 0x00} },
+{ 0x111f,	16,	{0x00, 0x12, 0xf3, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02} },
+{ 0x112f,	16,	{0x70, 0x69, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x12} },
+{ 0x113f,	16,	{0xfa, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x16, 0xd3, 0x8b, 0x12, 0x8a, 0x13, 0x89, 0x14, 0xea} },
+{ 0x114f,	16,	{0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5} },
+{ 0x115f,	16,	{0xf0, 0x02, 0x12, 0xfa, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x12, 0xfa, 0x90, 0x7f} },
+{ 0x116f,	16,	{0xea, 0xe0, 0xff, 0x12, 0x17, 0x22, 0x8b, 0x12, 0x8a, 0x13, 0x89, 0x14, 0xea, 0x49, 0x60, 0x11} },
+{ 0x117f,	16,	{0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x12} },
+{ 0x118f,	16,	{0xfa, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x12, 0xfa, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x119f,	16,	{0x01, 0xf0, 0x02, 0x12, 0xfa, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02} },
+{ 0x11af,	16,	{0x12, 0xfa, 0x12, 0x14, 0x47, 0x02, 0x12, 0xfa, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f} },
+{ 0x11bf,	16,	{0xb5, 0xf0, 0x02, 0x12, 0xfa, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31} },
+{ 0x11cf,	16,	{0x24, 0x02, 0x70, 0x5b, 0xa2, 0x25, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x29, 0xe4, 0x33} },
+{ 0x11df,	16,	{0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x12} },
+{ 0x11ef,	16,	{0xfa, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x12} },
+{ 0x11ff,	16,	{0xfa, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07} },
+{ 0x120f,	16,	{0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90} },
+{ 0x121f,	16,	{0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x12, 0xfa, 0x90} },
+{ 0x122f,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x12, 0xfa, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60} },
+{ 0x123f,	16,	{0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x12, 0xfa, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2} },
+{ 0x124f,	16,	{0x25, 0x02, 0x12, 0xfa, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x12, 0xfa, 0x90, 0x7f} },
+{ 0x125f,	16,	{0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff} },
+{ 0x126f,	16,	{0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4} },
+{ 0x127f,	16,	{0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54} },
+{ 0x128f,	16,	{0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x129f,	16,	{0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70} },
+{ 0x12af,	16,	{0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x25, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x12bf,	16,	{0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4} },
+{ 0x12cf,	16,	{0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x12df,	16,	{0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x12ef,	16,	{0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x12ff,	2,	{0x02, 0xf0} },
+{ 0x1301,	1,	{0x22} },
+{ 0x1302,	16,	{0x20, 0x27, 0x03, 0x02, 0x14, 0x46, 0xe5, 0x40, 0x60, 0x02, 0x15, 0x40, 0xe5, 0x48, 0x60, 0x4f} },
+{ 0x1312,	16,	{0x65, 0x44, 0x70, 0x45, 0xe5, 0x42, 0xf4, 0x60, 0x02, 0x05, 0x42, 0xe5, 0x42, 0xc3, 0x95, 0x55} },
+{ 0x1322,	16,	{0x40, 0x3d, 0xc2, 0xaf, 0x30, 0x00, 0x18, 0x90, 0x7f, 0xb8, 0xe0, 0x20, 0xe1, 0x27, 0x90, 0x7f} },
+{ 0x1332,	16,	{0xb7, 0xe5, 0x48, 0xf0, 0xc2, 0x00, 0xe4, 0xf5, 0x48, 0xf5, 0x42, 0xf5, 0x44, 0x80, 0x16, 0x90} },
+{ 0x1342,	16,	{0x7f, 0xb6, 0xe0, 0x20, 0xe1, 0x0f, 0x90, 0x7f, 0xb9, 0xe5, 0x48, 0xf0, 0xd2, 0x00, 0xe4, 0xf5} },
+{ 0x1352,	16,	{0x48, 0xf5, 0x42, 0xf5, 0x44, 0xd2, 0xaf, 0x80, 0x06, 0x85, 0x48, 0x44, 0xe4, 0xf5, 0x42, 0xe5} },
+{ 0x1362,	16,	{0x2e, 0x60, 0x2d, 0x20, 0x16, 0x07, 0x90, 0x7f, 0x9b, 0xe0, 0x30, 0xe0, 0x0e, 0xe5, 0x2f, 0x60} },
+{ 0x1372,	16,	{0x05, 0xe4, 0xf5, 0x2f, 0xd2, 0x09, 0xe4, 0xf5, 0x3e, 0x80, 0x13, 0xe5, 0x3e, 0xd3, 0x95, 0x56} },
+{ 0x1382,	16,	{0x50, 0x0c, 0xe5, 0x3e, 0xb5, 0x56, 0x05, 0x75, 0x2f, 0x01, 0xd2, 0x09, 0x05, 0x3e, 0xc2, 0x16} },
+{ 0x1392,	16,	{0xe5, 0x41, 0x60, 0x02, 0x15, 0x41, 0xe5, 0x49, 0x60, 0x4f, 0x65, 0x45, 0x70, 0x45, 0xe5, 0x43} },
+{ 0x13a2,	16,	{0xf4, 0x60, 0x02, 0x05, 0x43, 0xe5, 0x43, 0xc3, 0x95, 0x6d, 0x40, 0x3d, 0xc2, 0xaf, 0x30, 0x01} },
+{ 0x13b2,	16,	{0x18, 0x90, 0x7f, 0xbc, 0xe0, 0x20, 0xe1, 0x27, 0x90, 0x7f, 0xbb, 0xe5, 0x49, 0xf0, 0xc2, 0x01} },
+{ 0x13c2,	16,	{0xe4, 0xf5, 0x49, 0xf5, 0x43, 0xf5, 0x45, 0x80, 0x16, 0x90, 0x7f, 0xba, 0xe0, 0x20, 0xe1, 0x0f} },
+{ 0x13d2,	16,	{0x90, 0x7f, 0xbd, 0xe5, 0x49, 0xf0, 0xd2, 0x01, 0xe4, 0xf5, 0x49, 0xf5, 0x43, 0xf5, 0x45, 0xd2} },
+{ 0x13e2,	16,	{0xaf, 0x80, 0x06, 0x85, 0x49, 0x45, 0xe4, 0xf5, 0x43, 0xe5, 0x3a, 0x60, 0x2d, 0x20, 0x17, 0x07} },
+{ 0x13f2,	16,	{0x90, 0x7f, 0x9a, 0xe0, 0x30, 0xe2, 0x0e, 0xe5, 0x3b, 0x60, 0x05, 0xe4, 0xf5, 0x3b, 0xd2, 0x0b} },
+{ 0x1402,	16,	{0xe4, 0xf5, 0x3f, 0x80, 0x13, 0xe5, 0x3f, 0xd3, 0x95, 0x6e, 0x50, 0x0c, 0xe5, 0x3f, 0xb5, 0x6e} },
+{ 0x1412,	16,	{0x05, 0x75, 0x3b, 0x01, 0xd2, 0x0b, 0x05, 0x3f, 0xc2, 0x17, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1} },
+{ 0x1422,	16,	{0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5, 0x1c, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x1d} },
+{ 0x1432,	16,	{0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7, 0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4} },
+{ 0x1442,	5,	{0x90, 0x7f, 0xd3, 0xf0, 0x22} },
+{ 0x1447,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x96, 0xe0, 0x44} },
+{ 0x1457,	16,	{0x10, 0xf0, 0x90, 0x7f, 0x94, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0x9a, 0xf0, 0x90, 0x7f} },
+{ 0x1467,	16,	{0x97, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0x23, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x84} },
+{ 0x1477,	16,	{0xf0, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x90, 0x7f, 0xcf, 0xf0, 0x75, 0x98} },
+{ 0x1487,	16,	{0x40, 0x43, 0xa8, 0x10, 0xc2, 0x18, 0xc2, 0x20, 0xc2, 0x08, 0xc2, 0x10, 0xf5, 0x7c, 0xf5, 0x4a} },
+{ 0x1497,	16,	{0xc2, 0x0e, 0xc2, 0x12, 0xf5, 0x42, 0xc2, 0x16, 0xf5, 0x44, 0xf5, 0x48, 0xc2, 0x22, 0xc2, 0x19} },
+{ 0x14a7,	16,	{0xf5, 0x2d, 0xf5, 0x2f, 0xc2, 0x04, 0xc2, 0x1c, 0xf5, 0x3e, 0xc2, 0x06, 0xd2, 0x00, 0xd2, 0x02} },
+{ 0x14b7,	16,	{0xd2, 0x09, 0xd2, 0x1e, 0xf5, 0x26, 0x90, 0x7f, 0xcb, 0xf0, 0x90, 0x7f, 0xcd, 0xf0, 0x90, 0x7f} },
+{ 0x14c7,	16,	{0xd1, 0xf0, 0x75, 0xc0, 0x40, 0x43, 0xa8, 0x40, 0xc2, 0x1a, 0xc2, 0x21, 0xc2, 0x0a, 0xc2, 0x11} },
+{ 0x14d7,	16,	{0xf5, 0x7d, 0xf5, 0x4b, 0xc2, 0x0f, 0xc2, 0x13, 0xf5, 0x43, 0xc2, 0x17, 0xf5, 0x45, 0xf5, 0x49} },
+{ 0x14e7,	16,	{0xc2, 0x23, 0xc2, 0x1b, 0xf5, 0x39, 0xf5, 0x3b, 0xc2, 0x05, 0xc2, 0x1d, 0xf5, 0x3f, 0xc2, 0x07} },
+{ 0x14f7,	16,	{0xd2, 0x01, 0xd2, 0x03, 0xd2, 0x0b, 0xd2, 0x1f, 0x75, 0x32, 0x01, 0x90, 0x7f, 0xdf, 0x74, 0xff} },
+{ 0x1507,	8,	{0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xd2, 0x27, 0x22} },
+{ 0x150f,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x151f,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x1528,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x1538,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x1548,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x1555,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01} },
+{ 0x1565,	2,	{0xf3, 0x22} },
+{ 0x1567,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x1577,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x1587,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x1597,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x159f,	16,	{0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3} },
+{ 0x15af,	16,	{0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60} },
+{ 0x15bf,	6,	{0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf} },
+{ 0x15c5,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x7d, 0x02, 0x16, 0x0c} },
+{ 0x15d1,	16,	{0x02, 0x16, 0x51, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x15e1,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x15f1,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x1601,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x18, 0x9e, 0xe4, 0x7e} },
+{ 0x1611,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x1621,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x1631,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x1641,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x1651,	16,	{0x75, 0x11, 0x01, 0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3} },
+{ 0x1661,	16,	{0x92, 0x25, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde} },
+{ 0x1671,	16,	{0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9} },
+{ 0x1681,	16,	{0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90} },
+{ 0x1691,	16,	{0x7f, 0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0xbc, 0xd2, 0xbe, 0xd2, 0x2c, 0x12, 0x18} },
+{ 0x16a1,	16,	{0x58, 0xc2, 0x26, 0xc2, 0x24, 0xc2, 0x27, 0x30, 0x27, 0x03, 0x12, 0x0a, 0x6b, 0x90, 0x7f, 0xd8} },
+{ 0x16b1,	16,	{0xe0, 0x65, 0x10, 0x60, 0x08, 0xe0, 0xf5, 0x10, 0x12, 0x13, 0x02, 0x80, 0xea, 0x30, 0x26, 0x07} },
+{ 0x16c1,	16,	{0xc2, 0x26, 0x12, 0x10, 0xff, 0x80, 0xe0, 0x30, 0x2a, 0xdd, 0xc2, 0x2a, 0x12, 0x00, 0x26, 0x80} },
+{ 0x16d1,	1,	{0xd6} },
+{ 0x16d2,	1,	{0x22} },
+{ 0x16d3,	16,	{0xe4, 0xfe, 0x75, 0x17, 0xff, 0x75, 0x18, 0x19, 0x75, 0x19, 0x12, 0xab, 0x17, 0xaa, 0x18, 0xa9} },
+{ 0x16e3,	16,	{0x19, 0x90, 0x00, 0x01, 0x12, 0x15, 0x28, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x16f3,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x15, 0x67, 0x85, 0xf0, 0x15, 0xf5, 0x16, 0x62, 0x15} },
+{ 0x1703,	16,	{0xe5, 0x15, 0x62, 0x16, 0xe5, 0x16, 0x62, 0x15, 0x29, 0xfd, 0xe5, 0x15, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x1713,	14,	{0x17, 0xff, 0xf5, 0x18, 0x89, 0x19, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x1721,	1,	{0x22} },
+{ 0x1722,	2,	{0x8f, 0x15} },
+{ 0x1724,	16,	{0xe4, 0xf5, 0x16, 0x75, 0x17, 0xff, 0x75, 0x18, 0x19, 0x75, 0x19, 0x86, 0xab, 0x17, 0xaa, 0x18} },
+{ 0x1734,	16,	{0xa9, 0x19, 0x90, 0x00, 0x01, 0x12, 0x15, 0x28, 0xb4, 0x03, 0x1d, 0xaf, 0x16, 0x05, 0x16, 0xef} },
+{ 0x1744,	16,	{0xb5, 0x15, 0x01, 0x22, 0x12, 0x15, 0x0f, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x1754,	14,	{0x17, 0xff, 0xf5, 0x18, 0x89, 0x19, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x1762,	1,	{0x22} },
+{ 0x1763,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30} },
+{ 0x1773,	16,	{0x2b, 0x04, 0xc2, 0x2b, 0x80, 0x02, 0xd2, 0x2a, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x1783,	14,	{0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1791,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d} },
+{ 0x17a1,	16,	{0x74, 0x02, 0xf0, 0x90, 0x7f, 0x97, 0xf0, 0xe4, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74} },
+{ 0x17b1,	12,	{0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x90, 0x7f, 0x9d, 0xf0, 0x22} },
+{ 0x17bd,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90} },
+{ 0x17cd,	16,	{0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0} },
+{ 0x17dd,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x17e7,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2} },
+{ 0x17f7,	16,	{0x26, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85} },
+{ 0x1807,	7,	{0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x180e,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x181e,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x182e,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1833,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x1843,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x1853,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1858,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x2c, 0x04, 0xe0, 0x44} },
+{ 0x1868,	16,	{0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x00, 0x06, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x1878,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x187d,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x188d,	1,	{0x22} },
+{ 0x188e,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x189e,	16,	{0x01, 0x1a, 0x00, 0x03, 0x1b, 0x03, 0x00, 0x00, 0xc1, 0x26, 0xc1, 0x2a, 0xc1, 0x25, 0xc1, 0xa9} },
+{ 0x18ae,	2,	{0xc1, 0xab} },
+{ 0x18b0,	1,	{0x00} },
+{ 0x1900,	16,	{0x12, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x0f, 0x01, 0x00, 0x00, 0x01, 0x02} },
+{ 0x1910,	16,	{0x00, 0x01, 0x09, 0x02, 0x74, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e} },
+{ 0x1920,	16,	{0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1930,	16,	{0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1940,	16,	{0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1950,	16,	{0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02} },
+{ 0x1960,	16,	{0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00} },
+{ 0x1970,	16,	{0x00, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x07} },
+{ 0x1980,	16,	{0x05, 0x87, 0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00} },
+{ 0x1990,	16,	{0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00} },
+{ 0x19a0,	16,	{0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00} },
+{ 0x19b0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00} },
+{ 0x19c0,	16,	{0x6f, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x19d0,	16,	{0x2e, 0x00, 0x36, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00} },
+{ 0x19e0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00} },
+{ 0x19f0,	16,	{0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00} },
+{ 0x1a00,	10,	{0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00} },
+{ 0x1b00,	16,	{0x02, 0x17, 0xe7, 0x00, 0x02, 0x18, 0x0e, 0x00, 0x02, 0x17, 0xbd, 0x00, 0x02, 0x17, 0x63, 0x00} },
+{ 0x1b10,	3,	{0x02, 0x18, 0x33} },
+{ 0xffff,	0,	{0x00} }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa28msg.h linux.18p8/drivers/usb/serial/keyspan_usa28msg.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa28msg.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_usa28msg.h	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,212 @@
+/*
+	usa28msg.h
+
+	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+	This file is available under a BSD-style copyright
+
+	Keyspan USB Async Firmware to run on Anchor EZ-USB
+
+	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 this licence text
+   	without modification, this list of conditions, and the following
+   	disclaimer.  The following copyright notice must appear immediately at
+   	the beginning of all source files:
+
+        	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+
+        	This file is available under a BSD-style copyright
+
+	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 InnoSys Incorprated may not be used to endorse or promote
+   	products derived from this software without specific prior written
+   	permission.
+
+	THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``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 OR CONTRIBUTORS 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.    
+
+	Note: these message formats are common to USA18, USA19, and USA28;
+	(for USA28X, see usa26msg.h)
+
+	Buffer formats for RX/TX data messages are not defined by
+	a structure, but are described here:
+
+	USB OUT (host -> USA28, transmit) messages contain a 
+	REQUEST_ACK indicator (set to 0xff to request an ACK at the 
+	completion of transmit; 0x00 otherwise), followed by data.
+	If the port is configured for parity, the data will be an 
+	alternating string of parity and data bytes, so the message
+	format will be:
+
+		RQSTACK PAR DAT PAR DAT ...
+
+	so the maximum length is 63 bytes (1 + 62, or 31 data bytes);
+	always an odd number for the total message length.
+
+	If there is no parity, the format is simply:
+
+		RQSTACK DAT DAT DAT ...
+
+	with a total data length of 63.
+
+	USB IN (USA28 -> host, receive) messages contain data and parity
+	if parity is configred, thusly:
+	
+		DAT PAR DAT PAR DAT PAR ...
+
+	for a total of 32 data bytes;
+	
+	If parity is not configured, the format is:
+
+		DAT DAT DAT ...
+
+	for a total of 64 data bytes.
+
+	In the TX messages (USB OUT), the 0x01 bit of the PARity byte is 
+	the parity bit.  In the RX messages (USB IN), the PARity byte is 
+	the content of the 8051's status register; the parity bit 
+	(RX_PARITY_BIT) is the 0x04 bit.
+
+	revision history:
+
+	1999may06	add resetDataToggle to control message
+	2000mar21	add rs232invalid to status response message
+	2000apr04	add 230.4Kb definition to setBaudRate
+	2000apr13	add/remove loopbackMode switch
+	2000apr13	change definition of setBaudRate to cover 115.2Kb, too
+	2000jun01	add extended BSD-style copyright text
+*/
+
+#ifndef	__USA28MSG__
+#define	__USA28MSG__
+
+/*#ifndef STUBS
+#include "datadefs.h"
+#endif*/
+
+typedef struct txAckMessage
+{
+	u8	dummy;
+} txAckMessage;
+
+typedef struct portControlMessage
+{
+	/*
+		there are four types of "commands" sent in the control message:
+
+		1.	configuration changes which must be requested by setting
+			the corresponding "set" flag (and should only be requested
+			when necessary, to reduce overhead on the USA28):
+	*/
+	u8	setBaudRate,	// 0=don't set, 1=baudLo/Hi, 2=115.2K, 3=230.4K
+		baudLo,			// host does baud divisor calculation
+		baudHi;			// baudHi is only used for first port (gives lower rates)
+
+	/*
+		2.	configuration changes which are done every time (because it's
+			hardly more trouble to do them than to check whether to do them):
+	*/
+	u8	parity,			// 1=use parity, 0=don't
+		ctsFlowControl,	// 1=use CTS flow control, 0=don't
+		xonFlowControl,	// 1=use XON/XOFF flow control, 0=don't
+		rts,			// 1=on, 0=off
+		dtr;			// 1=on, 0=off
+
+	/*
+		3.	configuration data which is simply used as is (no overhead,
+			but must be correct in every host message).
+	*/
+	u8	forwardingLength,  // forward when this number of chars available
+		forwardMs,		// forward this many ms after last rx data
+		breakThreshold,	// specified in ms, 1-255 (see note below)
+		xonChar,		// specified in current character format
+		xoffChar;		// specified in current character format
+
+	/*
+		4.	commands which are flags only; these are processed in order
+			(so that, e.g., if both _txOn and _txOff flags are set, the
+			port ends in a TX_OFF state); any non-zero value is respected
+	*/
+	u8	_txOn,			// enable transmitting (and continue if there's data)
+		_txOff,			// stop transmitting
+		txFlush,		// toss outbound data
+		txForceXoff,	// pretend we've received XOFF
+		txBreak,		// turn on break (leave on until txOn clears it)
+		rxOn,			// turn on receiver
+		rxOff,			// turn off receiver
+		rxFlush,		// toss inbound data
+		rxForward,		// forward all inbound data, NOW
+		returnStatus,	// return current status n times (1 or 2)
+		resetDataToggle;// reset data toggle state to DATA0
+	
+} portControlMessage;
+
+typedef struct portStatusMessage
+{
+	u8	port,			// 0=first, 1=second, 2=global (see below)
+		cts,
+		dsr,			// (not used in all products)
+		dcd,
+
+		ri,				// (not used in all products)
+		_txOff,			// port has been disabled (by host)
+		_txXoff,		// port is in XOFF state (either host or RX XOFF)
+		dataLost,		// count of lost chars; wraps; not guaranteed exact
+
+		rxEnabled,		// as configured by rxOn/rxOff 1=on, 0=off
+		rxBreak,		// 1=we're in break state
+		rs232invalid,	// 1=no valid signals on rs-232 inputs
+		controlResponse;// 1=a control messages has been processed
+} portStatusMessage;
+
+// bit defines in txState
+#define	TX_OFF			0x01	// requested by host txOff command
+#define	TX_XOFF			0x02	// either real, or simulated by host
+
+typedef struct globalControlMessage
+{
+	u8	sendGlobalStatus,	// 2=request for two status responses
+		resetStatusToggle,	// 1=reset global status toggle
+		resetStatusCount;	// a cycling value
+} globalControlMessage;
+
+typedef struct globalStatusMessage
+{
+	u8	port,				// 3
+		sendGlobalStatus,	// from request, decremented
+		resetStatusCount;	// as in request
+} globalStatusMessage;
+
+typedef struct globalDebugMessage
+{
+	u8	port,				// 2
+		n,					// typically a count/status byte
+		b;					// typically a data byte
+} globalDebugMessage;
+
+// ie: the maximum length of an EZUSB endpoint buffer
+#define	MAX_DATA_LEN			64
+
+// the parity bytes have only one significant bit
+#define	RX_PARITY_BIT			0x04
+#define	TX_PARITY_BIT			0x01
+
+// update status approx. 60 times a second (16.6666 ms)
+#define	STATUS_UPDATE_INTERVAL	16
+
+#endif
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa28x_fw.h linux.18p8/drivers/usb/serial/keyspan_usa28x_fw.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa28x_fw.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/keyspan_usa28x_fw.h	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,406 @@
+/* keyspan_usa28x_fw.h
+  
+   Generated from Keyspan firmware image Wed Jul  5 09:18:29 2000 EST
+   This firmware is for the Keyspan USA-28X Serial Adaptor
+
+   "The firmware contained herein as keyspan_usa28x_fw.h is
+   Copyright (C) 1999-2000 Keyspan, A division of InnoSys Incorporated
+   ("Keyspan"), as an unpublished work.  This notice does not imply
+   unrestricted or public access to this firmware which is a trade secret of
+   Keyspan, and which may not be reproduced, used, sold or transferred to any
+   third party without Keyspan's prior written consent.  All Rights Reserved.
+
+   This firmware may not be modified and may only be used with the Keyspan 
+   USA-28X Serial Adapter.  Distribution and/or Modification of the
+   keyspan.c driver which includes this firmware, in whole or in part,
+   requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa28x_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x0e, 0x9b} },
+{ 0x0003,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x30, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} },
+{ 0x0013,	16,	{0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90} },
+{ 0x0023,	15,	{0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x07, 0xf0, 0xe4, 0x90, 0x7f, 0x98, 0xf0, 0x22} },
+{ 0x0033,	3,	{0x02, 0x13, 0xfc} },
+{ 0x0036,	12,	{0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0043,	3,	{0x02, 0x14, 0x00} },
+{ 0x0046,	16,	{0x30, 0x08, 0x13, 0x12, 0x13, 0xc0, 0xef, 0xc3, 0x95, 0x3c, 0x50, 0x73, 0x90, 0x7f, 0xbf, 0x74} },
+{ 0x0056,	16,	{0x01, 0xf0, 0xc2, 0x08, 0x80, 0x69, 0x30, 0x02, 0x34, 0x90, 0x7f, 0xc6, 0xe0, 0x20, 0xe1, 0x5f} },
+{ 0x0066,	16,	{0x12, 0x13, 0xc0, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x56, 0x90, 0x7e, 0x40, 0xe0, 0x13, 0x92, 0x08} },
+{ 0x0076,	16,	{0x90, 0x7f, 0xc7, 0xe0, 0x14, 0xf5, 0x08, 0x7e, 0x7e, 0x7f, 0x41, 0x75, 0x0c, 0x7e, 0x75, 0x0d} },
+{ 0x0086,	16,	{0x41, 0x12, 0x0d, 0x55, 0xc2, 0x02, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x32, 0x90, 0x7f, 0xc8} },
+{ 0x0096,	16,	{0xe0, 0x20, 0xe1, 0x2b, 0x12, 0x13, 0xc0, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x22, 0x90, 0x7d, 0xc0} },
+{ 0x00a6,	16,	{0xe0, 0x13, 0x92, 0x08, 0x90, 0x7f, 0xc9, 0xe0, 0x14, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0xc1, 0x75} },
+{ 0x00b6,	16,	{0x0c, 0x7d, 0x75, 0x0d, 0xc1, 0x12, 0x0d, 0x55, 0xd2, 0x02, 0xe4, 0x90, 0x7f, 0xc9, 0xf0, 0x90} },
+{ 0x00c6,	16,	{0x7f, 0xb6, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x01, 0x53, 0x53, 0x36, 0x80, 0x12, 0x13, 0xcc, 0xef} },
+{ 0x00d6,	16,	{0x42, 0x36, 0x12, 0x12, 0x49, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3a, 0x50, 0x0f, 0x12, 0x13, 0xa8} },
+{ 0x00e6,	16,	{0xef, 0x30, 0xe0, 0x08, 0xe5, 0x36, 0x20, 0xe7, 0x03, 0x30, 0x0a, 0x61, 0xc2, 0x0a, 0xe5, 0x19} },
+{ 0x00f6,	16,	{0x70, 0x04, 0xf5, 0x36, 0x80, 0x57, 0x12, 0x13, 0xcc, 0xef, 0x42, 0x36, 0xe5, 0x36, 0x30, 0xe7} },
+{ 0x0106,	16,	{0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08, 0x7e, 0x7e} },
+{ 0x0116,	16,	{0x7f, 0x80, 0x75, 0x0c, 0x7e, 0x75, 0x0d, 0x80, 0xaf, 0x36, 0x12, 0x0f, 0xb7, 0xe5, 0x19, 0x25} },
+{ 0x0126,	16,	{0xe0, 0x90, 0x7f, 0xb7, 0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03, 0x75, 0x19} },
+{ 0x0136,	16,	{0x3f, 0x85, 0x19, 0x08, 0xe4, 0x90, 0x7e, 0x80, 0xf0, 0x7e, 0x7e, 0x7f, 0x81, 0x75, 0x0c, 0x7e} },
+{ 0x0146,	16,	{0x75, 0x0d, 0x81, 0x12, 0x0d, 0x7a, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xb7, 0xf0, 0x90, 0x7f, 0xce} },
+{ 0x0156,	16,	{0xe0, 0x30, 0xe1, 0x06, 0x20, 0x04, 0x03, 0x02, 0x03, 0xbd, 0xc2, 0x04, 0xe4, 0xf5, 0x18, 0x74} },
+{ 0x0166,	16,	{0x40, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7c, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18, 0x7c, 0x00} },
+{ 0x0176,	16,	{0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x00, 0x24, 0x00, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef, 0x12, 0x0c} },
+{ 0x0186,	16,	{0xe5, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x00, 0xe0, 0x60, 0x68, 0x90, 0x7e} },
+{ 0x0196,	16,	{0x03, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x24, 0x7f, 0x03, 0x7d, 0xcd, 0x12} },
+{ 0x01a6,	16,	{0x12, 0x24, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46} },
+{ 0x01b6,	16,	{0xf0, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x01, 0xe0, 0xff, 0x12, 0x10, 0xa8} },
+{ 0x01c6,	16,	{0x90, 0x7e, 0x02, 0xe0, 0xff, 0x12, 0x10, 0xce, 0x7f, 0x01, 0x90, 0x7e, 0x11, 0xe0, 0xfd, 0x12} },
+{ 0x01d6,	16,	{0x12, 0x24, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x24, 0x43, 0x46, 0x80, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x01e6,	16,	{0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40} },
+{ 0x01f6,	16,	{0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x03, 0xe0, 0x70, 0x06, 0x90, 0x7e, 0x13, 0xe0} },
+{ 0x0206,	16,	{0x70, 0x08, 0xe4, 0x90, 0x7e, 0x13, 0xf0, 0x75, 0x25, 0xff, 0x90, 0x7e, 0x05, 0xe0, 0x60, 0x12} },
+{ 0x0216,	16,	{0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x44, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe5} },
+{ 0x0226,	16,	{0x44, 0xf0, 0x90, 0x7e, 0x07, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x42, 0x80, 0x80} },
+{ 0x0236,	16,	{0x03, 0x53, 0x42, 0x7f, 0x53, 0x42, 0xfc, 0x90, 0x7e, 0x09, 0xe0, 0x60, 0x11, 0x43, 0x42, 0x02} },
+{ 0x0246,	16,	{0xa3, 0xe0, 0xff, 0x12, 0x11, 0x1a, 0x90, 0x7e, 0x0b, 0xe0, 0xff, 0x12, 0x11, 0x40, 0xaf, 0x42} },
+{ 0x0256,	16,	{0x12, 0x10, 0xf4, 0x90, 0x7e, 0x03, 0xe0, 0x60, 0x08, 0x53, 0x42, 0x7f, 0xaf, 0x42, 0x12, 0x10} },
+{ 0x0266,	16,	{0xf4, 0x90, 0x7e, 0x0c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x02, 0x80, 0x03} },
+{ 0x0276,	16,	{0x53, 0x46, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90} },
+{ 0x0286,	16,	{0x7e, 0x0e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x46, 0x01, 0x80, 0x03, 0x53, 0x46} },
+{ 0x0296,	16,	{0xfe, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x12} },
+{ 0x02a6,	16,	{0xe0, 0xf5, 0x3a, 0xa3, 0xe0, 0x13, 0x92, 0x0c, 0xa3, 0xe0, 0xf5, 0x3c, 0xa3, 0xe0, 0x60, 0x05} },
+{ 0x02b6,	16,	{0x43, 0x46, 0x10, 0x80, 0x03, 0x53, 0x46, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0} },
+{ 0x02c6,	16,	{0x00, 0xe5, 0x46, 0xf0, 0x90, 0x7e, 0x16, 0xe0, 0x60, 0x32, 0x53, 0x44, 0xbf, 0x90, 0x7f, 0x98} },
+{ 0x02d6,	16,	{0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x11} },
+{ 0x02e6,	16,	{0xf0, 0x12, 0x13, 0x9c, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3e, 0xfd, 0xe4, 0xff} },
+{ 0x02f6,	16,	{0xad, 0x3e, 0x12, 0x12, 0x24, 0xe4, 0xf5, 0x2a, 0xf5, 0x29, 0xd2, 0x06, 0x90, 0x7e, 0x17, 0xe0} },
+{ 0x0306,	16,	{0x60, 0x0f, 0x43, 0x3e, 0x02, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x12, 0x24, 0x75, 0x29, 0x01, 0xd2} },
+{ 0x0316,	16,	{0x06, 0x90, 0x7e, 0x18, 0xe0, 0x60, 0x1b, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5, 0x40, 0x44} },
+{ 0x0326,	16,	{0x04, 0x90, 0xc0, 0x00, 0xf0, 0xe4, 0x90, 0x7f, 0xc7, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0xd2, 0x02} },
+{ 0x0336,	16,	{0xc2, 0x08, 0x90, 0x7e, 0x19, 0xe0, 0x60, 0x11, 0x43, 0x44, 0x40, 0x90, 0x7f, 0x98, 0x74, 0x13} },
+{ 0x0346,	16,	{0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1a, 0xe0, 0x60, 0x0f, 0x53} },
+{ 0x0356,	16,	{0x3e, 0xfe, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x12, 0x24, 0x75, 0x2b, 0x01, 0xd2, 0x06, 0x90, 0x7e} },
+{ 0x0366,	16,	{0x1b, 0xe0, 0x60, 0x0f, 0x43, 0x3e, 0x01, 0xe4, 0xff, 0xad, 0x3e, 0x12, 0x12, 0x24, 0xe4, 0xf5} },
+{ 0x0376,	16,	{0x2b, 0xd2, 0x06, 0x90, 0x7e, 0x1c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0xe5} },
+{ 0x0386,	16,	{0x40, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x1d, 0xe0, 0x60, 0x02, 0xd2, 0x0a, 0x90} },
+{ 0x0396,	16,	{0x7e, 0x1e, 0xe0, 0x60, 0x08, 0x75, 0x2c, 0x01, 0xe4, 0xf5, 0x38, 0xd2, 0x06, 0x90, 0x7e, 0x1f} },
+{ 0x03a6,	16,	{0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x11, 0xf0, 0x74, 0x31, 0xf0, 0x74, 0x15, 0xf0, 0x74} },
+{ 0x03b6,	16,	{0x35, 0xf0, 0xe4, 0x90, 0x7f, 0xcf, 0xf0, 0x30, 0x18, 0x52, 0xe5, 0x38, 0x60, 0x02, 0x15, 0x38} },
+{ 0x03c6,	16,	{0x20, 0x12, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e, 0x75, 0x13} },
+{ 0x03d6,	16,	{0x0a, 0x30, 0x19, 0x02, 0xd2, 0x12, 0x12, 0x13, 0x9c, 0xef, 0x54, 0x01, 0xf5, 0x19, 0x65, 0x2a} },
+{ 0x03e6,	16,	{0x60, 0x05, 0x85, 0x19, 0x2a, 0xd2, 0x06, 0x12, 0x13, 0xd8, 0xef, 0x54, 0x80, 0xf5, 0x19, 0x65} },
+{ 0x03f6,	16,	{0x26, 0x60, 0x05, 0x85, 0x19, 0x26, 0xd2, 0x06, 0x30, 0x0c, 0x11, 0x12, 0x13, 0xd8, 0xef, 0x54} },
+{ 0x0406,	16,	{0x10, 0xf5, 0x19, 0x65, 0x25, 0x60, 0x05, 0x85, 0x19, 0x25, 0xd2, 0x06, 0x20, 0x19, 0x03, 0x02} },
+{ 0x0416,	16,	{0x07, 0xe4, 0x30, 0x09, 0x13, 0x12, 0x14, 0x2b, 0xef, 0xc3, 0x95, 0x3d, 0x50, 0x73, 0x90, 0x7f} },
+{ 0x0426,	16,	{0xc1, 0x74, 0x01, 0xf0, 0xc2, 0x09, 0x80, 0x69, 0x30, 0x03, 0x34, 0x90, 0x7f, 0xca, 0xe0, 0x20} },
+{ 0x0436,	16,	{0xe1, 0x5f, 0x12, 0x14, 0x2b, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x56, 0x90, 0x7d, 0x40, 0xe0, 0x13} },
+{ 0x0446,	16,	{0x92, 0x09, 0x90, 0x7f, 0xcb, 0xe0, 0x14, 0xf5, 0x08, 0x7e, 0x7d, 0x7f, 0x41, 0x75, 0x0c, 0x7d} },
+{ 0x0456,	16,	{0x75, 0x0d, 0x41, 0x12, 0x0d, 0x9f, 0xc2, 0x03, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x32, 0x90} },
+{ 0x0466,	16,	{0x7f, 0xcc, 0xe0, 0x20, 0xe1, 0x2b, 0x12, 0x14, 0x2b, 0xef, 0xc3, 0x94, 0x40, 0x50, 0x22, 0x90} },
+{ 0x0476,	16,	{0x7c, 0xc0, 0xe0, 0x13, 0x92, 0x09, 0x90, 0x7f, 0xcd, 0xe0, 0x14, 0xf5, 0x08, 0x7e, 0x7c, 0x7f} },
+{ 0x0486,	16,	{0xc1, 0x75, 0x0c, 0x7c, 0x75, 0x0d, 0xc1, 0x12, 0x0d, 0x9f, 0xd2, 0x03, 0xe4, 0x90, 0x7f, 0xcd} },
+{ 0x0496,	16,	{0xf0, 0x90, 0x7f, 0xba, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x05, 0x25, 0x53, 0x37, 0x80, 0x12, 0x14} },
+{ 0x04a6,	16,	{0x37, 0xef, 0x42, 0x37, 0x12, 0x12, 0x93, 0x8f, 0x19, 0xef, 0xc3, 0x95, 0x3b, 0x50, 0x0f, 0x12} },
+{ 0x04b6,	16,	{0x14, 0x13, 0xef, 0x30, 0xe0, 0x08, 0xe5, 0x37, 0x20, 0xe7, 0x03, 0x30, 0x0b, 0x61, 0xc2, 0x0b} },
+{ 0x04c6,	16,	{0xe5, 0x19, 0x70, 0x04, 0xf5, 0x37, 0x80, 0x57, 0x12, 0x14, 0x37, 0xef, 0x42, 0x37, 0xe5, 0x37} },
+{ 0x04d6,	16,	{0x30, 0xe7, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x19, 0x20, 0x85, 0x19, 0x08} },
+{ 0x04e6,	16,	{0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x0c, 0x7d, 0x75, 0x0d, 0x80, 0xaf, 0x37, 0x12, 0x0f, 0xf0, 0xe5} },
+{ 0x04f6,	16,	{0x19, 0x25, 0xe0, 0x90, 0x7f, 0xbb, 0xf0, 0x80, 0x26, 0xe5, 0x19, 0xd3, 0x94, 0x3f, 0x40, 0x03} },
+{ 0x0506,	16,	{0x75, 0x19, 0x3f, 0x85, 0x19, 0x08, 0xe4, 0x90, 0x7d, 0x80, 0xf0, 0x7e, 0x7d, 0x7f, 0x81, 0x75} },
+{ 0x0516,	16,	{0x0c, 0x7d, 0x75, 0x0d, 0x81, 0x12, 0x0d, 0xc4, 0xe5, 0x19, 0x04, 0x90, 0x7f, 0xbb, 0xf0, 0x90} },
+{ 0x0526,	16,	{0x7f, 0xd0, 0xe0, 0x30, 0xe1, 0x06, 0x20, 0x05, 0x03, 0x02, 0x07, 0x8f, 0xc2, 0x05, 0xe4, 0xf5} },
+{ 0x0536,	16,	{0x18, 0x74, 0xc0, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x18} },
+{ 0x0546,	16,	{0x7c, 0x00, 0x7b, 0x01, 0x7a, 0x7e, 0x79, 0x20, 0x24, 0x20, 0xf9, 0xec, 0x34, 0x7e, 0xfa, 0xef} },
+{ 0x0556,	16,	{0x12, 0x0c, 0xe5, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x20, 0xd7, 0x90, 0x7e, 0x20, 0xe0, 0x60, 0x68} },
+{ 0x0566,	16,	{0x90, 0x7e, 0x23, 0xe0, 0x60, 0x24, 0x7f, 0x01, 0xe4, 0xfd, 0x12, 0x12, 0x6e, 0x7f, 0x03, 0x7d} },
+{ 0x0576,	16,	{0xcd, 0x12, 0x12, 0x6e, 0x43, 0x47, 0x80, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00} },
+{ 0x0586,	16,	{0xe5, 0x47, 0xf0, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x80, 0x30, 0x90, 0x7e, 0x21, 0xe0, 0xff, 0x12} },
+{ 0x0596,	16,	{0x11, 0x8c, 0x90, 0x7e, 0x22, 0xe0, 0xff, 0x12, 0x11, 0xb2, 0x7f, 0x01, 0x90, 0x7e, 0x31, 0xe0} },
+{ 0x05a6,	16,	{0xfd, 0x12, 0x12, 0x6e, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x6e, 0x43, 0x47, 0x80, 0x90, 0x7f} },
+{ 0x05b6,	16,	{0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0} },
+{ 0x05c6,	16,	{0xe5, 0x41, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x23, 0xe0, 0x70, 0x06, 0x90, 0x7e} },
+{ 0x05d6,	16,	{0x33, 0xe0, 0x70, 0x08, 0xe4, 0x90, 0x7e, 0x33, 0xf0, 0x75, 0x2e, 0xff, 0x90, 0x7e, 0x25, 0xe0} },
+{ 0x05e6,	16,	{0x60, 0x12, 0xa3, 0xe0, 0x54, 0x3f, 0xf5, 0x45, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0} },
+{ 0x05f6,	16,	{0x00, 0xe5, 0x45, 0xf0, 0x90, 0x7e, 0x27, 0xe0, 0x60, 0x2b, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x43} },
+{ 0x0606,	16,	{0x80, 0x80, 0x03, 0x53, 0x43, 0x7f, 0x53, 0x43, 0xfc, 0x90, 0x7e, 0x29, 0xe0, 0x60, 0x11, 0x43} },
+{ 0x0616,	16,	{0x43, 0x02, 0xa3, 0xe0, 0xff, 0x12, 0x11, 0xd8, 0x90, 0x7e, 0x2b, 0xe0, 0xff, 0x12, 0x11, 0xfe} },
+{ 0x0626,	16,	{0xaf, 0x43, 0x12, 0x11, 0x66, 0x90, 0x7e, 0x23, 0xe0, 0x60, 0x08, 0x53, 0x43, 0x7f, 0xaf, 0x43} },
+{ 0x0636,	16,	{0x12, 0x11, 0x66, 0x90, 0x7e, 0x2c, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x02} },
+{ 0x0646,	16,	{0x80, 0x03, 0x53, 0x47, 0xfd, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47} },
+{ 0x0656,	16,	{0xf0, 0x90, 0x7e, 0x2e, 0xe0, 0x60, 0x18, 0xa3, 0xe0, 0x60, 0x05, 0x43, 0x47, 0x01, 0x80, 0x03} },
+{ 0x0666,	16,	{0x53, 0x47, 0xfe, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90} },
+{ 0x0676,	16,	{0x7e, 0x32, 0xe0, 0xf5, 0x3b, 0xa3, 0xe0, 0x13, 0x92, 0x0d, 0xa3, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0} },
+{ 0x0686,	16,	{0x60, 0x05, 0x43, 0x47, 0x10, 0x80, 0x03, 0x53, 0x47, 0xef, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0} },
+{ 0x0696,	16,	{0x90, 0xc0, 0x00, 0xe5, 0x47, 0xf0, 0x90, 0x7e, 0x36, 0xe0, 0x60, 0x32, 0x53, 0x45, 0xbf, 0x90} },
+{ 0x06a6,	16,	{0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98} },
+{ 0x06b6,	16,	{0x74, 0x09, 0xf0, 0x12, 0x13, 0xf0, 0xef, 0x54, 0xfe, 0x90, 0xc0, 0x00, 0xf0, 0x53, 0x3f, 0xfd} },
+{ 0x06c6,	16,	{0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x6e, 0xe4, 0xf5, 0x33, 0xf5, 0x32, 0xd2, 0x07, 0x90, 0x7e} },
+{ 0x06d6,	16,	{0x37, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x02, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x6e, 0x75, 0x32} },
+{ 0x06e6,	16,	{0x01, 0xd2, 0x07, 0x90, 0x7e, 0x38, 0xe0, 0x60, 0x1b, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0xe5} },
+{ 0x06f6,	16,	{0x41, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0, 0xe4, 0x90, 0x7f, 0xcb, 0xf0, 0x90, 0x7f, 0xcd, 0xf0} },
+{ 0x0706,	16,	{0xd2, 0x03, 0xc2, 0x09, 0x90, 0x7e, 0x39, 0xe0, 0x60, 0x11, 0x43, 0x45, 0x40, 0x90, 0x7f, 0x98} },
+{ 0x0716,	16,	{0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3a, 0xe0, 0x60} },
+{ 0x0726,	16,	{0x0f, 0x53, 0x3f, 0xfe, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x6e, 0x75, 0x34, 0x01, 0xd2, 0x07} },
+{ 0x0736,	16,	{0x90, 0x7e, 0x3b, 0xe0, 0x60, 0x0f, 0x43, 0x3f, 0x01, 0xe4, 0xff, 0xad, 0x3f, 0x12, 0x12, 0x6e} },
+{ 0x0746,	16,	{0xe4, 0xf5, 0x34, 0xd2, 0x07, 0x90, 0x7e, 0x3c, 0xe0, 0x60, 0x0e, 0x90, 0x7f, 0x98, 0x74, 0x0a} },
+{ 0x0756,	16,	{0xf0, 0xe5, 0x41, 0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7e, 0x3d, 0xe0, 0x60, 0x02, 0xd2} },
+{ 0x0766,	16,	{0x0b, 0x90, 0x7e, 0x3e, 0xe0, 0x60, 0x08, 0x75, 0x35, 0x01, 0xe4, 0xf5, 0x39, 0xd2, 0x07, 0x90} },
+{ 0x0776,	16,	{0x7e, 0x3f, 0xe0, 0x60, 0x0f, 0x90, 0x7f, 0xd7, 0x74, 0x13, 0xf0, 0x74, 0x33, 0xf0, 0x74, 0x16} },
+{ 0x0786,	16,	{0xf0, 0x74, 0x36, 0xf0, 0xe4, 0x90, 0x7f, 0xd1, 0xf0, 0x30, 0x18, 0x52, 0xe5, 0x39, 0x60, 0x02} },
+{ 0x0796,	16,	{0x15, 0x39, 0x30, 0x12, 0x49, 0xe5, 0x13, 0xd3, 0x94, 0x00, 0x40, 0x04, 0x15, 0x13, 0x80, 0x3e} },
+{ 0x07a6,	16,	{0x75, 0x13, 0x0a, 0x30, 0x19, 0x02, 0xc2, 0x12, 0x12, 0x13, 0xf0, 0xef, 0x54, 0x01, 0xf5, 0x19} },
+{ 0x07b6,	16,	{0x65, 0x33, 0x60, 0x05, 0x85, 0x19, 0x33, 0xd2, 0x07, 0x12, 0x14, 0x43, 0xef, 0x54, 0x80, 0xf5} },
+{ 0x07c6,	16,	{0x19, 0x65, 0x2f, 0x60, 0x05, 0x85, 0x19, 0x2f, 0xd2, 0x07, 0x30, 0x0d, 0x11, 0x12, 0x14, 0x43} },
+{ 0x07d6,	16,	{0xef, 0x54, 0x10, 0xf5, 0x19, 0x65, 0x2e, 0x60, 0x05, 0x85, 0x19, 0x2e, 0xd2, 0x07, 0x30, 0x18} },
+{ 0x07e6,	16,	{0x2a, 0x90, 0x7f, 0xd2, 0xe0, 0x20, 0xe1, 0x23, 0x90, 0x7b, 0x40, 0xe0, 0x60, 0x09, 0xe0, 0xf5} },
+{ 0x07f6,	16,	{0x15, 0x90, 0x7b, 0x42, 0xe0, 0xf5, 0x16, 0x90, 0x7b, 0x41, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7} },
+{ 0x0806,	16,	{0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x90, 0x7f, 0xc2, 0xe0, 0x30} },
+{ 0x0816,	16,	{0xe1, 0x03, 0x02, 0x09, 0x18, 0xe5, 0x0a, 0x70, 0x40, 0x30, 0x06, 0x39, 0xe5, 0x38, 0x70, 0x35} },
+{ 0x0826,	16,	{0xc2, 0x06, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00} },
+{ 0x0836,	16,	{0xfa, 0x12, 0x0c, 0x9f, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83} },
+{ 0x0846,	16,	{0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75} },
+{ 0x0856,	16,	{0x38, 0x10, 0xe4, 0xf5, 0x2c, 0x75, 0x0a, 0x01, 0x22, 0xe5, 0x0a, 0x64, 0x01, 0x70, 0x40, 0x30} },
+{ 0x0866,	16,	{0x07, 0x39, 0xe5, 0x39, 0x70, 0x35, 0xc2, 0x07, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x2d} },
+{ 0x0876,	16,	{0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0c, 0x9f, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5} },
+{ 0x0886,	16,	{0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x09, 0xdb, 0x90} },
+{ 0x0896,	16,	{0x7f, 0xc3, 0x74, 0x09, 0xf0, 0x75, 0x39, 0x10, 0xe4, 0xf5, 0x35, 0x75, 0x0a, 0x02, 0x22, 0xe5} },
+{ 0x08a6,	16,	{0x0a, 0x64, 0x02, 0x70, 0x36, 0x30, 0x13, 0x2f, 0xc2, 0x13, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00} },
+{ 0x08b6,	16,	{0x74, 0x0e, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x0c, 0x9f, 0xff, 0x74, 0x80, 0x25} },
+{ 0x08c6,	16,	{0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x05} },
+{ 0x08d6,	16,	{0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x05, 0xf0, 0x75, 0x0a, 0x03, 0x22, 0xe5, 0x15, 0x60, 0x30, 0x15} },
+{ 0x08e6,	16,	{0x15, 0xe4, 0xf5, 0x18, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x14, 0x25, 0x18, 0xf9, 0xee, 0x34, 0x00} },
+{ 0x08f6,	16,	{0xfa, 0x12, 0x0c, 0x9f, 0xff, 0x74, 0x80, 0x25, 0x18, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83} },
+{ 0x0906,	16,	{0xef, 0xf0, 0x05, 0x18, 0xe5, 0x18, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4} },
+{ 0x0916,	2,	{0xf5, 0x0a} },
+{ 0x0918,	1,	{0x22} },
+{ 0x0919,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x0d, 0x2f, 0x09, 0xe9, 0x00, 0x0a, 0x5d, 0x01, 0x0a, 0xc9, 0x03} },
+{ 0x0929,	16,	{0x09, 0x3c, 0x06, 0x09, 0xdc, 0x08, 0x09, 0xd6, 0x09, 0x09, 0xbe, 0x0a, 0x09, 0xcd, 0x0b, 0x00} },
+{ 0x0939,	16,	{0x00, 0x0b, 0x18, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02} },
+{ 0x0949,	16,	{0x70, 0x69, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b} },
+{ 0x0959,	16,	{0x1f, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0f, 0x27, 0x8b, 0x18, 0x8a, 0x19, 0x89, 0x1a, 0xea} },
+{ 0x0969,	16,	{0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5} },
+{ 0x0979,	16,	{0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f} },
+{ 0x0989,	16,	{0xea, 0xe0, 0xff, 0x12, 0x0f, 0x76, 0x8b, 0x18, 0x8a, 0x19, 0x89, 0x1a, 0xea, 0x49, 0x60, 0x11} },
+{ 0x0999,	16,	{0xae, 0x02, 0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x0b} },
+{ 0x09a9,	16,	{0x1f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x09b9,	16,	{0x01, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0x00, 0xe5, 0x09, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01} },
+{ 0x09c9,	16,	{0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x09, 0x02, 0x0b, 0x1f, 0x12, 0x0b, 0x27} },
+{ 0x09d9,	16,	{0x02, 0x0b, 0x1f, 0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x0b, 0x1f} },
+{ 0x09e9,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
+{ 0x09f9,	16,	{0x0f, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x14, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
+{ 0x0a09,	16,	{0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x1f, 0xe4, 0x90, 0x7f, 0x00} },
+{ 0x0a19,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x0a29,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x0a39,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
+{ 0x0a49,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x0a59,	16,	{0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03} },
+{ 0x0a69,	16,	{0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x0f, 0x02, 0x0b, 0x1f, 0x90} },
+{ 0x0a79,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x0b, 0x1f, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90} },
+{ 0x0a89,	16,	{0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
+{ 0x0a99,	16,	{0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x0aa9,	16,	{0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7} },
+{ 0x0ab9,	16,	{0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56} },
+{ 0x0ac9,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x0ad9,	16,	{0xb4, 0x01, 0x04, 0xd2, 0x0f, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36} },
+{ 0x0ae9,	16,	{0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54} },
+{ 0x0af9,	16,	{0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
+{ 0x0b09,	16,	{0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90} },
+{ 0x0b19,	13,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0b26,	1,	{0x22} },
+{ 0x0b27,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0x18, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} },
+{ 0x0b37,	16,	{0x90, 0x7f, 0x95, 0x74, 0xc0, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x0b47,	16,	{0x18, 0xf0, 0xe4, 0xf5, 0x8e, 0x90, 0x7f, 0xdf, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0xe4} },
+{ 0x0b57,	16,	{0xf5, 0x24, 0x75, 0x1b, 0x01, 0x7b, 0x00, 0x74, 0x24, 0x25, 0x1b, 0xf9, 0xe4, 0x34, 0x00, 0xfa} },
+{ 0x0b67,	16,	{0xe4, 0x12, 0x0c, 0xe5, 0x05, 0x1b, 0xe5, 0x1b, 0xb4, 0x09, 0xea, 0x75, 0x3a, 0x01, 0xe4, 0xf5} },
+{ 0x0b77,	16,	{0x38, 0xf5, 0x13, 0xf5, 0x36, 0xc2, 0x06, 0xc2, 0x0a, 0xc2, 0x04, 0xc2, 0x08, 0xc2, 0x12, 0xd2} },
+{ 0x0b87,	16,	{0x02, 0xd2, 0x00, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x75, 0x44, 0x03, 0x90, 0xc0, 0x00, 0x74} },
+{ 0x0b97,	16,	{0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x12, 0x24, 0x7f, 0x10, 0x8f, 0x42, 0x12, 0x10, 0xf4} },
+{ 0x0ba7,	16,	{0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x7f, 0x01, 0x8f, 0x40, 0xef, 0x44, 0x06, 0x90, 0xc0, 0x00} },
+{ 0x0bb7,	16,	{0xf0, 0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x75, 0x46, 0x80, 0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0} },
+{ 0x0bc7,	16,	{0x0f, 0xe4, 0xfd, 0x12, 0x12, 0x24, 0xe4, 0xff, 0x7e, 0xa3, 0xad, 0x06, 0x8d, 0x3e, 0x12, 0x12} },
+{ 0x0bd7,	16,	{0x24, 0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f} },
+{ 0x0be7,	16,	{0x12, 0x12, 0x24, 0x7f, 0x01, 0x12, 0x13, 0x27, 0x7f, 0x03, 0x7d, 0x07, 0x12, 0x12, 0x24, 0x20} },
+{ 0x0bf7,	16,	{0x19, 0x03, 0x02, 0x0c, 0x9c, 0x75, 0x2d, 0x01, 0x75, 0x1b, 0x01, 0x7b, 0x00, 0x74, 0x2d, 0x25} },
+{ 0x0c07,	16,	{0x1b, 0xf9, 0xe4, 0x34, 0x00, 0xfa, 0xe4, 0x12, 0x0c, 0xe5, 0x05, 0x1b, 0xe5, 0x1b, 0xb4, 0x09} },
+{ 0x0c17,	16,	{0xea, 0x75, 0x3b, 0x01, 0xe4, 0xf5, 0x39, 0xf5, 0x13, 0xf5, 0x37, 0xc2, 0x07, 0xc2, 0x0b, 0xc2} },
+{ 0x0c27,	16,	{0x05, 0xc2, 0x09, 0xc2, 0x12, 0xd2, 0x03, 0xd2, 0x01, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x75} },
+{ 0x0c37,	16,	{0x45, 0x03, 0x90, 0xc0, 0x00, 0x74, 0x03, 0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x12, 0x6e, 0x7f} },
+{ 0x0c47,	16,	{0x10, 0x8f, 0x43, 0x12, 0x11, 0x66, 0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x7f, 0x01, 0x8f, 0x41} },
+{ 0x0c57,	16,	{0xef, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x75, 0x47, 0x80} },
+{ 0x0c67,	16,	{0x90, 0xc0, 0x00, 0x74, 0x80, 0xf0, 0x0f, 0xe4, 0xfd, 0x12, 0x12, 0x6e, 0xe4, 0xff, 0x7e, 0xa3} },
+{ 0x0c77,	16,	{0xad, 0x06, 0x8d, 0x3f, 0x12, 0x12, 0x6e, 0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00} },
+{ 0x0c87,	16,	{0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x12, 0x6e, 0x7f, 0x01, 0x12, 0x13, 0x48, 0x7f, 0x03} },
+{ 0x0c97,	7,	{0x7d, 0x07, 0x12, 0x12, 0x6e, 0xd2, 0x11} },
+{ 0x0c9e,	1,	{0x22} },
+{ 0x0c9f,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x0caf,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0cb8,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x0cc8,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x0cd8,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0ce5,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01} },
+{ 0x0cf5,	2,	{0xf3, 0x22} },
+{ 0x0cf7,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x0d07,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x0d17,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x0d27,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x0d2f,	16,	{0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3} },
+{ 0x0d3f,	16,	{0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60} },
+{ 0x0d4f,	6,	{0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf} },
+{ 0x0d55,	16,	{0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83} },
+{ 0x0d65,	16,	{0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86} },
+{ 0x0d75,	16,	{0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x10, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5} },
+{ 0x0d85,	16,	{0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0} },
+{ 0x0d95,	16,	{0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05, 0x86, 0xd2, 0xaf, 0x22, 0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0} },
+{ 0x0da5,	16,	{0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2, 0xaf, 0x05, 0x86, 0x90, 0xc0} },
+{ 0x0db5,	16,	{0x00, 0x05, 0x86, 0xe0, 0xa3, 0x05, 0x86, 0xf0, 0x05, 0x86, 0xdf, 0xf7, 0xd2, 0xaf, 0x22, 0x90} },
+{ 0x0dc5,	16,	{0x7f, 0x98, 0x74, 0x08, 0xf0, 0xaf, 0x08, 0xe5, 0x0d, 0xf5, 0x82, 0xe5, 0x0c, 0xf5, 0x83, 0xc2} },
+{ 0x0dd5,	16,	{0xaf, 0x05, 0x86, 0x90, 0xc0, 0x00, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xf7, 0x05} },
+{ 0x0de5,	4,	{0x86, 0xd2, 0xaf, 0x22} },
+{ 0x0de9,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x0df9,	1,	{0x22} },
+{ 0x0dfa,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x0e0a,	16,	{0xd2, 0x17, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92} },
+{ 0x0e1a,	16,	{0x0f, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74} },
+{ 0x0e2a,	16,	{0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0} },
+{ 0x0e3a,	16,	{0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f} },
+{ 0x0e4a,	16,	{0xae, 0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x18, 0x12, 0x13, 0x02, 0xc2, 0x10, 0xe4, 0xf5} },
+{ 0x0e5a,	16,	{0x0b, 0xf5, 0x13, 0xc2, 0x15, 0xc2, 0x11, 0x90, 0x7f, 0xa1, 0x04, 0xf0, 0x90, 0x7f, 0xd8, 0xe0} },
+{ 0x0e6a,	16,	{0x65, 0x17, 0x60, 0x10, 0x30, 0x11, 0x05, 0xd2, 0x18, 0x12, 0x00, 0x46, 0x90, 0x7f, 0xd8, 0xe0} },
+{ 0x0e7a,	16,	{0xf5, 0x17, 0x80, 0x08, 0x30, 0x11, 0x05, 0xc2, 0x18, 0x12, 0x00, 0x46, 0x30, 0x10, 0x07, 0xc2} },
+{ 0x0e8a,	16,	{0x10, 0x12, 0x09, 0x19, 0x80, 0xd6, 0x30, 0x16, 0xd3, 0xc2, 0x16, 0x12, 0x14, 0x4f, 0x80, 0xcc} },
+{ 0x0e9a,	1,	{0x22} },
+{ 0x0e9b,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x47, 0x02, 0x0e, 0xe2} },
+{ 0x0ea7,	16,	{0x02, 0x0e, 0x0a, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x0eb7,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x0ec7,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x0ed7,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x13, 0x69, 0xe4, 0x7e} },
+{ 0x0ee7,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x0ef7,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x0f07,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x0f17,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x0f27,	16,	{0xe4, 0xfe, 0x75, 0x1d, 0xff, 0x75, 0x1e, 0x19, 0x75, 0x1f, 0x12, 0xab, 0x1d, 0xaa, 0x1e, 0xa9} },
+{ 0x0f37,	16,	{0x1f, 0x90, 0x00, 0x01, 0x12, 0x0c, 0xb8, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0f47,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x0c, 0xf7, 0x85, 0xf0, 0x1b, 0xf5, 0x1c, 0x62, 0x1b} },
+{ 0x0f57,	16,	{0xe5, 0x1b, 0x62, 0x1c, 0xe5, 0x1c, 0x62, 0x1b, 0x29, 0xfd, 0xe5, 0x1b, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0f67,	14,	{0x1d, 0xff, 0xf5, 0x1e, 0x89, 0x1f, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0f75,	1,	{0x22} },
+{ 0x0f76,	2,	{0x8f, 0x1b} },
+{ 0x0f78,	16,	{0xe4, 0xf5, 0x1c, 0x75, 0x1d, 0xff, 0x75, 0x1e, 0x19, 0x75, 0x1f, 0x86, 0xab, 0x1d, 0xaa, 0x1e} },
+{ 0x0f88,	16,	{0xa9, 0x1f, 0x90, 0x00, 0x01, 0x12, 0x0c, 0xb8, 0xb4, 0x03, 0x1d, 0xaf, 0x1c, 0x05, 0x1c, 0xef} },
+{ 0x0f98,	16,	{0xb5, 0x1b, 0x01, 0x22, 0x12, 0x0c, 0x9f, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x0fa8,	14,	{0x1d, 0xff, 0xf5, 0x1e, 0x89, 0x1f, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0fb6,	1,	{0x22} },
+{ 0x0fb7,	16,	{0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e} },
+{ 0x0fc7,	16,	{0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x00, 0x36, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05} },
+{ 0x0fd7,	16,	{0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x13} },
+{ 0x0fe7,	9,	{0xcc, 0x8f, 0x1a, 0xef, 0x42, 0x36, 0x80, 0xca, 0x22} },
+{ 0x0ff0,	16,	{0x8f, 0x1a, 0x05, 0x0d, 0xe5, 0x0d, 0xae, 0x0c, 0x70, 0x02, 0x05, 0x0c, 0x14, 0xf5, 0x82, 0x8e} },
+{ 0x1000,	16,	{0x83, 0xe5, 0x1a, 0xf0, 0x12, 0x13, 0xe4, 0x05, 0x0d, 0xe5, 0x0d, 0xac, 0x0c, 0x70, 0x02, 0x05} },
+{ 0x1010,	16,	{0x0c, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x0a, 0x12, 0x14} },
+{ 0x1020,	9,	{0x37, 0x8f, 0x1a, 0xef, 0x42, 0x37, 0x80, 0xca, 0x22} },
+{ 0x1029,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30} },
+{ 0x1039,	16,	{0x1a, 0x04, 0xc2, 0x1a, 0x80, 0x02, 0xd2, 0x16, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x1049,	14,	{0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1057,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90} },
+{ 0x1067,	16,	{0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0} },
+{ 0x1077,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1081,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2} },
+{ 0x1091,	16,	{0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85} },
+{ 0x10a1,	7,	{0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x10a8,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x10b8,	16,	{0x10, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x10c8,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x10ce,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x10de,	16,	{0x11, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x10ee,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x10f4,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1104,	16,	{0x12, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x1114,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x111a,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x112a,	16,	{0x14, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x113a,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x1140,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1150,	16,	{0x16, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54} },
+{ 0x1160,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x1166,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1176,	16,	{0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x1186,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x118c,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x119c,	16,	{0x08, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x11ac,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x11b2,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x11c2,	16,	{0x09, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x11d2,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x11d8,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x11e8,	16,	{0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x11f8,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x11fe,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x120e,	16,	{0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54} },
+{ 0x121e,	6,	{0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x1224,	16,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0xe5, 0x44, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f} },
+{ 0x1234,	16,	{0x98, 0x74, 0x17, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90} },
+{ 0x1244,	5,	{0xc0, 0x00, 0xed, 0xf0, 0x22} },
+{ 0x1249,	16,	{0x12, 0x13, 0xb4, 0x8f, 0x1a, 0x12, 0x13, 0xb4, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12} },
+{ 0x1259,	16,	{0x12, 0x13, 0xb4, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x13, 0xb4, 0x8f, 0x1b} },
+{ 0x1269,	4,	{0x80, 0xe8, 0xaf, 0x1a} },
+{ 0x126d,	1,	{0x22} },
+{ 0x126e,	16,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0xe5, 0x45, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x7f} },
+{ 0x127e,	16,	{0x98, 0x74, 0x0f, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90} },
+{ 0x128e,	5,	{0xc0, 0x00, 0xed, 0xf0, 0x22} },
+{ 0x1293,	16,	{0x12, 0x14, 0x1f, 0x8f, 0x1a, 0x12, 0x14, 0x1f, 0x8f, 0x1b, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x12} },
+{ 0x12a3,	16,	{0x12, 0x14, 0x1f, 0x8f, 0x1a, 0xe5, 0x1a, 0x65, 0x1b, 0x60, 0x07, 0x12, 0x14, 0x1f, 0x8f, 0x1b} },
+{ 0x12b3,	4,	{0x80, 0xe8, 0xaf, 0x1a} },
+{ 0x12b7,	1,	{0x22} },
+{ 0x12b8,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x12c8,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x12d8,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x12dd,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x53} },
+{ 0x12ed,	16,	{0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82} },
+{ 0x12fd,	5,	{0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1302,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x18, 0x04, 0xe0, 0x44} },
+{ 0x1312,	16,	{0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x13, 0x85, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x1322,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x1327,	16,	{0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3e, 0x54, 0x7f, 0xfd, 0x12, 0x12, 0x24, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1337,	16,	{0x11, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3e, 0x44, 0x80, 0xfd, 0x12, 0x12, 0x24} },
+{ 0x1347,	1,	{0x22} },
+{ 0x1348,	16,	{0xae, 0x07, 0xe4, 0xff, 0xe5, 0x3f, 0x54, 0x7f, 0xfd, 0x12, 0x12, 0x6e, 0x90, 0x7f, 0x98, 0x74} },
+{ 0x1358,	16,	{0x09, 0xf0, 0x90, 0xc0, 0x00, 0xee, 0xf0, 0xe4, 0xe5, 0x3f, 0x44, 0x80, 0xfd, 0x12, 0x12, 0x6e} },
+{ 0x1368,	1,	{0x22} },
+{ 0x1369,	16,	{0x05, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x14, 0x03, 0x00, 0x00, 0xc1, 0x10, 0xc1, 0x16} },
+{ 0x1379,	7,	{0xc1, 0x0f, 0xc1, 0x94, 0x01, 0x0a, 0x00} },
+{ 0x1380,	2,	{0xc1, 0x99} },
+{ 0x1382,	2,	{0xc1, 0x9a} },
+{ 0x1384,	1,	{0x00} },
+{ 0x1385,	16,	{0x8e, 0x18, 0x8f, 0x19, 0xe5, 0x19, 0x15, 0x19, 0xae, 0x18, 0x70, 0x02, 0x15, 0x18, 0x4e, 0x60} },
+{ 0x1395,	7,	{0x05, 0x12, 0x0d, 0xe9, 0x80, 0xee, 0x22} },
+{ 0x139c,	12,	{0x90, 0x7f, 0x98, 0x74, 0x11, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13a8,	12,	{0x90, 0x7f, 0x98, 0x74, 0x12, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13b4,	12,	{0x90, 0x7f, 0x98, 0x74, 0x13, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13c0,	12,	{0x90, 0x7f, 0x98, 0x74, 0x14, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13cc,	12,	{0x90, 0x7f, 0x98, 0x74, 0x15, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13d8,	12,	{0x90, 0x7f, 0x98, 0x74, 0x16, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13e4,	12,	{0x90, 0x7f, 0x98, 0x74, 0x08, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13f0,	12,	{0x90, 0x7f, 0x98, 0x74, 0x09, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x13fc,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x1400,	16,	{0x02, 0x10, 0x81, 0x00, 0x02, 0x12, 0xb8, 0x00, 0x02, 0x10, 0x57, 0x00, 0x02, 0x10, 0x29, 0x00} },
+{ 0x1410,	3,	{0x02, 0x12, 0xdd} },
+{ 0x1413,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0a, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x141f,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0b, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x142b,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0c, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x1437,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0d, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x1443,	12,	{0x90, 0x7f, 0x98, 0x74, 0x0e, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x144f,	10,	{0x12, 0x00, 0x03, 0x12, 0x0d, 0xfa, 0x12, 0x0b, 0x27, 0x22} },
+{ 0x1900,	16,	{0x12, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x10, 0x01, 0x00, 0x00, 0x01, 0x02} },
+{ 0x1910,	16,	{0x00, 0x01, 0x09, 0x02, 0x74, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e} },
+{ 0x1920,	16,	{0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1930,	16,	{0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1940,	16,	{0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1950,	16,	{0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x82, 0x02} },
+{ 0x1960,	16,	{0x40, 0x00, 0x00, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00} },
+{ 0x1970,	16,	{0x00, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x00, 0x07} },
+{ 0x1980,	16,	{0x05, 0x87, 0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00} },
+{ 0x1990,	16,	{0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00} },
+{ 0x19a0,	16,	{0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00} },
+{ 0x19b0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00} },
+{ 0x19c0,	16,	{0x6f, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x19d0,	16,	{0x2e, 0x00, 0x36, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00} },
+{ 0x19e0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00} },
+{ 0x19f0,	16,	{0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00} },
+{ 0x1a00,	10,	{0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/omninet.c linux.18p8/drivers/usb/serial/omninet.c
--- linux.vanilla/drivers/usb/serial/omninet.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/omninet.c	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,356 @@
+/*
+ * USB ZyXEL omni.net LCD PLUS driver
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * Please report both successes and troubles to the author at omninet@kroah.com
+ *
+ * (07/19/2000) gkh
+ *	Added module_init and module_exit functions to handle the fact that this
+ *	driver is a loadable module now.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define isalpha(x) ( ( x > 96 && x < 123) || ( x > 64 && x < 91) || (x > 47 && x < 58) )
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+
+#define ZYXEL_VENDOR_ID		0x0586
+#define ZYXEL_OMNINET_ID	0x1000
+
+/* function prototypes */
+static int  omninet_open		(struct usb_serial_port *port, struct file *filp);
+static void omninet_close		(struct usb_serial_port *port, struct file *filp);
+static void omninet_read_bulk_callback	(struct urb *urb);
+static void omninet_write_bulk_callback	(struct urb *urb);
+static int  omninet_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  omninet_write_room		(struct usb_serial_port *port);
+
+/* All of the device info needed for the omni.net */
+static __u16	zyxel_vendor_id			= ZYXEL_VENDOR_ID;
+static __u16	zyxel_omninet_product_id	= ZYXEL_OMNINET_ID;
+
+struct usb_serial_device_type zyxel_omninet_device = {
+	name:			"ZyXEL - omni.net lcd plus usb",
+	idVendor:		&zyxel_vendor_id,
+	idProduct:		&zyxel_omninet_product_id,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		2,
+	num_ports:		1,
+	open:			omninet_open,
+	close:			omninet_close,
+	write:			omninet_write,
+	write_room:		omninet_write_room,
+	read_bulk_callback:	omninet_read_bulk_callback,
+	write_bulk_callback:	omninet_write_bulk_callback,
+};
+
+
+/* The protocol.
+ *
+ * The omni.net always exchange 64 bytes of data with the host. The first
+ * four bytes are the control header, you can see it in the above structure.
+ *
+ * oh_seq is a sequence number. Don't know if/how it's used.
+ * oh_len is the length of the data bytes in the packet.
+ * oh_xxx Bit-mapped, related to handshaking and status info.
+ *	I normally set it to 0x03 in trasmitted frames.
+ *	7: Active when the TA is in a CONNECTed state.
+ *	6: unknown
+ *	5: handshaking, unknown
+ *	4: handshaking, unknown
+ *	3: unknown, usually 0
+ *	2: unknown, usually 0
+ *	1: handshaking, unknown, usually set to 1 in trasmitted frames
+ *	0: handshaking, unknown, usually set to 1 in trasmitted frames
+ * oh_pad Probably a pad byte.
+ *
+ * After the header you will find data bytes if oh_len was greater than zero.
+ *
+ */
+
+struct omninet_header
+{
+	__u8	oh_seq;
+	__u8	oh_len;
+	__u8	oh_xxx;
+	__u8	oh_pad;
+};
+
+struct omninet_data
+{
+	__u8	od_outseq;	// Sequence number for bulk_out URBs
+};
+
+static int omninet_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial 	*serial = port->serial;
+	struct usb_serial_port 	*wport	= &serial->port[1];
+	struct omninet_data 	*od;
+
+	dbg("omninet_open port %d", port->number);
+
+	if (port->active) {
+		dbg ("device already open");
+		return -EINVAL;
+	}
+	port->active = 1;
+
+	od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
+
+	if( !od )
+	{
+		err("omninet_open: kmalloc(%d) failed.", sizeof(struct omninet_data));
+		return -ENOMEM;
+	}
+
+	port->private = od;
+
+	/* Start reading from the device */
+	if (usb_submit_urb(port->read_urb))
+		dbg("usb_submit_urb(read bulk, %p) failed", port->read_urb);
+
+	wport->tty = port->tty;
+
+	return (0);
+}
+
+static void omninet_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial 	*serial = port->serial;
+	struct usb_serial_port 	*wport 	= &serial->port[1];
+	struct omninet_data 	*od 	= (struct omninet_data *) port->private;
+
+	port->active = 0;
+
+
+	dbg("zyxel_close port %d", port->number);
+
+	usb_unlink_urb (wport->write_urb);
+	usb_unlink_urb (port->read_urb);
+
+	if(od) kfree(od);
+}
+
+
+#define OMNINET_DATAOFFSET	0x04
+#define OMNINET_HEADERLEN	sizeof(struct omninet_header)
+#define OMNINET_BULKOUTSIZE 	(64 - OMNINET_HEADERLEN)
+
+static void omninet_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port 	*port 	= (struct usb_serial_port *)urb->context;
+	struct usb_serial 	*serial = port->serial;
+
+	unsigned char 		*data 	= urb->transfer_buffer;
+	struct omninet_header 	*header = (struct omninet_header *) &data[0];
+
+	int i;
+
+//	dbg("omninet_read_bulk_callback");
+
+	if (port_paranoia_check (port, "omninet_read_bulk_callback")) {
+		return;
+	}
+
+	if (serial_paranoia_check (serial, "omninet_read_bulk_callback")) {
+		return;
+	}
+
+	if (urb->status) {
+		dbg("nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+#ifdef DEBUG
+	if(header->oh_xxx != 0x30)
+	{
+		if (urb->actual_length) {
+			printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len);
+			for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) {
+				printk ("%.2x ", data[i]);
+			}
+			printk ("\n");
+		}
+	}
+#endif
+
+	if (urb->actual_length && header->oh_len)
+	{
+		for (i = 0; i < header->oh_len; i++) {
+			 tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0);
+	  	}
+	  	tty_flip_buffer_push(port->tty);
+	}
+
+	/* Continue trying to always read  */
+	if (usb_submit_urb(urb))
+		dbg("failed resubmitting read urb");
+
+	return;
+}
+
+static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial 	*serial	= port->serial;
+	struct usb_serial_port 	*wport	= &serial->port[1];
+
+	struct omninet_data 	*od 	= (struct omninet_data   *) port->private;
+	struct omninet_header	*header = (struct omninet_header *) wport->write_urb->transfer_buffer;
+/*
+#ifdef DEBUG
+	int i;
+#endif
+*/
+
+//	dbg("omninet_write port %d", port->number);
+
+	if (count == 0) {
+		dbg("write request of 0 bytes");
+		return (0);
+	}
+/*
+#ifdef DEBUG
+	printk (KERN_DEBUG __FILE__ ": omninet_write %d: ", count);
+		for (i = 0; i < count; i++) {
+			if( isalpha(buf[i]) )
+				printk ("%c ", buf[i]);
+			else
+				printk ("%.2x ", buf[i]);
+		}
+		printk ("\n");
+#endif
+*/
+	if (wport->write_urb->status == -EINPROGRESS) {
+		dbg ("already writing");
+		return (0);
+	}
+
+	count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
+
+	if (from_user) {
+		copy_from_user(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
+	}
+	else {
+		memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
+	}
+
+
+	header->oh_seq 	= od->od_outseq++;
+	header->oh_len 	= count;
+	header->oh_xxx  = 0x03;
+	header->oh_pad 	= 0x00;
+
+	/* send the data out the bulk port, always 64 bytes */
+	wport->write_urb->transfer_buffer_length = 64;
+
+	if (usb_submit_urb(wport->write_urb))
+		dbg("usb_submit_urb(write bulk) failed");
+
+//	dbg("omninet_write returns %d", count);
+
+	return (count);
+}
+
+
+static int omninet_write_room (struct usb_serial_port *port)
+{
+	struct usb_serial 	*serial = port->serial;
+	struct usb_serial_port 	*wport 	= &serial->port[1];
+
+	int room = 0; // Default: no room
+
+	if (wport->write_urb->status != -EINPROGRESS)
+		room = wport->bulk_out_size - OMNINET_HEADERLEN;
+
+//	dbg("omninet_write_room returns %d", room);
+
+	return (room);
+}
+
+static void omninet_write_bulk_callback (struct urb *urb)
+{
+/*	struct omninet_header	*header = (struct omninet_header  *) urb->transfer_buffer; */
+	struct usb_serial_port 	*port   = (struct usb_serial_port *) urb->context;
+	struct usb_serial 	*serial;
+	struct tty_struct 	*tty;
+
+//	dbg("omninet_write_bulk_callback, port %0x\n", port);
+
+
+	if (port_paranoia_check (port, "omninet_write_bulk_callback")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "omninet_write_bulk_callback")) {
+		return;
+	}
+
+	if (urb->status) {
+		dbg("nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	tty = port->tty;
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+
+	wake_up_interruptible(&tty->write_wait);
+
+//	dbg("omninet_write_bulk_callback, tty %0x\n", tty);
+
+	return;
+}
+
+
+int omninet_init (void)
+{
+	usb_serial_register (&zyxel_omninet_device);
+	return 0;
+}
+
+
+void omninet_exit (void)
+{
+	usb_serial_deregister (&zyxel_omninet_device);
+}
+
+
+module_init(omninet_init);
+module_exit(omninet_exit);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/usb-serial.h linux.18p8/drivers/usb/serial/usb-serial.h
--- linux.vanilla/drivers/usb/serial/usb-serial.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/usb-serial.h	Fri Sep  8 17:20:08 2000
@@ -0,0 +1,189 @@
+/*
+ * USB Serial Converter driver
+ *
+ *	Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (08/08/2000) gkh
+ *	Added open_count to port structure.
+ *
+ * (07/23/2000) gkh
+ *	Added bulk_out_endpointAddress to port structure.
+ *
+ * (07/19/2000) gkh, pberger, and borchers
+ *	Modifications to allow usb-serial drivers to be modules.
+ *
+ * 
+ */
+
+
+#ifndef __LINUX_USB_SERIAL_H
+#define __LINUX_USB_SERIAL_H
+
+#include <linux/config.h>
+
+#define SERIAL_TTY_MAJOR	188	/* Nice legal number now */
+#define SERIAL_TTY_MINORS	255	/* loads of devices :) */
+
+#define MAX_NUM_PORTS		8	/* The maximum number of ports one device can grab at once */
+
+#define USB_SERIAL_MAGIC	0x6702	/* magic number for usb_serial struct */
+#define USB_SERIAL_PORT_MAGIC	0x7301	/* magic number for usb_serial_port struct */
+
+/* parity check flag */
+#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+
+struct usb_serial_port {
+	int			magic;
+	struct usb_serial	*serial;	/* pointer back to the owner of this port */
+	struct tty_struct *	tty;		/* the coresponding tty for this port */
+	unsigned char		number;
+	char			active;		/* someone has this device open */
+
+	unsigned char *		interrupt_in_buffer;
+	struct urb *		interrupt_in_urb;
+
+	unsigned char *		bulk_in_buffer;
+	struct urb *		read_urb;
+
+	unsigned char *		bulk_out_buffer;
+	int			bulk_out_size;
+	struct urb *		write_urb;
+	__u8			bulk_out_endpointAddress;
+
+	wait_queue_head_t	write_wait;
+
+	struct tq_struct	tqueue;		/* task queue for line discipline waking up */
+	int			open_count;	/* number of times this port has been opened */
+	
+	void *			private;	/* data private to the specific port */
+};
+
+struct usb_serial {
+	int				magic;
+	struct usb_device *		dev;
+	struct usb_serial_device_type *	type;			/* the type of usb serial device this is */
+	struct usb_interface *		interface;		/* the interface for this device */
+	struct tty_driver *		tty_driver;		/* the tty_driver for this device */
+	unsigned char			minor;			/* the starting minor number for this device */
+	unsigned char			num_ports;		/* the number of ports this device has */
+	char				num_interrupt_in;	/* number of interrupt in endpoints we have */
+	char				num_bulk_in;		/* number of bulk in endpoints we have */
+	char				num_bulk_out;		/* number of bulk out endpoints we have */
+	struct usb_serial_port		port[MAX_NUM_PORTS];
+
+	void *			private;		/* data private to the specific driver */
+};
+
+
+#define MUST_HAVE_NOT	0x01
+#define MUST_HAVE	0x02
+#define DONT_CARE	0x03
+
+#define	HAS		0x02
+#define HAS_NOT		0x01
+
+#define NUM_DONT_CARE	(-1)
+
+
+/* This structure defines the individual serial converter. */
+struct usb_serial_device_type {
+	char	*name;
+	__u16	*idVendor;
+	__u16	*idProduct;
+	char	needs_interrupt_in;
+	char	needs_bulk_in;
+	char	needs_bulk_out;
+	char	num_interrupt_in;
+	char	num_bulk_in;
+	char	num_bulk_out;
+	char	num_ports;		/* number of serial ports this device has */
+
+	struct list_head	driver_list;
+	
+	/* function call to make before accepting driver */
+	int (*startup) (struct usb_serial *serial);	/* return 0 to continue initialization, anything else to abort */
+	void (*shutdown) (struct usb_serial *serial);
+
+	/* serial function calls */
+	int  (*open)		(struct usb_serial_port *port, struct file * filp);
+	void (*close)		(struct usb_serial_port *port, struct file * filp);
+	int  (*write)		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+	int  (*write_room)	(struct usb_serial_port *port);
+	int  (*ioctl)		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+	void (*set_termios)	(struct usb_serial_port *port, struct termios * old);
+	void (*break_ctl)	(struct usb_serial_port *port, int break_state);
+	int  (*chars_in_buffer)	(struct usb_serial_port *port);
+	void (*throttle)	(struct usb_serial_port *port);
+	void (*unthrottle)	(struct usb_serial_port *port);
+
+	void (*read_int_callback)(struct urb *urb);
+	void (*read_bulk_callback)(struct urb *urb);
+	void (*write_bulk_callback)(struct urb *urb);
+};
+
+extern int  usb_serial_register(struct usb_serial_device_type *new_device);
+extern void usb_serial_deregister(struct usb_serial_device_type *device);
+
+/* determine if we should include the EzUSB loader functions */
+#if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_WHITEHEAT) || defined(CONFIG_USB_SERIAL_KEYSPAN) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE) || defined(CONFIG_USB_SERIAL_WHITEHEAT_MODULE) || defined(CONFIG_USB_SERIAL_KEYSPAN_MODULE)
+	#define	USES_EZUSB_FUNCTIONS
+	extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
+	extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
+#else
+	#undef 	USES_EZUSB_FUNCTIONS
+#endif
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int serial_paranoia_check (struct usb_serial *serial, const char *function)
+{
+	if (!serial) {
+		dbg("%s - serial == NULL", function);
+		return -1;
+	}
+	if (serial->magic != USB_SERIAL_MAGIC) {
+		dbg("%s - bad magic number for serial", function);
+		return -1;
+	}
+	if (!serial->type) {
+		dbg("%s - serial->type == NULL!", function);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static inline int port_paranoia_check (struct usb_serial_port *port, const char *function)
+{
+	if (!port) {
+		dbg("%s - port == NULL", function);
+		return -1;
+	}
+	if (port->magic != USB_SERIAL_PORT_MAGIC) {
+		dbg("%s - bad magic number for port", function);
+		return -1;
+	}
+	if (!port->serial) {
+		dbg("%s - port->serial == NULL", function);
+		return -1;
+	}
+	if (!port->tty) {
+		dbg("%s - port->tty == NULL", function);
+		return -1;
+	}
+
+	return 0;
+}
+
+#endif	/* ifdef __LINUX_USB_SERIAL_H */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/usbserial.c linux.18p8/drivers/usb/serial/usbserial.c
--- linux.vanilla/drivers/usb/serial/usbserial.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/usbserial.c	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,1366 @@
+/*
+ * USB Serial Converter driver
+ *
+ * Copyright (C) 1999, 2000 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2000 Peter Berger (pberger@brimson.com)
+ * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * This driver was originally based on the ACM driver by Armin Fuerst (which was 
+ * based on a driver by Brad Keryan)
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ * (07/23/2000) gkh
+ *	Added bulk_out_endpointAddress to port structure.
+ *
+ * (07/19/2000) gkh, pberger, and borchers
+ *	Modifications to allow usb-serial drivers to be modules.
+ *
+ * (07/03/2000) gkh
+ *	Added more debugging to serial_ioctl call
+ * 
+ * (06/25/2000) gkh
+ *	Changed generic_write_bulk_callback to not call wake_up_interruptible
+ *	directly, but to have port_softint do it at a safer time.
+ *
+ * (06/23/2000) gkh
+ *	Cleaned up debugging statements in a quest to find UHCI timeout bug.
+ *
+ * (05/22/2000) gkh
+ *	Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be 
+ *	removed from the individual device source files.
+ *
+ * (05/03/2000) gkh
+ *	Added the Digi Acceleport driver from Al Borchers and Peter Berger.
+ * 
+ * (05/02/2000) gkh
+ *	Changed devfs and tty register code to work properly now. This was based on
+ *	the ACM driver changes by Vojtech Pavlik.
+ *
+ * (04/27/2000) Ryan VanderBijl
+ * 	Put calls to *_paranoia_checks into one function.
+ * 
+ * (04/23/2000) gkh
+ *	Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
+ *	Moved when the startup code printed out the devices that are supported.
+ *
+ * (04/19/2000) gkh
+ *	Added driver for ZyXEL omni.net lcd plus ISDN TA
+ *	Made startup info message specify which drivers were compiled in.
+ *
+ * (04/03/2000) gkh
+ *	Changed the probe process to remove the module unload races.
+ *	Changed where the tty layer gets initialized to have devfs work nicer.
+ *	Added initial devfs support.
+ *
+ * (03/26/2000) gkh
+ *	Split driver up into device specific pieces.
+ * 
+ * (03/19/2000) gkh
+ *	Fixed oops that could happen when device was removed while a program
+ *	was talking to the device.
+ *	Removed the static urbs and now all urbs are created and destroyed
+ *	dynamically.
+ *	Reworked the internal interface. Now everything is based on the 
+ *	usb_serial_port structure instead of the larger usb_serial structure.
+ *	This fixes the bug that a multiport device could not have more than
+ *	one port open at one time.
+ *
+ * (03/17/2000) gkh
+ *	Added config option for debugging messages.
+ *	Added patch for keyspan pda from Brian Warner.
+ *
+ * (03/06/2000) gkh
+ *	Added the keyspan pda code from Brian Warner <warner@lothar.com>
+ *	Moved a bunch of the port specific stuff into its own structure. This
+ *	is in anticipation of the true multiport devices (there's a bug if you
+ *	try to access more than one port of any multiport device right now)
+ *
+ * (02/21/2000) gkh
+ *	Made it so that any serial devices only have to specify which functions
+ *	they want to overload from the generic function calls (great, 
+ *	inheritance in C, in a driver, just what I wanted...)
+ *	Added support for set_termios and ioctl function calls. No drivers take
+ *	advantage of this yet.
+ *	Removed the #ifdef MODULE, now there is no module specific code.
+ *	Cleaned up a few comments in usb-serial.h that were wrong (thanks again
+ *	to Miles Lott).
+ *	Small fix to get_free_serial.
+ *
+ * (02/14/2000) gkh
+ *	Removed the Belkin and Peracom functionality from the driver due to
+ *	the lack of support from the vendor, and me not wanting people to 
+ *	accidenatly buy the device, expecting it to work with Linux.
+ *	Added read_bulk_callback and write_bulk_callback to the type structure
+ *	for the needs of the FTDI and WhiteHEAT driver.
+ *	Changed all reverences to FTDI to FTDI_SIO at the request of Bill
+ *	Ryder.
+ *	Changed the output urb size back to the max endpoint size to make
+ *	the ftdi_sio driver have it easier, and due to the fact that it didn't
+ *	really increase the speed any.
+ *
+ * (02/11/2000) gkh
+ *	Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
+ *	patch from Miles Lott (milos@insync.net).
+ *	Fixed bug with not restoring the minor range that a device grabs, if
+ *	the startup function fails (thanks Miles for finding this).
+ *
+ * (02/05/2000) gkh
+ *	Added initial framework for the Keyspan PDA serial converter so that
+ *	Brian Warner has a place to put his code.
+ *	Made the ezusb specific functions generic enough that different
+ *	devices can use them (whiteheat and keyspan_pda both need them).
+ *	Split out a whole bunch of structure and other stuff to a seperate
+ *	usb-serial.h file.
+ *	Made the Visor connection messages a little more understandable, now
+ *	that Miles Lott (milos@insync.net) has gotten the Generic channel to
+ *	work. Also made them always show up in the log file.
+ * 
+ * (01/25/2000) gkh
+ *	Added initial framework for FTDI serial converter so that Bill Ryder
+ *	has a place to put his code.
+ *	Added the vendor specific info from Handspring. Now we can print out
+ *	informational debug messages as well as understand what is happening.
+ *
+ * (01/23/2000) gkh
+ *	Fixed problem of crash when trying to open a port that didn't have a
+ *	device assigned to it. Made the minor node finding a little smarter,
+ *	now it looks to find a continous space for the new device.
+ *
+ * (01/21/2000) gkh
+ *	Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
+ *	Fixed get_serial_by_minor which was all messed up for multi port 
+ *	devices. Fixed multi port problem for generic devices. Now the number
+ *	of ports is determined by the number of bulk out endpoints for the
+ *	generic device.
+ *
+ * (01/19/2000) gkh
+ *	Removed lots of cruft that was around from the old (pre urb) driver 
+ *	interface.
+ *	Made the serial_table dynamic. This should save lots of memory when
+ *	the number of minor nodes goes up to 256.
+ *	Added initial support for devices that have more than one port. 
+ *	Added more debugging comments for the Visor, and added a needed 
+ *	set_configuration call.
+ *
+ * (01/17/2000) gkh
+ *	Fixed the WhiteHEAT firmware (my processing tool had a bug)
+ *	and added new debug loader firmware for it.
+ *	Removed the put_char function as it isn't really needed.
+ *	Added visor startup commands as found by the Win98 dump.
+ * 
+ * (01/13/2000) gkh
+ *	Fixed the vendor id for the generic driver to the one I meant it to be.
+ *
+ * (01/12/2000) gkh
+ *	Forget the version numbering...that's pretty useless...
+ *	Made the driver able to be compiled so that the user can select which
+ *	converter they want to use. This allows people who only want the Visor
+ *	support to not pay the memory size price of the WhiteHEAT.
+ *	Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
+ *	grabbed the root hub. Not good.
+ * 
+ * version 0.4.0 (01/10/2000) gkh
+ *	Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
+ *	device. Added startup function to allow firmware to be downloaded to
+ *	a device if it needs to be.
+ *	Added firmware download logic to the WhiteHEAT device.
+ *	Started to add #defines to split up the different drivers for potential
+ *	configuration option.
+ *	
+ * version 0.3.1 (12/30/99) gkh
+ *      Fixed problems with urb for bulk out.
+ *      Added initial support for multiple sets of endpoints. This enables
+ *      the Handspring Visor to be attached successfully. Only the first
+ *      bulk in / bulk out endpoint pair is being used right now.
+ *
+ * version 0.3.0 (12/27/99) gkh
+ *	Added initial support for the Handspring Visor based on a patch from
+ *	Miles Lott (milos@sneety.insync.net)
+ *	Cleaned up the code a bunch and converted over to using urbs only.
+ *
+ * version 0.2.3 (12/21/99) gkh
+ *	Added initial support for the Connect Tech WhiteHEAT converter.
+ *	Incremented the number of ports in expectation of getting the
+ *	WhiteHEAT to work properly (4 ports per connection).
+ *	Added notification on insertion and removal of what port the
+ *	device is/was connected to (and what kind of device it was).
+ *
+ * version 0.2.2 (12/16/99) gkh
+ *	Changed major number to the new allocated number. We're legal now!
+ *
+ * version 0.2.1 (12/14/99) gkh
+ *	Fixed bug that happens when device node is opened when there isn't a
+ *	device attached to it. Thanks to marek@webdesign.no for noticing this.
+ *
+ * version 0.2.0 (11/10/99) gkh
+ *	Split up internals to make it easier to add different types of serial 
+ *	converters to the code.
+ *	Added a "generic" driver that gets it's vendor and product id
+ *	from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
+ *	for the idea and sample code (from the usb scanner driver.)
+ *	Cleared up any licensing questions by releasing it under the GNU GPL.
+ *
+ * version 0.1.2 (10/25/99) gkh
+ * 	Fixed bug in detecting device.
+ *
+ * version 0.1.1 (10/05/99) gkh
+ * 	Changed the major number to not conflict with anything else.
+ *
+ * version 0.1 (09/28/99) gkh
+ * 	Can recognize the two different devices and start up a read from
+ *	device when asked to. Writes also work. No control signals yet, this
+ *	all is vendor specific data (i.e. no spec), also no control for
+ *	different baud rates or other bit settings.
+ *	Currently we are using the same devid as the acm driver. This needs
+ *	to change.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+/* Module information */
+MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/");
+MODULE_DESCRIPTION("USB Serial Driver");
+
+#include "usb-serial.h"
+
+#define MAX(a,b)	(((a)>(b))?(a):(b))
+
+/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
+/* need to always compile these in, as some of the other devices use these functions as their own. */
+/* if a driver does not provide a function pointer, the generic function will be called. */
+static int  generic_open		(struct usb_serial_port *port, struct file *filp);
+static void generic_close		(struct usb_serial_port *port, struct file *filp);
+static int  generic_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  generic_write_room		(struct usb_serial_port *port);
+static int  generic_chars_in_buffer	(struct usb_serial_port *port);
+static void generic_read_bulk_callback	(struct urb *urb);
+static void generic_write_bulk_callback	(struct urb *urb);
+
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+static __u16	vendor	= 0x05f9;
+static __u16	product	= 0xffff;
+MODULE_PARM(vendor, "i");
+MODULE_PARM_DESC(vendor, "User specified USB idVendor");
+
+MODULE_PARM(product, "i");
+MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+/* All of the device info needed for the Generic Serial Converter */
+static struct usb_serial_device_type generic_device = {
+	name:			"Generic",
+	idVendor:		&vendor,		/* use the user specified vendor id */
+	idProduct:		&product,		/* use the user specified product id */
+	needs_interrupt_in:	DONT_CARE,		/* don't have to have an interrupt in endpoint */
+	needs_bulk_in:		DONT_CARE,		/* don't have to have a bulk in endpoint */
+	needs_bulk_out:		DONT_CARE,		/* don't have to have a bulk out endpoint */
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+};
+#endif
+
+
+/* local function prototypes */
+static int  serial_open (struct tty_struct *tty, struct file * filp);
+static void serial_close (struct tty_struct *tty, struct file * filp);
+static int  serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
+static int  serial_write_room (struct tty_struct *tty);
+static int  serial_chars_in_buffer (struct tty_struct *tty);
+static void serial_throttle (struct tty_struct * tty);
+static void serial_unthrottle (struct tty_struct * tty);
+static int  serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg);
+static void serial_set_termios (struct tty_struct *tty, struct termios * old);
+
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum);
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr);
+
+static struct usb_driver usb_serial_driver = {
+	name:		"serial",
+	probe:		usb_serial_probe,
+	disconnect:	usb_serial_disconnect,
+};
+
+static int			serial_refcount;
+static struct tty_driver	serial_tty_driver;
+static struct tty_struct *	serial_tty[SERIAL_TTY_MINORS];
+static struct termios *		serial_termios[SERIAL_TTY_MINORS];
+static struct termios *		serial_termios_locked[SERIAL_TTY_MINORS];
+static struct usb_serial	*serial_table[SERIAL_TTY_MINORS] = {NULL, };
+
+LIST_HEAD(usb_serial_driver_list);
+
+
+static inline struct usb_serial* get_usb_serial (struct usb_serial_port *port, const char *function) 
+{ 
+	/* if no port was specified, or it fails a paranoia check */
+	if (!port || 
+		port_paranoia_check (port, function) ||
+		serial_paranoia_check (port->serial, function)) {
+		/* then say that we dont have a valid usb_serial thing, which will
+		 * end up genrating -ENODEV return values */ 
+		return NULL;
+	}
+
+	return port->serial;
+}
+
+
+static struct usb_serial *get_serial_by_minor (int minor)
+{
+	return serial_table[minor];
+}
+
+
+static struct usb_serial *get_free_serial (int num_ports, int *minor)
+{
+	struct usb_serial *serial = NULL;
+	int i, j;
+	int good_spot;
+
+	dbg(__FUNCTION__ " %d", num_ports);
+
+	*minor = 0;
+	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+		if (serial_table[i])
+			continue;
+
+		good_spot = 1;
+		for (j = 1; j <= num_ports-1; ++j)
+			if (serial_table[i+j])
+				good_spot = 0;
+		if (good_spot == 0)
+			continue;
+			
+		if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
+			err(__FUNCTION__ " - Out of memory");
+			return NULL;
+		}
+		memset(serial, 0, sizeof(struct usb_serial));
+		serial->magic = USB_SERIAL_MAGIC;
+		serial_table[i] = serial;
+		*minor = i;
+		dbg(__FUNCTION__ " - minor base = %d", *minor);
+		for (i = *minor+1; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
+			serial_table[i] = serial;
+		return serial;
+	}
+	return NULL;
+}
+
+
+static void return_serial (struct usb_serial *serial)
+{
+	int i;
+
+	dbg(__FUNCTION__);
+
+	if (serial == NULL)
+		return;
+
+	for (i = 0; i < serial->num_ports; ++i) {
+		serial_table[serial->minor + i] = NULL;
+	}
+
+	return;
+}
+
+
+#ifdef USES_EZUSB_FUNCTIONS
+/* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */
+#define CPUCS_REG    0x7F92
+
+int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest)
+{
+	int result;
+	unsigned char *transfer_buffer =  kmalloc (length, GFP_KERNEL);
+
+//	dbg("ezusb_writememory %x, %d", address, length);
+
+	if (!transfer_buffer) {
+		err(__FUNCTION__ " - kmalloc(%d) failed.", length);
+		return -ENOMEM;
+	}
+	memcpy (transfer_buffer, data, length);
+	result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300);
+	kfree (transfer_buffer);
+	return result;
+}
+
+
+int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
+{
+	int	response;
+	dbg(__FUNCTION__ " - %d", reset_bit);
+	response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0);
+	if (response < 0) {
+		err(__FUNCTION__ "- %d failed", reset_bit);
+	}
+	return response;
+}
+
+#endif	/* USES_EZUSB_FUNCTIONS */
+
+
+/*****************************************************************************
+ * Driver tty interface functions
+ *****************************************************************************/
+static int serial_open (struct tty_struct *tty, struct file * filp)
+{
+	struct usb_serial *serial;
+	struct usb_serial_port *port;
+	int portNumber;
+	
+	dbg(__FUNCTION__);
+
+	/* initialize the pointer incase something fails */
+	tty->driver_data = NULL;
+
+	/* get the serial object associated with this tty pointer */
+	serial = get_serial_by_minor (MINOR(tty->device));
+
+	if (serial_paranoia_check (serial, __FUNCTION__)) {
+		return -ENODEV;
+	}
+
+	/* set up our port structure making the tty driver remember our port object, and us it */
+	portNumber = MINOR(tty->device) - serial->minor;
+	port = &serial->port[portNumber];
+	tty->driver_data = port;
+	port->tty = tty;
+	 
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->open) {
+		return (serial->type->open(port, filp));
+	} else {
+		return (generic_open(port, filp));
+	}
+}
+
+
+static void serial_close(struct tty_struct *tty, struct file * filp)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	if (!serial) {
+		return;
+	}
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (!port->active) {
+		dbg (__FUNCTION__ " - port not opened");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->close) {
+		serial->type->close(port, filp);
+	} else {
+		generic_close(port, filp);
+	}
+}	
+
+
+static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	
+	if (!serial) {
+		return -ENODEV;
+	}
+	
+	dbg(__FUNCTION__ " - port %d, %d byte(s)", port->number, count);
+
+	if (!port->active) {
+		dbg (__FUNCTION__ " - port not opened");
+		return -EINVAL;
+	}
+	
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->write) {
+		return (serial->type->write(port, from_user, buf, count));
+	} else {
+		return (generic_write(port, from_user, buf, count));
+	}
+}
+
+
+static int serial_write_room (struct tty_struct *tty) 
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	if (!serial) {
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (!port->active) {
+		dbg (__FUNCTION__ " - port not open");
+		return -EINVAL;
+	}
+
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->write_room) {
+		return (serial->type->write_room(port));
+	} else {
+		return (generic_write_room(port));
+	}
+}
+
+
+static int serial_chars_in_buffer (struct tty_struct *tty) 
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	if (!serial) {
+		return -ENODEV;
+	}
+
+	if (!port->active) {
+		dbg (__FUNCTION__ " - port not open");
+		return -EINVAL;
+	}
+
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->chars_in_buffer) {
+		return (serial->type->chars_in_buffer(port));
+	} else {
+		return (generic_chars_in_buffer(port));
+	}
+}
+
+
+static void serial_throttle (struct tty_struct * tty)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	if (!serial) {
+		return;
+	}
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (!port->active) {
+		dbg (__FUNCTION__ " - port not open");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function */
+	if (serial->type->throttle) {
+		serial->type->throttle(port);
+	}
+
+	return;
+}
+
+
+static void serial_unthrottle (struct tty_struct * tty)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	if (!serial) {
+		return;
+	}
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (!port->active) {
+		dbg (__FUNCTION__ " - port not open");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function */
+	if (serial->type->unthrottle) {
+		serial->type->unthrottle(port);
+	}
+
+	return;
+}
+
+
+static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	if (!serial) {
+		return -ENODEV;
+	}
+
+	dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+
+	if (!port->active) {
+		dbg (__FUNCTION__ " - port not open");
+		return -ENODEV;
+	}
+
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->ioctl) {
+		return (serial->type->ioctl(port, file, cmd, arg));
+	} else {
+		return -ENOIOCTLCMD;
+	}
+}
+
+
+static void serial_set_termios (struct tty_struct *tty, struct termios * old)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	if (!serial) {
+		return;
+	}
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (!port->active) {
+		dbg (__FUNCTION__ " - port not open");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->set_termios) {
+		serial->type->set_termios(port, old);
+	}
+	
+	return;
+}
+
+
+static void serial_break (struct tty_struct *tty, int break_state)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	if (!serial) {
+		return;
+	}
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (!port->active) {
+		dbg (__FUNCTION__ " - port not open");
+		return;
+	}
+
+	/* pass on to the driver specific version of this function if it is
+           available */
+	if (serial->type->break_ctl) {
+		serial->type->break_ctl(port, break_state);
+	}
+}
+
+
+
+/*****************************************************************************
+ * generic devices specific driver functions
+ *****************************************************************************/
+static int generic_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (port->active) {
+		dbg (__FUNCTION__ " - device already open");
+		return -EINVAL;
+	}
+	port->active = 1;
+ 
+	/* if we have a bulk interrupt, start reading from it */
+	if (serial->num_bulk_in) {
+		/*Start reading from the device*/
+		if (usb_submit_urb(port->read_urb))
+			dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+	}
+
+	return (0);
+}
+
+
+static void generic_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial *serial = port->serial;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	/* shutdown any bulk reads that might be going on */
+	if (serial->num_bulk_out) {
+		usb_unlink_urb (port->write_urb);
+	}
+	if (serial->num_bulk_in) {
+		usb_unlink_urb (port->read_urb);
+	}
+
+	port->active = 0;
+}
+
+
+static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (count == 0) {
+		dbg(__FUNCTION__ " - write request of 0 bytes");
+		return (0);
+	}
+
+	/* only do something if we have a bulk out endpoint */
+	if (serial->num_bulk_out) {
+		if (port->write_urb->status == -EINPROGRESS) {
+			dbg (__FUNCTION__ " - already writing");
+			return (0);
+		}
+
+		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+#ifdef DEBUG
+		{
+			int i;
+			printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
+			for (i = 0; i < count; ++i) {
+				printk ("%.2x ", buf[i]);
+			}
+			printk ("\n");
+		}
+#endif
+
+		if (from_user) {
+			copy_from_user(port->write_urb->transfer_buffer, buf, count);
+		}
+		else {
+			memcpy (port->write_urb->transfer_buffer, buf, count);
+		}  
+
+		/* send the data out the bulk port */
+		port->write_urb->transfer_buffer_length = count;
+
+		if (usb_submit_urb(port->write_urb))
+			dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed");
+
+		return (count);
+	}
+	
+	/* no bulk out, so return 0 bytes written */
+	return (0);
+} 
+
+
+static int generic_write_room (struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+	int room = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (serial->num_bulk_out)
+		if (port->write_urb->status != -EINPROGRESS)
+			room = port->bulk_out_size;
+	
+	dbg(__FUNCTION__ " - returns %d", room);
+	return (room);
+}
+
+
+static int generic_chars_in_buffer (struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+	int chars = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (serial->num_bulk_out)
+		if (port->write_urb->status == -EINPROGRESS)
+			chars = port->write_urb->transfer_buffer_length;
+
+	dbg (__FUNCTION__ " - returns %d", chars);
+	return (chars);
+}
+
+
+static void generic_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int i;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+#ifdef DEBUG
+	if (urb->actual_length) {
+		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length);
+		for (i = 0; i < urb->actual_length; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+	tty = port->tty;
+	if (urb->actual_length) {
+		for (i = 0; i < urb->actual_length ; ++i) {
+			 tty_insert_flip_char(tty, data[i], 0);
+	  	}
+	  	tty_flip_buffer_push(tty);
+	}
+
+	/* Continue trying to always read  */
+	if (usb_submit_urb(urb))
+		dbg(__FUNCTION__ " - failed resubmitting read urb");
+
+	return;
+}
+
+
+static void generic_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	queue_task(&port->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	
+	return;
+}
+
+
+static void port_softint(void *private)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)private;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	struct tty_struct *tty;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (!serial) {
+		return;
+	}
+ 	
+	tty = port->tty;
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+		dbg(__FUNCTION__ " - write wakeup call.");
+		(tty->ldisc.write_wakeup)(tty);
+	}
+
+	wake_up_interruptible(&tty->write_wait);
+}
+
+
+
+static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_serial *serial = NULL;
+	struct usb_serial_port *port;
+	struct usb_interface *interface;
+	struct usb_interface_descriptor *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
+	struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
+	struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
+	struct usb_serial_device_type *type = NULL;
+	struct list_head *tmp;
+	int found;
+	int minor;
+	int buffer_size;
+	int i;
+	char interrupt_pipe;
+	char bulk_in_pipe;
+	char bulk_out_pipe;
+	int num_interrupt_in = 0;
+	int num_bulk_in = 0;
+	int num_bulk_out = 0;
+	int num_ports;
+	int max_endpoints;
+
+	
+	/* loop through our list of known serial converters, and see if this
+	   device matches. */
+	found = 0;
+	list_for_each (tmp, &usb_serial_driver_list) {
+		type = list_entry(tmp, struct usb_serial_device_type, driver_list);
+		dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", 
+			type->name, *(type->idVendor), *(type->idProduct));
+
+		/* look at the device descriptor */
+		if ((dev->descriptor.idVendor == *(type->idVendor)) &&
+		    (dev->descriptor.idProduct == *(type->idProduct))) {
+			dbg("descriptor matches");
+			found = 1;
+			break;
+		}
+	}
+	if (!found) {
+		/* no match */
+		dbg("none matched");
+		return(NULL);
+	}
+	
+	/* descriptor matches, let's find the endpoints needed */
+	interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
+			
+	/* check out the endpoints */
+	interface = &dev->actconfig->interface[ifnum];
+	iface_desc = &interface->altsetting[0];
+	for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i];
+		
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk in endpoint */
+			dbg("found bulk in");
+			bulk_in_pipe = HAS;
+			bulk_in_endpoint[num_bulk_in] = endpoint;
+			++num_bulk_in;
+		}
+
+		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+		    ((endpoint->bmAttributes & 3) == 0x02)) {
+			/* we found a bulk out endpoint */
+			dbg("found bulk out");
+			bulk_out_pipe = HAS;
+			bulk_out_endpoint[num_bulk_out] = endpoint;
+			++num_bulk_out;
+		}
+		
+		if ((endpoint->bEndpointAddress & 0x80) &&
+		    ((endpoint->bmAttributes & 3) == 0x03)) {
+			/* we found a interrupt in endpoint */
+			dbg("found interrupt in");
+			interrupt_pipe = HAS;
+			interrupt_in_endpoint[num_interrupt_in] = endpoint;
+			++num_interrupt_in;
+		}
+	}
+	
+	/* verify that we found all of the endpoints that we need */
+	if (!((interrupt_pipe & type->needs_interrupt_in) &&
+	      (bulk_in_pipe & type->needs_bulk_in) &&
+	      (bulk_out_pipe & type->needs_bulk_out))) {
+		/* nope, they don't match what we expected */
+		info("descriptors matched, but endpoints did not");
+		return NULL;
+	}
+
+	/* found all that we need */
+	MOD_INC_USE_COUNT;
+	info("%s converter detected", type->name);
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+	if (type == &generic_device) {
+		num_ports = num_bulk_out;
+		if (num_ports == 0) {
+			err("Generic device with no bulk out, not allowed.");
+			MOD_DEC_USE_COUNT;
+			return NULL;
+		}
+	} else
+#endif
+		num_ports = type->num_ports;
+
+	serial = get_free_serial (num_ports, &minor);
+	if (serial == NULL) {
+		err("No more free serial devices");
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+	
+	serial->dev = dev;
+	serial->type = type;
+	serial->interface = interface;
+	serial->minor = minor;
+	serial->num_ports = num_ports;
+	serial->num_bulk_in = num_bulk_in;
+	serial->num_bulk_out = num_bulk_out;
+	serial->num_interrupt_in = num_interrupt_in;
+
+	/* if this device type has a startup function, call it */
+	if (type->startup) {
+		if (type->startup (serial)) {
+			goto probe_error;
+		}
+	}
+
+	/* set up the endpoint information */
+	for (i = 0; i < num_bulk_in; ++i) {
+		endpoint = bulk_in_endpoint[i];
+		port = &serial->port[i];
+		port->read_urb = usb_alloc_urb (0);
+		if (!port->read_urb) {
+			err("No free urbs available");
+			goto probe_error;
+		}
+		buffer_size = endpoint->wMaxPacketSize;
+		port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!port->bulk_in_buffer) {
+			err("Couldn't allocate bulk_in_buffer");
+			goto probe_error;
+		}
+		FILL_BULK_URB(port->read_urb, dev, 
+			      usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+			      port->bulk_in_buffer, buffer_size, 
+			      ((serial->type->read_bulk_callback) ?
+			       serial->type->read_bulk_callback :
+			       generic_read_bulk_callback), 
+			      port);
+	}
+
+	for (i = 0; i < num_bulk_out; ++i) {
+		endpoint = bulk_out_endpoint[i];
+		port = &serial->port[i];
+		port->write_urb = usb_alloc_urb(0);
+		if (!port->write_urb) {
+			err("No free urbs available");
+			goto probe_error;
+		}
+		buffer_size = endpoint->wMaxPacketSize;
+		port->bulk_out_size = buffer_size;
+		port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
+		port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!port->bulk_out_buffer) {
+			err("Couldn't allocate bulk_out_buffer");
+			goto probe_error;
+		}
+		FILL_BULK_URB(port->write_urb, dev, 
+			      usb_sndbulkpipe(dev, endpoint->bEndpointAddress),
+			      port->bulk_out_buffer, buffer_size,
+			      ((serial->type->write_bulk_callback) ? 
+			       serial->type->write_bulk_callback : 
+			       generic_write_bulk_callback), 
+			      port);
+	}
+
+	for (i = 0; i < num_interrupt_in; ++i) {
+		endpoint = interrupt_in_endpoint[i];
+		port = &serial->port[i];
+		port->interrupt_in_urb = usb_alloc_urb(0);
+		if (!port->interrupt_in_urb) {
+			err("No free urbs available");
+			goto probe_error;
+		}
+		buffer_size = endpoint->wMaxPacketSize;
+		port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!port->interrupt_in_buffer) {
+			err("Couldn't allocate interrupt_in_buffer");
+			goto probe_error;
+		}
+		FILL_INT_URB(port->interrupt_in_urb, dev, 
+			     usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+			     port->interrupt_in_buffer, buffer_size, 
+			     serial->type->read_int_callback,
+			     port, 
+			     endpoint->bInterval);
+	}
+
+	/* initialize some parts of the port structures */
+	/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
+	max_endpoints = MAX(num_bulk_in, num_bulk_out);
+	max_endpoints = MAX(max_endpoints, num_interrupt_in);
+	for (i = 0; i < max_endpoints; ++i) {
+		port = &serial->port[i];
+		port->number = i + serial->minor;
+		port->serial = serial;
+		port->magic = USB_SERIAL_PORT_MAGIC;
+		port->tqueue.routine = port_softint;
+		port->tqueue.data = port;
+	}
+	
+	/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
+	for (i = 0; i < serial->num_ports; ++i) {
+		tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number);
+		info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", 
+		     type->name, serial->port[i].number, serial->port[i].number);
+	}
+	
+	return serial; /* success */
+
+
+probe_error:
+	for (i = 0; i < num_bulk_in; ++i) {
+		port = &serial->port[i];
+		if (port->read_urb)
+			usb_free_urb (port->read_urb);
+		if (port->bulk_in_buffer)
+			kfree (port->bulk_in_buffer);
+	}
+	for (i = 0; i < num_bulk_out; ++i) {
+		port = &serial->port[i];
+		if (port->write_urb)
+			usb_free_urb (port->write_urb);
+		if (port->bulk_out_buffer)
+			kfree (port->bulk_out_buffer);
+	}
+	for (i = 0; i < num_interrupt_in; ++i) {
+		port = &serial->port[i];
+		if (port->interrupt_in_urb)
+			usb_free_urb (port->interrupt_in_urb);
+		if (port->interrupt_in_buffer)
+			kfree (port->interrupt_in_buffer);
+	}
+		
+	/* return the minor range that this device had */
+	return_serial (serial);
+
+	/* free up any memory that we allocated */
+	kfree (serial);
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+
+static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_serial *serial = (struct usb_serial *) ptr;
+	struct usb_serial_port *port;
+	int i;
+
+	if (serial) {
+		/* fail all future close/read/write/ioctl/etc calls */
+		for (i = 0; i < serial->num_ports; ++i) {
+			if (serial->port[i].tty != NULL)
+				serial->port[i].tty->driver_data = NULL;
+		}
+
+		if (serial->type->shutdown)
+			serial->type->shutdown(serial);
+
+		for (i = 0; i < serial->num_ports; ++i)
+			serial->port[i].active = 0;
+
+		for (i = 0; i < serial->num_bulk_in; ++i) {
+			port = &serial->port[i];
+			if (port->read_urb) {
+				usb_unlink_urb (port->read_urb);
+				usb_free_urb (port->read_urb);
+			}
+			if (port->bulk_in_buffer)
+				kfree (port->bulk_in_buffer);
+		}
+		for (i = 0; i < serial->num_bulk_out; ++i) {
+			port = &serial->port[i];
+			if (port->write_urb) {
+				usb_unlink_urb (port->write_urb);
+				usb_free_urb (port->write_urb);
+			}
+			if (port->bulk_out_buffer)
+				kfree (port->bulk_out_buffer);
+		}
+		for (i = 0; i < serial->num_interrupt_in; ++i) {
+			port = &serial->port[i];
+			if (port->interrupt_in_urb) {
+				usb_unlink_urb (port->interrupt_in_urb);
+				usb_free_urb (port->interrupt_in_urb);
+			}
+			if (port->interrupt_in_buffer)
+				kfree (port->interrupt_in_buffer);
+		}
+
+		for (i = 0; i < serial->num_ports; ++i) {
+			tty_unregister_devfs (&serial_tty_driver, serial->port[i].number);
+			info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->port[i].number);
+		}
+
+		/* return the minor range that this device had */
+		return_serial (serial);
+
+		/* free up any memory that we allocated */
+		kfree (serial);
+
+	} else {
+		info("device disconnected");
+	}
+	
+	MOD_DEC_USE_COUNT;
+}
+
+
+static struct tty_driver serial_tty_driver = {
+	magic:			TTY_DRIVER_MAGIC,
+	driver_name:		"usb-serial",
+	name:			"usb/tts/%d",
+	major:			SERIAL_TTY_MAJOR,
+	minor_start:		0,
+	num:			SERIAL_TTY_MINORS,
+	type:			TTY_DRIVER_TYPE_SERIAL,
+	subtype:		SERIAL_TYPE_NORMAL,
+	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+	
+	refcount:		&serial_refcount,
+	table:			serial_tty,
+	termios:		serial_termios,
+	termios_locked:		serial_termios_locked,
+	
+	open:			serial_open,
+	close:			serial_close,
+	write:			serial_write,
+	write_room:		serial_write_room,
+	ioctl:			serial_ioctl,
+	set_termios:		serial_set_termios,
+	throttle:		serial_throttle,
+	unthrottle:		serial_unthrottle,
+	break_ctl:		serial_break,
+	chars_in_buffer:	serial_chars_in_buffer,
+};
+
+
+int usb_serial_init(void)
+{
+	int i;
+	int result;
+
+	/* Initalize our global data */
+	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
+		serial_table[i] = NULL;
+	}
+
+	/* register the tty driver */
+	serial_tty_driver.init_termios          = tty_std_termios;
+	serial_tty_driver.init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	if (tty_register_driver (&serial_tty_driver)) {
+		err(__FUNCTION__ " - failed to register tty driver");
+		return -1;
+	}
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+	/* register our generic driver with ourselves */
+	usb_serial_register (&generic_device);
+#endif
+	
+	/* register the USB driver */
+	result = usb_register(&usb_serial_driver);
+	if (result < 0) {
+		tty_unregister_driver(&serial_tty_driver);
+		err("usb_register failed for the usb-serial driver. Error number %d", result);
+		return -1;
+	}
+	
+	
+	return 0;
+}
+
+
+void usb_serial_exit(void)
+{
+
+#ifdef CONFIG_USB_SERIAL_GENERIC
+	/* remove our generic driver */
+	usb_serial_deregister (&generic_device);
+#endif
+	
+	usb_deregister(&usb_serial_driver);
+	tty_unregister_driver(&serial_tty_driver);
+}
+
+
+module_init(usb_serial_init);
+module_exit(usb_serial_exit);
+
+
+int usb_serial_register(struct usb_serial_device_type *new_device)
+{
+	/* Add this device to our list of devices */
+	list_add(&new_device->driver_list, &usb_serial_driver_list);
+
+	info ("USB Serial support registered for %s", new_device->name);
+
+	usb_scan_devices();
+
+	return 0;
+}
+
+
+void usb_serial_deregister(struct usb_serial_device_type *device)
+{
+	struct usb_serial *serial;
+	int i;
+
+	info("USB Serial deregistering driver %s", device->name);
+
+	/* clear out the serial_table if the device is attached to a port */
+	for(i = 0; i < SERIAL_TTY_MINORS; ++i) {
+		serial = serial_table[i];
+		if ((serial != NULL) && (serial->type == device)) {
+			usb_driver_release_interface (&usb_serial_driver, serial->interface);
+			usb_serial_disconnect (NULL, serial);
+		}
+	}
+
+	list_del(&device->driver_list);
+}
+
+
+
+/* If the usb-serial core is build into the core, the usb-serial drivers
+   need these symbols to load properly as modules. */
+EXPORT_SYMBOL(usb_serial_register);
+EXPORT_SYMBOL(usb_serial_deregister);
+#ifdef USES_EZUSB_FUNCTIONS
+	EXPORT_SYMBOL(ezusb_writememory);
+	EXPORT_SYMBOL(ezusb_set_reset);
+#endif
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/visor.c linux.18p8/drivers/usb/serial/visor.c
--- linux.vanilla/drivers/usb/serial/visor.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/visor.c	Tue Sep 12 12:53:10 2000
@@ -0,0 +1,479 @@
+/*
+ * USB HandSpring Visor driver
+ *
+ *	Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (09/06/2000) gkh
+ *	Fixed oops in visor_exit.  Need to uncomment usb_unlink_urb call _after_
+ *	the host controller drivers set urb->dev = NULL when the urb is finished.
+ *
+ * (08/08/2000) gkh
+ *	Fixed endian problem in visor_startup.
+ *	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more 
+ *	than once.
+ * 
+ * (07/23/2000) gkh
+ *	Added pool of write urbs to speed up transfers to the visor.
+ * 
+ * (07/19/2000) gkh
+ *	Added module_init and module_exit functions to handle the fact that this
+ *	driver is a loadable module now.
+ *
+ * (07/03/2000) gkh
+ *	Added visor_set_ioctl and visor_set_termios functions (they don't do much
+ *	of anything, but are good for debugging.)
+ * 
+ * (06/25/2000) gkh
+ *	Fixed bug in visor_unthrottle that should help with the disconnect in PPP
+ *	bug that people have been reporting.
+ *
+ * (06/23/2000) gkh
+ *	Cleaned up debugging statements in a quest to find UHCI timeout bug.
+ *
+ * (04/27/2000) Ryan VanderBijl
+ * 	Fixed memory leak in visor_close
+ *
+ * (03/26/2000) gkh
+ *	Split driver up into device specific pieces.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "visor.h"
+
+
+/* function prototypes for a handspring visor */
+static int  visor_open		(struct usb_serial_port *port, struct file *filp);
+static void visor_close		(struct usb_serial_port *port, struct file *filp);
+static int  visor_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static void visor_throttle	(struct usb_serial_port *port);
+static void visor_unthrottle	(struct usb_serial_port *port);
+static int  visor_startup	(struct usb_serial *serial);
+static void visor_shutdown	(struct usb_serial *serial);
+static int  visor_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void visor_set_termios	(struct usb_serial_port *port, struct termios *old_termios);
+static void visor_write_bulk_callback (struct urb *urb);
+
+/* All of the device info needed for the Handspring Visor */
+static __u16	handspring_vendor_id	= HANDSPRING_VENDOR_ID;
+static __u16	handspring_product_id	= HANDSPRING_VISOR_ID;
+struct usb_serial_device_type handspring_device = {
+	name:			"Handspring Visor",
+	idVendor:		&handspring_vendor_id,	/* the Handspring vendor ID */
+	idProduct:		&handspring_product_id,	/* the Handspring Visor product id */
+	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
+	num_interrupt_in:	0,
+	num_bulk_in:		2,
+	num_bulk_out:		2,
+	num_ports:		2,
+	open:			visor_open,
+	close:			visor_close,
+	throttle:		visor_throttle,
+	unthrottle:		visor_unthrottle,
+	startup:		visor_startup,
+	shutdown:		visor_shutdown,
+	ioctl:			visor_ioctl,
+	set_termios:		visor_set_termios,
+	write:			visor_write,
+	write_bulk_callback:	visor_write_bulk_callback,
+};
+
+
+#define NUM_URBS	24
+static struct urb *write_urb_pool[NUM_URBS];
+
+
+/******************************************************************************
+ * Handspring Visor specific driver functions
+ ******************************************************************************/
+static int visor_open (struct usb_serial_port *port, struct file *filp)
+{
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (port->active) {
+		dbg (__FUNCTION__ " - device already open");
+		return -EINVAL;
+	}
+
+	++port->open_count;
+	MOD_INC_USE_COUNT;
+	
+	if (!port->active) {
+		port->active = 1;
+
+		/*Start reading from the device*/
+		if (usb_submit_urb(port->read_urb))
+			dbg(__FUNCTION__  " - usb_submit_urb(read bulk) failed");
+	}
+	
+	return 0;
+}
+
+
+static void visor_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial *serial = port->serial;
+	unsigned char *transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+			 
+	--port->open_count;
+	MOD_DEC_USE_COUNT;
+
+	if (port->open_count <= 0) {
+		if (!transfer_buffer) {
+			err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
+		} else {
+			/* send a shutdown message to the device */
+			usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_CLOSE_NOTIFICATION,
+					0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+			kfree (transfer_buffer);
+		}
+
+		/* shutdown our bulk read */
+		usb_unlink_urb (port->read_urb);
+		port->active = 0;
+		port->open_count = 0;
+	}
+}
+
+
+static int visor_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+	struct urb *urb = NULL;
+	unsigned char *buffer = NULL;
+	int status;
+	int i;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (count == 0) {
+		dbg(__FUNCTION__ " - write request of 0 bytes");
+		return 0;
+	}
+
+	/* try to find a free urb in our list of them */
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]->status != -EINPROGRESS) {
+			urb = write_urb_pool[i];
+			break;
+		}
+	}
+	if (urb == NULL) {
+		dbg (__FUNCTION__ " - no free urbs");
+		return 0;
+	}
+
+	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+#ifdef DEBUG
+	printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count);
+	for (i = 0; i < count; ++i) {
+		printk ("%.2x ", buf[i]);
+	}
+	printk ("\n");
+#endif
+
+	if (urb->transfer_buffer != NULL)
+		kfree(urb->transfer_buffer);
+	buffer = kmalloc (count, GFP_KERNEL);
+	if (buffer == NULL) {
+		err(__FUNCTION__" no more kernel memory...");
+		return 0;
+	}
+	
+	if (from_user) {
+		copy_from_user(buffer, buf, count);
+	}
+	else {
+		memcpy (buffer, buf, count);
+	}  
+
+	/* build up our urb */
+	FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+			buffer, count, visor_write_bulk_callback, port);
+	urb->transfer_flags |= USB_QUEUE_BULK;
+
+	/* send it down the pipe */
+	status = usb_submit_urb(urb);
+	if (status)
+		dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+
+	return (count);
+} 
+
+
+static void visor_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	queue_task(&port->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	
+	return;
+}
+
+
+static void visor_throttle (struct usb_serial_port *port)
+{
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	usb_unlink_urb (port->read_urb);
+
+	return;
+}
+
+
+static void visor_unthrottle (struct usb_serial_port *port)
+{
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (usb_submit_urb (port->read_urb))
+		dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+
+	return;
+}
+
+
+static int  visor_startup (struct usb_serial *serial)
+{
+	int response;
+	int i;
+	unsigned char *transfer_buffer =  kmalloc (256, GFP_KERNEL);
+
+	if (!transfer_buffer) {
+		err(__FUNCTION__ " - kmalloc(%d) failed.", 256);
+		return -ENOMEM;
+	}
+
+	dbg(__FUNCTION__);
+
+	dbg(__FUNCTION__ " - Set config to 1");
+	usb_set_configuration (serial->dev, 1);
+
+	/* send a get connection info request */
+	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_GET_CONNECTION_INFORMATION,
+					0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300);
+	if (response < 0) {
+		err(__FUNCTION__ " - error getting connection information");
+	} else {
+		struct visor_connection_info *connection_info = (struct visor_connection_info *)transfer_buffer;
+		char *string;
+
+		le16_to_cpus(&connection_info->num_ports);
+		info("%s: Number of ports: %d", serial->type->name, connection_info->num_ports);
+		for (i = 0; i < connection_info->num_ports; ++i) {
+			switch (connection_info->connections[i].port_function_id) {
+				case VISOR_FUNCTION_GENERIC:
+					string = "Generic";
+					break;
+				case VISOR_FUNCTION_DEBUGGER:
+					string = "Debugger";
+					break;
+				case VISOR_FUNCTION_HOTSYNC:
+					string = "HotSync";
+					break;
+				case VISOR_FUNCTION_CONSOLE:
+					string = "Console";
+					break;
+				case VISOR_FUNCTION_REMOTE_FILE_SYS:
+					string = "Remote File System";
+					break;
+				default:
+					string = "unknown";
+					break;	
+			}
+			info("%s: port %d, is for %s use and is bound to ttyUSB%d", serial->type->name, connection_info->connections[i].port, string, serial->minor + i);
+		}
+	}
+
+	/* ask for the number of bytes available, but ignore the response as it is broken */
+	response = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), VISOR_REQUEST_BYTES_AVAILABLE,
+					0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300);
+	if (response < 0) {
+		err(__FUNCTION__ " - error getting bytes available request");
+	}
+
+	kfree (transfer_buffer);
+
+	/* continue on with initialization */
+	return (0);
+}
+
+
+static void visor_shutdown (struct usb_serial *serial)
+{
+	int i;
+
+	dbg (__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			visor_close (&serial->port[i], NULL);
+		}
+	}
+}
+
+
+static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+
+	return -ENOIOCTLCMD;
+}
+
+
+/* This function is all nice and good, but we don't change anything based on it :) */
+static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+	unsigned int cflag = port->tty->termios->c_cflag;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	/* check that they really want us to change something */
+	if (old_termios) {
+		if ((cflag == old_termios->c_cflag) &&
+		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg(__FUNCTION__ " - nothing to change...");
+			return;
+		}
+	}
+
+	if ((!port->tty) || (!port->tty->termios)) {
+		dbg(__FUNCTION__" - no tty structures");
+		return;
+	}
+
+	/* get the byte size */
+	switch (cflag & CSIZE) {
+		case CS5:	dbg(__FUNCTION__ " - data bits = 5");   break;
+		case CS6:	dbg(__FUNCTION__ " - data bits = 6");   break;
+		case CS7:	dbg(__FUNCTION__ " - data bits = 7");   break;
+		default:
+		case CS8:	dbg(__FUNCTION__ " - data bits = 8");   break;
+	}
+	
+	/* determine the parity */
+	if (cflag & PARENB)
+		if (cflag & PARODD)
+			dbg(__FUNCTION__ " - parity = odd");
+		else
+			dbg(__FUNCTION__ " - parity = even");
+	else
+		dbg(__FUNCTION__ " - parity = none");
+
+	/* figure out the stop bits requested */
+	if (cflag & CSTOPB)
+		dbg(__FUNCTION__ " - stop bits = 2");
+	else
+		dbg(__FUNCTION__ " - stop bits = 1");
+
+	
+	/* figure out the flow control settings */
+	if (cflag & CRTSCTS)
+		dbg(__FUNCTION__ " - RTS/CTS is enabled");
+	else
+		dbg(__FUNCTION__ " - RTS/CTS is disabled");
+	
+	/* determine software flow control */
+	if (I_IXOFF(port->tty))
+		dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty));
+	else
+		dbg(__FUNCTION__ " - XON/XOFF is disabled");
+
+	/* get the baud rate wanted */
+	dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty));
+
+	return;
+}
+
+
+int visor_init (void)
+{
+	int i;
+
+	usb_serial_register (&handspring_device);
+	
+	/* create our write urb pool */ 
+	for (i = 0; i < NUM_URBS; ++i) {
+		struct urb  *urb = usb_alloc_urb(0);
+		if (urb == NULL) {
+			err("No more urbs???");
+			continue;
+		}
+		urb->transfer_buffer = NULL;
+		write_urb_pool[i] = urb;
+	}
+	
+	return 0;
+}
+
+
+void visor_exit (void)
+{
+	int i;
+
+	usb_serial_deregister (&handspring_device);
+	
+	for (i = 0; i < NUM_URBS; ++i) {
+		/* FIXME - uncomment the following usb_unlink_urb call when
+		 * the host controllers get fixed to set urb->dev = NULL after
+		 * the urb is finished.  Otherwise this call oopses. */
+		/* usb_unlink_urb(write_urb_pool[i]); */
+		if (write_urb_pool[i]->transfer_buffer)
+			kfree(write_urb_pool[i]->transfer_buffer);
+		usb_free_urb (write_urb_pool[i]);
+	}
+}
+
+
+module_init(visor_init);
+module_exit(visor_exit);
+
+MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
+MODULE_DESCRIPTION("USB HandSpring Visor driver");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/visor.h linux.18p8/drivers/usb/serial/visor.h
--- linux.vanilla/drivers/usb/serial/visor.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/visor.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,74 @@
+/*
+ * USB HandSpring Visor driver
+ *
+ *	Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ */
+
+#ifndef __LINUX_USB_SERIAL_VISOR_H
+#define __LINUX_USB_SERIAL_VISOR_H
+
+
+#define HANDSPRING_VENDOR_ID		0x082d
+#define HANDSPRING_VISOR_ID		0x0100
+
+/****************************************************************************
+ * Handspring Visor Vendor specific request codes (bRequest values)
+ * A big thank you to Handspring for providing the following information.
+ * If anyone wants the original file where these values and structures came
+ * from, send email to <greg@kroah.com>.
+ ****************************************************************************/
+
+/****************************************************************************
+ * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that
+ * are available to be transfered to the host for the specified endpoint.
+ * Currently this is not used, and always returns 0x0001
+ ****************************************************************************/
+#define VISOR_REQUEST_BYTES_AVAILABLE		0x01
+
+/****************************************************************************
+ * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host
+ * is now closing the pipe. An empty packet is sent in response.
+ ****************************************************************************/
+#define VISOR_CLOSE_NOTIFICATION		0x02
+
+/****************************************************************************
+ * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to
+ * get the endpoints used by the connection.
+ ****************************************************************************/
+#define VISOR_GET_CONNECTION_INFORMATION	0x03
+
+
+/****************************************************************************
+ * VISOR_GET_CONNECTION_INFORMATION returns data in the following format
+ ****************************************************************************/
+struct visor_connection_info {
+	__u16	num_ports;
+	struct {
+		__u8	port_function_id;
+		__u8	port;
+	} connections[2];
+};
+
+
+/* struct visor_connection_info.connection[x].port defines: */
+#define VISOR_ENDPOINT_1		0x01
+#define VISOR_ENDPOINT_2		0x02
+
+/* struct visor_connection_info.connection[x].port_function_id defines: */
+#define VISOR_FUNCTION_GENERIC		0x00
+#define VISOR_FUNCTION_DEBUGGER		0x01
+#define VISOR_FUNCTION_HOTSYNC		0x02
+#define VISOR_FUNCTION_CONSOLE		0x03
+#define VISOR_FUNCTION_REMOTE_FILE_SYS	0x04
+
+#endif
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/whiteheat.c linux.18p8/drivers/usb/serial/whiteheat.c
--- linux.vanilla/drivers/usb/serial/whiteheat.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/whiteheat.c	Fri Sep  8 17:02:03 2000
@@ -0,0 +1,553 @@
+/*
+ * USB ConnectTech WhiteHEAT driver
+ *
+ *	Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ * (07/19/2000) gkh
+ *	Added module_init and module_exit functions to handle the fact that this
+ *	driver is a loadable module now.
+ *	Fixed bug with port->minor that was found by Al Borchers
+ *
+ * (07/04/2000) gkh
+ *	Added support for port settings. Baud rate can now be changed. Line signals
+ *	are not transferred to and from the tty layer yet, but things seem to be 
+ *	working well now.
+ *
+ * (05/04/2000) gkh
+ *	First cut at open and close commands. Data can flow through the ports at
+ *	default speeds now.
+ *
+ * (03/26/2000) gkh
+ *	Split driver up into device specific pieces.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#include "whiteheat_fw.h"		/* firmware for the ConnectTech WhiteHEAT device */
+
+#include "whiteheat.h"			/* WhiteHEAT specific commands */
+
+#define CONNECT_TECH_VENDOR_ID		0x0710
+#define CONNECT_TECH_FAKE_WHITE_HEAT_ID	0x0001
+#define CONNECT_TECH_WHITE_HEAT_ID	0x8001
+
+/* function prototypes for the Connect Tech WhiteHEAT serial converter */
+static int  whiteheat_open		(struct usb_serial_port *port, struct file *filp);
+static void whiteheat_close		(struct usb_serial_port *port, struct file *filp);
+static int  whiteheat_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void whiteheat_set_termios	(struct usb_serial_port *port, struct termios * old);
+static void whiteheat_throttle		(struct usb_serial_port *port);
+static void whiteheat_unthrottle	(struct usb_serial_port *port);
+static int  whiteheat_startup		(struct usb_serial *serial);
+static void whiteheat_shutdown		(struct usb_serial *serial);
+
+/* All of the device info needed for the Connect Tech WhiteHEAT */
+static __u16	connecttech_vendor_id			= CONNECT_TECH_VENDOR_ID;
+static __u16	connecttech_whiteheat_fake_product_id	= CONNECT_TECH_FAKE_WHITE_HEAT_ID;
+static __u16	connecttech_whiteheat_product_id	= CONNECT_TECH_WHITE_HEAT_ID;
+struct usb_serial_device_type whiteheat_fake_device = {
+	name:			"Connect Tech - WhiteHEAT - (prerenumeration)",
+	idVendor:		&connecttech_vendor_id,			/* the Connect Tech vendor id */
+	idProduct:		&connecttech_whiteheat_fake_product_id,	/* the White Heat initial product id */
+	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
+	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */
+	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	startup:		whiteheat_startup	
+};
+struct usb_serial_device_type whiteheat_device = {
+	name:			"Connect Tech - WhiteHEAT",
+	idVendor:		&connecttech_vendor_id,			/* the Connect Tech vendor id */
+	idProduct:		&connecttech_whiteheat_product_id,	/* the White Heat real product id */
+	needs_interrupt_in:	DONT_CARE,				/* don't have to have an interrupt in endpoint */
+	needs_bulk_in:		DONT_CARE,				/* don't have to have a bulk in endpoint */
+	needs_bulk_out:		DONT_CARE,				/* don't have to have a bulk out endpoint */
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		4,
+	open:			whiteheat_open,
+	close:			whiteheat_close,
+	throttle:		whiteheat_throttle,
+	unthrottle:		whiteheat_unthrottle,
+	ioctl:			whiteheat_ioctl,
+	set_termios:		whiteheat_set_termios,
+	shutdown:		whiteheat_shutdown,
+};
+
+struct whiteheat_private {
+	__u8			command_finished;
+	wait_queue_head_t	wait_command;	/* for handling sleeping while waiting for a command to finish */
+};
+
+
+/* local function prototypes */
+static inline void set_rts	(struct usb_serial_port *port, unsigned char rts);
+static inline void set_dtr	(struct usb_serial_port *port, unsigned char dtr);
+static inline void set_break	(struct usb_serial_port *port, unsigned char brk);
+
+
+
+#define COMMAND_PORT		4
+#define COMMAND_TIMEOUT		(2*HZ)	/* 2 second timeout for a command */
+
+/*****************************************************************************
+ * Connect Tech's White Heat specific driver functions
+ *****************************************************************************/
+static void command_port_write_callback (struct urb *urb)
+{
+	unsigned char *data = urb->transfer_buffer;
+#ifdef DEBUG
+	int i;
+#endif
+
+	dbg (__FUNCTION__);
+
+	if (urb->status) {
+		dbg ("nonzero urb status: %d", urb->status);
+		return;
+	}
+
+#ifdef DEBUG
+	if (urb->actual_length) {
+		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", urb->actual_length);
+		for (i = 0; i < urb->actual_length; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+	return;
+}
+
+
+static void command_port_read_callback (struct urb *urb)
+{
+	struct whiteheat_private *info = (struct whiteheat_private *)urb->context;
+	unsigned char *data = urb->transfer_buffer;
+#ifdef DEBUG
+	int i;
+#endif
+
+	dbg (__FUNCTION__);
+
+	if (urb->status) {
+		dbg (__FUNCTION__ " - nonzero urb status: %d", urb->status);
+		return;
+	}
+
+#ifdef DEBUG
+	if (urb->actual_length) {
+		printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", urb->actual_length);
+		for (i = 0; i < urb->actual_length; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+	/* right now, if the command is COMMAND_COMPLETE, just flip the bit saying the command finished */
+	/* in the future we're going to have to pay attention to the actual command that completed */
+	if (data[0] == WHITEHEAT_CMD_COMPLETE) {
+		info->command_finished = TRUE;
+	}
+	
+	return;
+}
+
+
+static int whiteheat_send_cmd (struct usb_serial *serial, __u8 command, __u8 *data, __u8 datasize)
+{
+	struct whiteheat_private *info;
+	struct usb_serial_port *port;
+	int timeout;
+	__u8 *transfer_buffer;
+
+	dbg(__FUNCTION__" - command %d", command);
+
+	port = &serial->port[COMMAND_PORT];
+	info = (struct whiteheat_private *)port->private;
+	info->command_finished = FALSE;
+	
+	transfer_buffer = (__u8 *)port->write_urb->transfer_buffer;
+	transfer_buffer[0] = command;
+	memcpy (&transfer_buffer[1], data, datasize);
+	port->write_urb->transfer_buffer_length = datasize + 1;
+	if (usb_submit_urb (port->write_urb)) {
+		dbg (__FUNCTION__" - submit urb failed");
+		return -1;
+	}
+
+	/* wait for the command to complete */
+	timeout = COMMAND_TIMEOUT;
+	while (timeout && (info->command_finished == FALSE)) {
+		timeout = interruptible_sleep_on_timeout (&info->wait_command, timeout);
+	}
+
+	if (info->command_finished == FALSE) {
+		dbg (__FUNCTION__ " - command timed out.");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct whiteheat_min_set	open_command;
+	struct usb_serial_port 		*command_port;
+	struct whiteheat_private	*info;
+
+	dbg(__FUNCTION__" - port %d", port->number);
+
+	if (port->active) {
+		dbg (__FUNCTION__ " - device already open");
+		return -EINVAL;
+	}
+	port->active = 1;
+
+	/* set up some stuff for our command port */
+	command_port = &port->serial->port[COMMAND_PORT];
+	if (command_port->private == NULL) {
+		info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
+		if (info == NULL) {
+			err(__FUNCTION__ " - out of memory");
+			return -ENOMEM;
+		}
+		
+		init_waitqueue_head(&info->wait_command);
+		command_port->private = info;
+		command_port->write_urb->complete = command_port_write_callback;
+		command_port->read_urb->complete = command_port_read_callback;
+		usb_submit_urb (command_port->read_urb);	
+	}
+	
+	/* Start reading from the device */
+	if (usb_submit_urb(port->read_urb))
+		dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+
+	/* send an open port command */
+	open_command.port = port->number - port->serial->minor;
+	whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
+
+	/* Need to do device specific setup here (control lines, baud rate, etc.) */
+	/* FIXME!!! */
+
+	dbg(__FUNCTION__ " - exit");
+	
+	return 0;
+}
+
+
+static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
+{
+	struct whiteheat_min_set	close_command;
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	/* send a close command to the port */
+	close_command.port = port->number - port->serial->minor;
+	whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
+
+	/* Need to change the control lines here */
+	/* FIXME */
+	
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	port->active = 0;
+}
+
+
+static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+
+	return -ENOIOCTLCMD;
+}
+
+
+static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+	unsigned int cflag = port->tty->termios->c_cflag;
+	struct whiteheat_port_settings port_settings;
+
+	dbg(__FUNCTION__ " -port %d", port->number);
+
+	/* check that they really want us to change something */
+	if (old_termios) {
+		if ((cflag == old_termios->c_cflag) &&
+		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg(__FUNCTION__ " - nothing to change...");
+			return;
+		}
+	}
+
+	if ((!port->tty) || (!port->tty->termios)) {
+		dbg(__FUNCTION__" - no tty structures");
+		return;
+	}
+	
+	/* get the byte size */
+	switch (cflag & CSIZE) {
+		case CS5:	port_settings.bits = 5;   break;
+		case CS6:	port_settings.bits = 6;   break;
+		case CS7:	port_settings.bits = 7;   break;
+		default:
+		case CS8:	port_settings.bits = 8;   break;
+	}
+	dbg(__FUNCTION__ " - data bits = %d", port_settings.bits);
+	
+	/* determine the parity */
+	if (cflag & PARENB)
+		if (cflag & PARODD)
+			port_settings.parity = 'o';
+		else
+			port_settings.parity = 'e';
+	else
+		port_settings.parity = 'n';
+	dbg(__FUNCTION__ " - parity = %c", port_settings.parity);
+
+	/* figure out the stop bits requested */
+	if (cflag & CSTOPB)
+		port_settings.stop = 2;
+	else
+		port_settings.stop = 1;
+	dbg(__FUNCTION__ " - stop bits = %d", port_settings.stop);
+
+	
+	/* figure out the flow control settings */
+	if (cflag & CRTSCTS)
+		port_settings.hflow = (WHITEHEAT_CTS_FLOW | WHITEHEAT_RTS_FLOW);
+	else
+		port_settings.hflow = 0;
+	dbg(__FUNCTION__ " - hardware flow control = %s %s %s %s",
+	    (port_settings.hflow | WHITEHEAT_CTS_FLOW) ? "CTS" : "",
+	    (port_settings.hflow | WHITEHEAT_RTS_FLOW) ? "RTS" : "",
+	    (port_settings.hflow | WHITEHEAT_DSR_FLOW) ? "DSR" : "",
+	    (port_settings.hflow | WHITEHEAT_DTR_FLOW) ? "DTR" : "");
+	
+	/* determine software flow control */
+	if (I_IXOFF(port->tty))
+		port_settings.sflow = 'b';
+	else
+		port_settings.sflow = 'n';
+	dbg(__FUNCTION__ " - software flow control = %c", port_settings.sflow);
+	
+	port_settings.xon = START_CHAR(port->tty);
+	port_settings.xoff = STOP_CHAR(port->tty);
+	dbg(__FUNCTION__ " - XON = %2x, XOFF = %2x", port_settings.xon, port_settings.xoff);
+
+	/* get the baud rate wanted */
+	port_settings.baud = tty_get_baud_rate(port->tty);
+	dbg(__FUNCTION__ " - baud rate = %d", port_settings.baud);
+
+	/* handle any settings that aren't specified in the tty structure */
+	port_settings.lloop = 0;
+	
+	/* now send the message to the device */
+	whiteheat_send_cmd (port->serial, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings));
+	
+	return;
+}
+
+
+static void whiteheat_throttle (struct usb_serial_port *port)
+{
+	dbg(__FUNCTION__" - port %d", port->number);
+
+	/* Change the control signals */
+	/* FIXME!!! */
+
+	return;
+}
+
+
+static void whiteheat_unthrottle (struct usb_serial_port *port)
+{
+	dbg(__FUNCTION__" - port %d", port->number);
+
+	/* Change the control signals */
+	/* FIXME!!! */
+
+	return;
+}
+
+
+/* steps to download the firmware to the WhiteHEAT device:
+ - hold the reset (by writing to the reset bit of the CPUCS register)
+ - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD
+ - release the reset (by writing to the CPUCS register)
+ - download the WH.HEX file for all addresses greater than 0x1b3f using
+   VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD
+ - hold the reset
+ - download the WH.HEX file for all addresses less than 0x1b40 using
+   VENDOR_REQUEST_ANCHOR_LOAD
+ - release the reset
+ - device renumerated itself and comes up as new device id with all
+   firmware download completed.
+*/
+static int  whiteheat_startup (struct usb_serial *serial)
+{
+	int response;
+	const struct whiteheat_hex_record *record;
+	
+	dbg(__FUNCTION__);
+	
+	response = ezusb_set_reset (serial, 1);
+
+	record = &whiteheat_loader[0];
+	while (record->address != 0xffff) {
+		response = ezusb_writememory (serial, record->address, 
+				(unsigned char *)record->data, record->data_size, 0xa0);
+		if (response < 0) {
+			err(__FUNCTION__ " - ezusb_writememory failed for loader (%d %04X %p %d)", 
+				response, record->address, record->data, record->data_size);
+			break;
+		}
+		++record;
+	}
+
+	response = ezusb_set_reset (serial, 0);
+
+	record = &whiteheat_firmware[0];
+	while (record->address < 0x1b40) {
+		++record;
+	}
+	while (record->address != 0xffff) {
+		response = ezusb_writememory (serial, record->address, 
+				(unsigned char *)record->data, record->data_size, 0xa3);
+		if (response < 0) {
+			err(__FUNCTION__ " - ezusb_writememory failed for first firmware step (%d %04X %p %d)", 
+				response, record->address, record->data, record->data_size);
+			break;
+		}
+		++record;
+	}
+	
+	response = ezusb_set_reset (serial, 1);
+
+	record = &whiteheat_firmware[0];
+	while (record->address < 0x1b40) {
+		response = ezusb_writememory (serial, record->address, 
+				(unsigned char *)record->data, record->data_size, 0xa0);
+		if (response < 0) {
+			err(__FUNCTION__" - ezusb_writememory failed for second firmware step (%d %04X %p %d)", 
+				response, record->address, record->data, record->data_size);
+			break;
+		}
+		++record;
+	}
+
+	response = ezusb_set_reset (serial, 0);
+
+	/* we want this device to fail to have a driver assigned to it. */
+	return 1;
+}
+
+
+static void whiteheat_shutdown (struct usb_serial *serial)
+{
+	struct usb_serial_port 		*command_port;
+
+	dbg(__FUNCTION__);
+
+	/* free up our private data for our command port */
+	command_port = &serial->port[COMMAND_PORT];
+	if (command_port->private != NULL) {
+		kfree (command_port->private);
+		command_port->private = NULL;
+	}
+
+	return;
+}
+
+
+
+
+static void set_command (struct usb_serial_port *port, unsigned char state, unsigned char command)
+{
+	struct whiteheat_rdb_set rdb_command;
+	
+	/* send a set rts command to the port */
+	rdb_command.port = port->number - port->serial->minor;
+	rdb_command.state = state;
+
+	whiteheat_send_cmd (port->serial, command, (__u8 *)&rdb_command, sizeof(rdb_command));
+}
+
+
+static inline void set_rts (struct usb_serial_port *port, unsigned char rts)
+{
+	set_command (port, rts, WHITEHEAT_SET_RTS);
+}
+
+
+static inline void set_dtr (struct usb_serial_port *port, unsigned char dtr)
+{
+	set_command (port, dtr, WHITEHEAT_SET_DTR);
+}
+
+
+static inline void set_break (struct usb_serial_port *port, unsigned char brk)
+{
+	set_command (port, brk, WHITEHEAT_SET_BREAK);
+}
+
+
+int whiteheat_init (void)
+{
+	usb_serial_register (&whiteheat_fake_device);
+	usb_serial_register (&whiteheat_device);
+	return 0;
+}
+
+
+void whiteheat_exit (void)
+{
+	usb_serial_deregister (&whiteheat_fake_device);
+	usb_serial_deregister (&whiteheat_device);
+}
+
+
+module_init(whiteheat_init);
+module_exit(whiteheat_exit);
+
+MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
+MODULE_DESCRIPTION("USB ConnectTech WhiteHEAT driver");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/whiteheat.h linux.18p8/drivers/usb/serial/whiteheat.h
--- linux.vanilla/drivers/usb/serial/whiteheat.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/whiteheat.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,169 @@
+/*
+ * USB ConnectTech WhiteHEAT driver
+ *
+ *      Copyright (C) 1999, 2000
+ *          Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ */
+
+#ifndef __LINUX_USB_SERIAL_WHITEHEAT_H
+#define __LINUX_USB_SERIAL_WHITEHEAT_H
+
+
+#define FALSE				0
+#define TRUE				1
+
+/* WhiteHEAT commands */
+#define WHITEHEAT_OPEN			1	/* open the port */
+#define WHITEHEAT_CLOSE			2	/* close the port */
+#define WHITEHEAT_SETUP_PORT		3	/* change port settings */
+#define WHITEHEAT_SET_RTS		4	/* turn RTS on or off */
+#define WHITEHEAT_SET_DTR		5	/* turn DTR on or off */
+#define WHITEHEAT_SET_BREAK		6	/* turn BREAK on or off */
+#define WHITEHEAT_DUMP			7	/* dump memory */
+#define WHITEHEAT_STATUS		8	/* get status */
+#define WHITEHEAT_PURGE			9	/* clear the UART fifos */
+#define WHITEHEAT_GET_DTR_RTS		10	/* get the state of DTR and RTS for a port */
+#define WHITEHEAT_GET_HW_INFO		11	/* get EEPROM info and hardware ID */
+#define WHITEHEAT_REPORT_TX_DONE	12	/* get the next TX done */
+#define WHITEHEAT_EVENT			13	/* unsolicited status events */
+#define WHITEHEAT_ECHO			14	/* send data to the indicated IN endpoint */
+#define WHITEHEAT_DO_TEST		15	/* perform the specified test */
+#define WHITEHEAT_CMD_COMPLETE		16	/* reply for certain commands */
+
+/* Data for the WHITEHEAT_SETUP_PORT command */
+#define WHITEHEAT_CTS_FLOW		0x08
+#define WHITEHEAT_RTS_FLOW		0x80
+#define WHITEHEAT_DSR_FLOW		0x10
+#define WHITEHEAT_DTR_FLOW		0x02
+struct whiteheat_port_settings {
+	__u8	port;		/* port number (1 to N) */
+	__u32	baud;		/* any value allowed, default 9600, arrives little endian, range is 7 - 460800 */
+	__u8	bits;		/* 5, 6, 7, or 8, default 8 */
+	__u8	stop;		/* 1 or 2, default 1 (2 = 1.5 if bits = 5) */
+	__u8	parity;		/* 'n, e, o, 0, or 1' (ascii), default 'n'
+				 *	n = none	e = even	o = odd
+				 *	0 = force 0	1 = force 1	*/
+	__u8	sflow;		/* 'n, r, t, or b' (ascii), default 'n'
+				 *	n = none
+				 *	r = receive (XOFF/XON transmitted when receiver fills / empties)
+				 *	t = transmit (XOFF/XON received will stop/start TX)
+				 *	b = both 	*/
+	__u8	xoff;		/* XOFF byte value, default 0x13 */
+	__u8	xon;		/* XON byte value, default 0x11 */
+	__u8	hflow;		/* bits indicate mode as follows:
+				 *	CTS (0x08) (CTS off/on will control/cause TX off/on)
+				 *	DSR (0x10) (DSR off/on will control/cause TX off/on)
+				 *	RTS (0x80) (RTS off/on when receiver fills/empties)
+				 *	DTR (0x02) (DTR off/on when receiver fills/empties) */
+	__u8	lloop;		/* local loopback 0 or 1, default 0 */
+};
+
+/* data for WHITEHEAT_SET_RTS, WHITEHEAT_SET_DTR, and WHITEHEAT_SET_BREAK commands */
+struct whiteheat_rdb_set {
+	__u8	port;		/* port number (1 to N) */
+	__u8	state;		/* 0 = off, non-zero = on */
+};
+
+/* data for:
+	WHITEHEAT_OPEN
+	WHITEHEAT_CLOSE
+	WHITEHEAT_STATUS
+	WHITEHEAT_GET_DTR_RTS
+	WHITEHEAT_REPORT_TX_DONE */
+struct whiteheat_min_set {
+	__u8	port;		/* port number (1 to N) */
+};
+
+/* data for WHITEHEAT_PURGE command */
+#define WHITEHEAT_PURGE_INPUT		0x01
+#define WHITEHEAT_PURGE_OUTPUT		0x02
+struct whiteheat_purge_set {
+	__u8	port;		/* port number (1 to N) */
+	__u8	what;		/* bit pattern of what to purge */
+};
+
+/* data for WHITEHEAT_DUMP command */
+struct whiteheat_dump_info {
+	__u8	mem_type;	/* memory type: 'd' = data, 'i' = idata, 'b' = bdata, 'x' = xdata */
+	__u16	addr;		/* memory address to dump, address range depends on the above mem_type:
+				 *	'd' = 0 to ff (80 to FF is SFR's)
+				 *	'i' = 80 to ff
+				 *	'b' = 20 to 2f (bits returned as bytes)
+				 *	'x' = 0000 to ffff (also code space)	*/
+	__u16	length;		/* number of bytes to dump, max 64 */
+};
+
+/* data for WHITEHEAT_ECHO command */
+struct whiteheat_echo_set {
+	__u8	port;		/* port number (1 to N) */
+	__u8	length;		/* length of message to echo */
+	__u8	echo_data[61];	/* data to echo */
+};
+
+/* data returned from WHITEHEAT_STATUS command */
+#define WHITEHEAT_OVERRUN_ERROR		0x02
+#define WHITEHEAT_PARITY_ERROR		0x04
+#define WHITEHEAT_FRAMING_ERROR		0x08
+#define WHITEHEAT_BREAK_ERROR		0x10
+
+#define WHITEHEAT_OHFLOW		0x01	/* TX is stopped by CTS (waiting for CTS to go ON) */
+#define WHITEHEAT_IHFLOW		0x02	/* remote TX is stopped by RTS */
+#define WHITEHEAT_OSFLOW		0x04	/* TX is stopped by XOFF received (waiting for XON to occur) */
+#define WHITEHEAT_ISFLOW		0x08	/* remote TX is stopped by XOFF transmitted */
+#define WHITEHEAT_TX_DONE		0x80	/* TX has completed */
+
+#define WHITEHEAT_MODEM_EVENT		0x01
+#define WHITEHEAT_ERROR_EVENT		0x02
+#define WHITEHEAT_FLOW_EVENT		0x04
+#define WHITEHEAT_CONNECT_EVENT		0x08
+struct whiteheat_status_info {
+	__u8	port;		/* port number (1 to N) */
+	__u8	event;		/* indicates which of the following bytes are the current event */
+	__u8	modem;		/* modem signal status (copy of UART MSR register) */
+	__u8	error;		/* PFO and RX break (copy of UART LSR register) */
+	__u8	flow;		/* flow control state */
+	__u8	connect;	/* connect state, non-zero value indicates connected */
+};
+
+/* data returned from WHITEHEAT_EVENT command */
+struct whiteheat_event {
+	__u8	port;		/* port number (1 to N) */
+	__u8	event;		/* indicates which of the following bytes are the current event */
+	__u8	info;		/* either modem, error, flow, or connect information */
+};
+
+/* data retured by the WHITEHEAT_GET_HW_INFO command */
+struct whiteheat_hw_info {
+	__u8	hw_id;		/* hardware id number, WhiteHEAT = 0 */
+	__u8	sw_major_rev;	/* major version number */
+	__u8	sw_minor_rev;	/* minor version number */
+	struct whiteheat_hw_eeprom_info {
+		__u8	b0;			/* B0 */
+		__u8	vendor_id_low;		/* vendor id (low byte) */
+		__u8	vendor_id_high;		/* vendor id (high byte) */
+		__u8	product_id_low;		/* product id (low byte) */
+		__u8	product_id_high;	/* product id (high byte) */
+		__u8	device_id_low;		/* device id (low byte) */
+		__u8	device_id_high;		/* device id (high byte) */
+		__u8	not_used_1;
+		__u8	serial_number_0;	/* serial number (low byte) */
+		__u8	serial_number_1;	/* serial number */
+		__u8	serial_number_2;	/* serial number */
+		__u8	serial_number_3;	/* serial number (high byte) */
+		__u8	not_used_2;
+		__u8	not_used_3;
+		__u8	checksum_low;		/* checksum (low byte) */
+		__u8	checksum_high;		/* checksum (high byte */
+	} hw_eeprom_info;	/* EEPROM contents */
+};
+
+#endif
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/whiteheat_fw.h linux.18p8/drivers/usb/serial/whiteheat_fw.h
--- linux.vanilla/drivers/usb/serial/whiteheat_fw.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/serial/whiteheat_fw.h	Fri Sep  1 13:51:29 2000
@@ -0,0 +1,1556 @@
+/*****************************************************************************
+ *
+ *      whiteheat.h  --  ConnectTech WhiteHEAT Firmware.
+ *
+ *      Copyright (C) 2000  ConnectTech Inc (http://www.connecttech.com/)
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * (04/09/2000) gkh
+ *	Updated the firmware with the latest provided by ConnectTech.
+ *
+ * (01/16/2000) gkh
+ *	Fixed my intel hex processing tool, so now the firmware actually
+ *	matches the original file (this was causing a few problems...)
+ *
+ * (01/15/2000) gkh
+ *	Added debug loader firmware if DEBUG is #defined:
+ *		Port 1 LED flashes when the vend_ax program is running
+ *		Port 2 LED flashes when any SETUP command arrives
+ *		Port 3 LED flashes when any valid VENDOR request occurs
+ *		Port 4 LED flashes when the EXTERNAL RAM DOWNLOAD request occurs
+ *
+ * version 1.0 (01/09/2000) gkh
+ *	Original firmware from ConnectTech massaged a little to be program
+ *	readable.
+ *
+ *****************************************************************************/
+
+#define whiteheat_DATE "20000106"
+
+struct whiteheat_hex_record {
+	__u16	address;
+	__u8	data_size;
+	__u8	data[16];
+};
+
+static const struct whiteheat_hex_record whiteheat_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x93, 0xa9} },
+{ 0x0003,	3,	{0x02, 0x13, 0x12} },
+{ 0x000b,	3,	{0x02, 0x0a, 0x80} },
+{ 0x0033,	3,	{0x02, 0x08, 0x15} },
+{ 0x0043,	3,	{0x02, 0x0a, 0x00} },
+{ 0x005b,	3,	{0x02, 0x82, 0x31} },
+{ 0x0370,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x73, 0x14, 0x70, 0x03, 0x02, 0x04, 0xe7, 0x24} },
+{ 0x0380,	16,	{0xfe, 0x70, 0x03, 0x02, 0x05, 0x45, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x64, 0x14, 0x70, 0x03} },
+{ 0x0390,	16,	{0x02, 0x04, 0x52, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x49, 0x24} },
+{ 0x03a0,	16,	{0x05, 0x60, 0x03, 0x02, 0x05, 0x94, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60} },
+{ 0x03b0,	16,	{0x36, 0x24, 0x02, 0x70, 0x7b, 0x74, 0x12, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
+{ 0x03c0,	16,	{0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x7b, 0xea, 0x49, 0x60, 0x0d} },
+{ 0x03d0,	16,	{0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4} },
+{ 0x03e0,	16,	{0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x09, 0x3a, 0xea} },
+{ 0x03f0,	16,	{0x49, 0x60, 0x33, 0x12, 0x9b, 0x72, 0xf5, 0x4b, 0x90, 0x7f, 0xee, 0xe0, 0xff, 0xe5, 0x4b, 0xd3} },
+{ 0x0400,	16,	{0x9f, 0x40, 0x03, 0xe0, 0xf5, 0x4b, 0xe5, 0x4b, 0xd3, 0x94, 0x40, 0x40, 0x03, 0x75, 0x4b, 0x40} },
+{ 0x0410,	16,	{0xae, 0x02, 0xaf, 0x01, 0x7c, 0x7f, 0x7d, 0x00, 0xab, 0x4b, 0x12, 0x8d, 0xd9, 0x90, 0x7f, 0xb5} },
+{ 0x0420,	16,	{0xe5, 0x4b, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b} },
+{ 0x0430,	16,	{0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0x00, 0xe5, 0x21, 0xf0} },
+{ 0x0440,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x21, 0x02} },
+{ 0x0450,	16,	{0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x31, 0xd2, 0x02, 0x43, 0x88, 0x10, 0xd2, 0xeb, 0xd2} },
+{ 0x0460,	16,	{0xa8, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0x00, 0xe5, 0x31, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0} },
+{ 0x0470,	16,	{0x02, 0x05, 0x9b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02} },
+{ 0x0480,	16,	{0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x05, 0xe4, 0x33, 0x4f, 0x90} },
+{ 0x0490,	16,	{0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0xe4} },
+{ 0x04a0,	16,	{0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0x90} },
+{ 0x04b0,	16,	{0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25} },
+{ 0x04c0,	16,	{0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0x01, 0x90, 0x7f, 0x00} },
+{ 0x04d0,	16,	{0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xb4} },
+{ 0x04e0,	16,	{0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24} },
+{ 0x04f0,	16,	{0x02, 0x60, 0x03, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02} },
+{ 0x0500,	16,	{0x05, 0x9b, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0x9b, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x0510,	16,	{0x70, 0x2a, 0x90, 0x7f, 0xec, 0xe0, 0xff, 0xf4, 0x54, 0x80, 0xfe, 0xc4, 0x54, 0x0f, 0xfe, 0xef} },
+{ 0x0520,	16,	{0x54, 0x07, 0xfd, 0x2e, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4} },
+{ 0x0530,	16,	{0xf0, 0x90, 0x7f, 0xd7, 0xed, 0xf0, 0xef, 0x44, 0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0540,	16,	{0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70} },
+{ 0x0550,	16,	{0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04, 0xd2, 0x00, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0560,	16,	{0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4} },
+{ 0x0570,	16,	{0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x0580,	16,	{0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x0590,	16,	{0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44} },
+{ 0x05a0,	2,	{0x02, 0xf0} },
+{ 0x05a2,	1,	{0x22} },
+{ 0x05a3,	16,	{0x75, 0x47, 0xff, 0x75, 0x46, 0xff, 0x75, 0x45, 0x0f, 0x75, 0x44, 0x00, 0xd2, 0x03, 0xc2, 0x06} },
+{ 0x05b3,	16,	{0xc2, 0x02, 0xc2, 0x00, 0xc2, 0x05, 0xc2, 0x01, 0x90, 0x03, 0x00, 0x74, 0x19, 0xf0, 0xe4, 0x90} },
+{ 0x05c3,	16,	{0x01, 0xbc, 0xf0, 0xc2, 0x04, 0x90, 0x01, 0xc0, 0xf0, 0xa3, 0xf0, 0xc2, 0xaf, 0xc2, 0xa8, 0x12} },
+{ 0x05d3,	16,	{0x0b, 0x8d, 0xe4, 0x90, 0x02, 0xaf, 0xf0, 0x90, 0x01, 0x00, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x05e3,	16,	{0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x08, 0xf0, 0x7e} },
+{ 0x05f3,	16,	{0x01, 0x7f, 0x00, 0x12, 0x19, 0xc1, 0x75, 0x49, 0x12, 0x75, 0x4a, 0x0a, 0x90, 0x01, 0x0b, 0xe0} },
+{ 0x0603,	16,	{0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
+{ 0x0613,	16,	{0xef, 0xf0, 0x90, 0x01, 0x0c, 0xe0, 0x44, 0x80, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70} },
+{ 0x0623,	16,	{0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0d, 0xe0, 0xff, 0x05} },
+{ 0x0633,	16,	{0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x0643,	16,	{0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14} },
+{ 0x0653,	16,	{0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x12, 0x0a, 0xe4, 0x93, 0xff, 0x74, 0x01, 0x93, 0x90} },
+{ 0x0663,	16,	{0x01, 0x1c, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0xff, 0xa3, 0xe0, 0xfe, 0xef} },
+{ 0x0673,	16,	{0x6e, 0xff, 0x90, 0x01, 0x1c, 0xf0, 0xa3, 0xe0, 0x6f, 0xff, 0xf0, 0x90, 0x01, 0x1c, 0xe0, 0x6f} },
+{ 0x0683,	16,	{0xf0, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xe4, 0xfc, 0xfd, 0x75, 0x4f, 0x10, 0x75, 0x50, 0x02, 0x75} },
+{ 0x0693,	16,	{0x51, 0x12, 0x75, 0x52, 0xac, 0x12, 0x90, 0x15, 0x75, 0x49, 0x12, 0x75, 0x4a, 0xb2, 0x90, 0x01} },
+{ 0x06a3,	16,	{0x0d, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14, 0xf5, 0x82} },
+{ 0x06b3,	16,	{0x8c, 0x83, 0xef, 0xf0, 0x90, 0x01, 0x0e, 0xe0, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70} },
+{ 0x06c3,	16,	{0x02, 0x05, 0x49, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4} },
+{ 0x06d3,	16,	{0x54, 0x0f, 0x24, 0x41, 0xff, 0x05, 0x4a, 0xe5, 0x4a, 0xac, 0x49, 0x70, 0x02, 0x05, 0x49, 0x14} },
+{ 0x06e3,	16,	{0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x05, 0x4a, 0xe5, 0x4a, 0xae, 0x49, 0x70, 0x02, 0x05, 0x49} },
+{ 0x06f3,	16,	{0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x75, 0x82, 0x10, 0x75, 0x83, 0x01, 0xe0, 0xfc, 0xa3} },
+{ 0x0703,	16,	{0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x90, 0x01, 0x18, 0x12, 0x9d, 0x25, 0x7e, 0x01} },
+{ 0x0713,	16,	{0x7f, 0x18, 0x12, 0x85, 0x08, 0x90, 0x01, 0x18, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x0723,	16,	{0xa3, 0xe0, 0xff, 0x75, 0x4f, 0x0a, 0x75, 0x50, 0x06, 0x75, 0x51, 0x12, 0x75, 0x52, 0xb8, 0x12} },
+{ 0x0733,	16,	{0x90, 0x15, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x53, 0x91, 0xef} },
+{ 0x0743,	16,	{0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0, 0x44, 0x1f, 0xf0, 0xd2, 0xaf} },
+{ 0x0753,	16,	{0x20, 0x01, 0x2e, 0x20, 0x01, 0x2b, 0xa2, 0x03, 0x92, 0x07, 0x12, 0x09, 0xca, 0x75, 0x43, 0x50} },
+{ 0x0763,	16,	{0x75, 0x42, 0x6d, 0x75, 0x41, 0x33, 0x75, 0x40, 0x00, 0x20, 0x01, 0xe4, 0x7f, 0xff, 0x7e, 0xff} },
+{ 0x0773,	16,	{0x7d, 0xff, 0x7c, 0xff, 0x78, 0x40, 0x12, 0x9d, 0x0e, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0xd1, 0x80} },
+{ 0x0783,	16,	{0xe8, 0x30, 0x01, 0x05, 0x12, 0x03, 0x70, 0xc2, 0x01, 0x30, 0x06, 0x0d, 0x12, 0x0a, 0xed, 0x50} },
+{ 0x0793,	16,	{0x06, 0x12, 0x0b, 0x00, 0x12, 0x0a, 0xf2, 0xc2, 0x06, 0x12, 0x92, 0x38, 0x90, 0x01, 0xbd, 0xe0} },
+{ 0x07a3,	16,	{0x60, 0x10, 0x7e, 0x7b, 0x7f, 0x40, 0x12, 0x8e, 0xc1, 0xe4, 0x90, 0x01, 0xbd, 0xf0, 0x90, 0x7f} },
+{ 0x07b3,	16,	{0xd3, 0xf0, 0x90, 0x02, 0xaf, 0xe0, 0xb4, 0x0f, 0x03, 0x12, 0x95, 0x30, 0x12, 0x99, 0xcc, 0xe4} },
+{ 0x07c3,	16,	{0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x90, 0x01, 0xbc} },
+{ 0x07d3,	16,	{0xe0, 0x5e, 0x60, 0x14, 0x74, 0x27, 0x2f, 0xf8, 0xe6, 0xd3, 0x94, 0x0a, 0x40, 0x04, 0x7e, 0x01} },
+{ 0x07e3,	16,	{0x80, 0x02, 0x7e, 0x00, 0x8e, 0x48, 0x80, 0x03, 0x75, 0x48, 0x01, 0x74, 0x68, 0x2f, 0xf5, 0x82} },
+{ 0x07f3,	16,	{0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe5, 0x48, 0xf0, 0x0f, 0xbf, 0x04, 0xc5, 0xe5, 0x2b, 0xd3, 0x94} },
+{ 0x0803,	16,	{0x0a, 0x40, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x90, 0x20, 0x6c, 0xef, 0xf0, 0x02, 0x07} },
+{ 0x0813,	1,	{0x84} },
+{ 0x0814,	1,	{0x22} },
+{ 0x0815,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x0819,	16,	{0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0829,	16,	{0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x09, 0x23, 0x90, 0x7f} },
+{ 0x0839,	16,	{0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x02, 0x7d, 0xff} },
+{ 0x0849,	16,	{0x12, 0x81, 0xe0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02} },
+{ 0x0859,	16,	{0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x0869,	16,	{0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf} },
+{ 0x0879,	16,	{0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f} },
+{ 0x0889,	7,	{0x32, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x22} },
+{ 0x0890,	16,	{0x90, 0x7f, 0x96, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x80, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12} },
+{ 0x08a0,	16,	{0x09, 0x23, 0x7f, 0x02, 0xe4, 0xfd, 0x12, 0x81, 0xe0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23} },
+{ 0x08b0,	16,	{0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f} },
+{ 0x08c0,	16,	{0x96, 0xe0, 0x44, 0x04, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0} },
+{ 0x08d0,	16,	{0x54, 0xf7, 0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x01} },
+{ 0x08e0,	12,	{0xf0, 0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x12, 0x0b, 0x00, 0x22} },
+{ 0x08ec,	16,	{0x90, 0x11, 0xfc, 0xe4, 0x93, 0x70, 0x2f, 0x90, 0x7f, 0x93, 0x74, 0x30, 0xf0, 0x90, 0x7f, 0x94} },
+{ 0x08fc,	16,	{0x74, 0x3c, 0xf0, 0x90, 0x7f, 0x95, 0x74, 0xc6, 0xf0, 0xe4, 0x90, 0x7f, 0x97, 0xf0, 0x90, 0x7f} },
+{ 0x090c,	16,	{0x9d, 0x74, 0x02, 0xf0, 0x90, 0x7f, 0xe2, 0x74, 0x12, 0xf0, 0x12, 0x08, 0x19, 0x75, 0x82, 0xfc} },
+{ 0x091c,	7,	{0x75, 0x83, 0x11, 0x74, 0xff, 0xf0, 0x22} },
+{ 0x0923,	16,	{0x8e, 0x58, 0x8f, 0x59, 0xe5, 0x59, 0x15, 0x59, 0xae, 0x58, 0x70, 0x02, 0x15, 0x58, 0x4e, 0x60} },
+{ 0x0933,	7,	{0x05, 0x12, 0x09, 0xef, 0x80, 0xee, 0x22} },
+{ 0x093a,	2,	{0x8f, 0x4c} },
+{ 0x093c,	16,	{0xe4, 0xf5, 0x4d, 0x75, 0x4e, 0xff, 0x75, 0x4f, 0x12, 0x75, 0x50, 0x6a, 0xab, 0x4e, 0xaa, 0x4f} },
+{ 0x094c,	16,	{0xa9, 0x50, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0xb4, 0x03, 0x1d, 0xaf, 0x4d, 0x05, 0x4d, 0xef} },
+{ 0x095c,	16,	{0xb5, 0x4c, 0x01, 0x22, 0x12, 0x9b, 0x72, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x096c,	14,	{0x4e, 0xff, 0xf5, 0x4f, 0x89, 0x50, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x097a,	1,	{0x22} },
+{ 0x097b,	16,	{0xe4, 0xfe, 0x75, 0x4e, 0xff, 0x75, 0x4f, 0x12, 0x75, 0x50, 0x12, 0xab, 0x4e, 0xaa, 0x4f, 0xa9} },
+{ 0x098b,	16,	{0x50, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x099b,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x9b, 0xe4, 0x85, 0xf0, 0x4c, 0xf5, 0x4d, 0x62, 0x4c} },
+{ 0x09ab,	16,	{0xe5, 0x4c, 0x62, 0x4d, 0xe5, 0x4d, 0x62, 0x4c, 0x29, 0xfd, 0xe5, 0x4c, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x09bb,	14,	{0x4e, 0xff, 0xf5, 0x4f, 0x89, 0x50, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x09c9,	1,	{0x22} },
+{ 0x09ca,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x07, 0x04, 0xe0, 0x44} },
+{ 0x09da,	16,	{0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x09, 0x23, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x09ea,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x09ef,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x09ff,	1,	{0x22} },
+{ 0x0a00,	16,	{0x02, 0x0b, 0xaa, 0x00, 0x02, 0x0b, 0xdd, 0x00, 0x02, 0x0b, 0xc2, 0x00, 0x02, 0x0c, 0x1c, 0x00} },
+{ 0x0a10,	16,	{0x02, 0x0c, 0x06, 0x00, 0x02, 0x0a, 0xf7, 0x00, 0x02, 0x0a, 0xf8, 0x00, 0x02, 0x0a, 0xf9, 0x00} },
+{ 0x0a20,	16,	{0x02, 0x0c, 0x37, 0x00, 0x02, 0x0d, 0x27, 0x00, 0x02, 0x0c, 0x73, 0x00, 0x02, 0x0d, 0x7b, 0x00} },
+{ 0x0a30,	16,	{0x02, 0x0c, 0xaf, 0x00, 0x02, 0x0d, 0xcf, 0x00, 0x02, 0x0c, 0xeb, 0x00, 0x02, 0x0e, 0x23, 0x00} },
+{ 0x0a40,	16,	{0x02, 0x0a, 0xfa, 0x00, 0x02, 0x0a, 0xfc, 0x00, 0x02, 0x0a, 0xfb, 0x00, 0x02, 0x0a, 0xfd, 0x00} },
+{ 0x0a50,	8,	{0x02, 0x0e, 0x77, 0x00, 0x02, 0x0e, 0x8d, 0x00} },
+{ 0x0a58,	16,	{0x53, 0x8e, 0xf7, 0xe5, 0x89, 0x54, 0xf1, 0x44, 0x01, 0xf5, 0x89, 0x75, 0x8c, 0xb1, 0xd2, 0xa9} },
+{ 0x0a68,	16,	{0x75, 0x98, 0x40, 0x75, 0xcb, 0xff, 0x75, 0xca, 0xf3, 0x75, 0xc8, 0x34, 0xe4, 0xff, 0x7f, 0x05} },
+{ 0x0a78,	7,	{0x78, 0x27, 0xe4, 0xf6, 0x08, 0xdf, 0xfc} },
+{ 0x0a7f,	1,	{0x22} },
+{ 0x0a80,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0, 0x00, 0xc0, 0x06, 0xc0} },
+{ 0x0a90,	1,	{0x07} },
+{ 0x0a91,	16,	{0x30, 0x04, 0x16, 0x75, 0x8c, 0xf8, 0x75, 0x8a, 0x30, 0x7f, 0x2f, 0xae, 0x07, 0x1f, 0xee, 0x60} },
+{ 0x0aa1,	16,	{0x3c, 0x90, 0x20, 0x00, 0x74, 0x55, 0xf0, 0x80, 0xf2, 0x75, 0x8c, 0xb1, 0x7f, 0x27, 0xef, 0xd3} },
+{ 0x0ab1,	16,	{0x94, 0x2b, 0x50, 0x09, 0xa8, 0x07, 0xe6, 0x60, 0x01, 0x16, 0x0f, 0x80, 0xf1, 0x90, 0x03, 0x00} },
+{ 0x0ac1,	16,	{0xe0, 0x60, 0x02, 0x14, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x0e, 0x90} },
+{ 0x0ad1,	13,	{0x01, 0xc1, 0xe0, 0x24, 0xff, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x34, 0xff, 0xf0} },
+{ 0x0ade,	15,	{0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0aed,	5,	{0x12, 0x08, 0x90, 0xd3, 0x22} },
+{ 0x0af2,	5,	{0x12, 0x08, 0x19, 0xd3, 0x22} },
+{ 0x0af7,	1,	{0x32} },
+{ 0x0af8,	1,	{0x32} },
+{ 0x0af9,	1,	{0x32} },
+{ 0x0afa,	1,	{0x32} },
+{ 0x0afb,	1,	{0x32} },
+{ 0x0afc,	1,	{0x32} },
+{ 0x0afd,	1,	{0x32} },
+{ 0x0b00,	9,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x0b7d,	16,	{0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x0b8d,	16,	{0xd2, 0x00, 0x75, 0x8e, 0x10, 0xe4, 0x90, 0x7f, 0x92, 0xf0, 0x12, 0x10, 0x0c, 0x12, 0x08, 0xec} },
+{ 0x0b9d,	13,	{0x12, 0x0e, 0xa9, 0x12, 0x90, 0xe6, 0x12, 0x1b, 0x0c, 0x12, 0x0a, 0x58, 0x22} },
+{ 0x0baa,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0bba,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bc2,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0bd2,	11,	{0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0bdd,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0x90} },
+{ 0x0bed,	16,	{0x7f, 0xd8, 0xe0, 0x70, 0x0d, 0x90, 0x7f, 0xd9, 0xe0, 0x70, 0x07, 0xe5, 0x2b, 0x70, 0x03, 0x75} },
+{ 0x0bfd,	9,	{0x2b, 0x14, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c06,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0c16,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c1c,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x30, 0x02, 0x02, 0xd2, 0x06, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c2c,	11,	{0xab, 0x74, 0x08, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c37,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c47,	16,	{0xa9, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x30, 0xe0, 0x13, 0xe5, 0x3b, 0x30, 0xe0, 0x07, 0x90, 0x20} },
+{ 0x0c57,	16,	{0x04, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0c67,	12,	{0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0c73,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0c83,	16,	{0xa9, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x30, 0xe1, 0x13, 0xe5, 0x3b, 0x30, 0xe1, 0x07, 0x90, 0x20} },
+{ 0x0c93,	16,	{0x0c, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0ca3,	12,	{0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0caf,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0cbf,	16,	{0xa9, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x30, 0xe2, 0x13, 0xe5, 0x3b, 0x30, 0xe2, 0x07, 0x90, 0x20} },
+{ 0x0ccf,	16,	{0x14, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0cdf,	12,	{0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ceb,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0cfb,	16,	{0xa9, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x30, 0xe3, 0x13, 0xe5, 0x3b, 0x30, 0xe3, 0x07, 0x90, 0x20} },
+{ 0x0d0b,	16,	{0x1c, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x2b, 0x70, 0x03} },
+{ 0x0d1b,	12,	{0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d27,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0d37,	16,	{0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x02, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0d47,	16,	{0xe0, 0x06, 0x90, 0x7f, 0xc7, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x90, 0x7f, 0xc7} },
+{ 0x0d57,	16,	{0xe0, 0x90, 0x02, 0xf8, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x01, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0d67,	16,	{0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0d77,	4,	{0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d7b,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0d8b,	16,	{0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x04, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0d9b,	16,	{0xe1, 0x06, 0x90, 0x7f, 0xc9, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x90, 0x7f, 0xc9} },
+{ 0x0dab,	16,	{0xe0, 0x90, 0x02, 0xf9, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x09, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0dbb,	16,	{0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0dcb,	4,	{0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dcf,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0ddf,	16,	{0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x08, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0def,	16,	{0xe2, 0x06, 0x90, 0x7f, 0xcb, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x90, 0x7f, 0xcb} },
+{ 0x0dff,	16,	{0xe0, 0x90, 0x02, 0xfa, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x11, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0e0f,	16,	{0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0e1f,	4,	{0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e23,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x0e33,	16,	{0xd0, 0x75, 0xd0, 0x10, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x10, 0xf0, 0xe5, 0x30, 0x20} },
+{ 0x0e43,	16,	{0xe3, 0x06, 0x90, 0x7f, 0xcd, 0xf0, 0x80, 0x16, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x90, 0x7f, 0xcd} },
+{ 0x0e53,	16,	{0xe0, 0x90, 0x02, 0xfb, 0xf0, 0x80, 0x07, 0x90, 0x20, 0x19, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x2b} },
+{ 0x0e63,	16,	{0x70, 0x03, 0x75, 0x2b, 0x14, 0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0} },
+{ 0x0e73,	4,	{0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e77,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xa9, 0x74, 0x80, 0xf0, 0xd0} },
+{ 0x0e87,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e8d,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xaa, 0x74, 0x80, 0xf0, 0x90} },
+{ 0x0e9d,	12,	{0x01, 0xbd, 0x74, 0xff, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0ea9,	16,	{0x90, 0x01, 0x20, 0x12, 0x9d, 0x31, 0x00, 0x00, 0x25, 0x80, 0x90, 0x01, 0x24, 0x74, 0x08, 0xf0} },
+{ 0x0eb9,	16,	{0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x6e, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x13, 0xf0, 0xa3, 0x74} },
+{ 0x0ec9,	16,	{0x11, 0xf0, 0xe4, 0xa3, 0xf0, 0xa3, 0xf0, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff} },
+{ 0x0ed9,	16,	{0xc3, 0x94, 0x04, 0x50, 0x13, 0xef, 0x04, 0xa3, 0xf0, 0x7e, 0x01, 0x7f, 0x1f, 0x12, 0x85, 0xe1} },
+{ 0x0ee9,	16,	{0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xe3, 0xe4, 0xf5, 0x26, 0x90, 0x01, 0x1e, 0xf0, 0x90} },
+{ 0x0ef9,	16,	{0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94, 0x04, 0x50, 0x1a, 0x74, 0xf8, 0x2f, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0f09,	16,	{0x02, 0xf5, 0x83, 0xe4, 0xf0, 0x74, 0x22, 0x2f, 0xf8, 0xe4, 0xf6, 0x90, 0x01, 0x1e, 0xe0, 0x04} },
+{ 0x0f19,	16,	{0xf0, 0x80, 0xdc, 0xe4, 0xf5, 0x30, 0xe5, 0xc0, 0x60, 0x2f, 0x90, 0x01, 0x1e, 0x74, 0x01, 0xf0} },
+{ 0x0f29,	16,	{0x90, 0x01, 0x1e, 0xe0, 0xff, 0xd3, 0x94, 0x04, 0x50, 0x1f, 0xef, 0x14, 0xff, 0x74, 0x01, 0xa8} },
+{ 0x0f39,	16,	{0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x30, 0x7e, 0x01, 0x7f, 0x1e, 0x12, 0x83} },
+{ 0x0f49,	16,	{0x5f, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0x80, 0xd7, 0xe4, 0xf5, 0x3a, 0x90, 0x01, 0x1e, 0xf0} },
+{ 0x0f59,	16,	{0x90, 0x01, 0x1e, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34, 0x20} },
+{ 0x0f69,	16,	{0xf5, 0x83, 0xe0, 0x54, 0xf0, 0xfe, 0x74, 0xc5, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83} },
+{ 0x0f79,	16,	{0xee, 0xf0, 0x74, 0x36, 0x2f, 0xf8, 0xa6, 0x06, 0x74, 0x32, 0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0x2c} },
+{ 0x0f89,	16,	{0x2f, 0xf8, 0xe4, 0xf6, 0x74, 0xfc, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0} },
+{ 0x0f99,	16,	{0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0, 0xe0, 0xb4, 0x04, 0xb6, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f} },
+{ 0x0fa9,	16,	{0xf5, 0x4b, 0x60, 0x5e, 0xe4, 0x90, 0x01, 0x1e, 0xf0, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0xc3, 0x94} },
+{ 0x0fb9,	16,	{0x04, 0x50, 0xe7, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x55, 0x4b} },
+{ 0x0fc9,	16,	{0x60, 0x38, 0x90, 0x01, 0x1e, 0xe0, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4} },
+{ 0x0fd9,	16,	{0x34, 0x20, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4} },
+{ 0x0fe9,	16,	{0x34, 0x20, 0xf5, 0x83, 0xe0, 0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0ff9,	16,	{0x20, 0xf5, 0x83, 0xe0, 0xfe, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x90, 0x01, 0x1e, 0xe0, 0x04, 0xf0} },
+{ 0x1009,	3,	{0x80, 0xa7, 0x22} },
+{ 0x100c,	16,	{0x7b, 0xff, 0x7a, 0x12, 0x79, 0x1b, 0x90, 0x00, 0x04, 0x12, 0x9b, 0x8b, 0xfd, 0x8b, 0x4d, 0x75} },
+{ 0x101c,	16,	{0x4e, 0x12, 0x75, 0x4f, 0x24, 0xe4, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x7f, 0xe0, 0xf0, 0xf5, 0x4b} },
+{ 0x102c,	16,	{0xf5, 0x4c, 0x90, 0x02, 0xae, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f} },
+{ 0x103c,	16,	{0xa9, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0xe4, 0xfc, 0xec, 0x25, 0xe0, 0x24, 0xb4, 0xf5} },
+{ 0x104c,	16,	{0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x0c, 0xbc, 0x10, 0xee, 0xe4, 0x90, 0x7f, 0xdd} },
+{ 0x105c,	16,	{0xf0, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03, 0x02, 0x11, 0xd2, 0xab, 0x4d, 0xaa, 0x4e, 0xa9, 0x4f} },
+{ 0x106c,	16,	{0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0x64, 0x05, 0x60, 0x03, 0x02, 0x11, 0xc1, 0x90, 0x00, 0x03} },
+{ 0x107c,	16,	{0x12, 0x9b, 0x8b, 0x64, 0x01, 0x60, 0x03, 0x02, 0x11, 0x48, 0x90, 0x00, 0x02, 0x12, 0x9b, 0x8b} },
+{ 0x108c,	16,	{0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50, 0x03, 0x02, 0x11, 0x22, 0xec, 0xc3, 0x94, 0x10} },
+{ 0x109c,	16,	{0x40, 0x03, 0x02, 0x11, 0x22, 0xef, 0x30, 0xe7, 0x42, 0xe5, 0x4c, 0xae, 0x4b, 0x78, 0x02, 0xce} },
+{ 0x10ac,	16,	{0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xf0, 0x2c, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5} },
+{ 0x10bc,	16,	{0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe0, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01, 0xa8, 0x06} },
+{ 0x10cc,	16,	{0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe0, 0xf0, 0x90, 0x02, 0xae, 0xe0} },
+{ 0x10dc,	16,	{0x04, 0xf0, 0x90, 0x7f, 0xdd, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x3e, 0xe5, 0x4c, 0xae, 0x4b, 0x78} },
+{ 0x10ec,	16,	{0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0x74, 0xe8, 0x2c, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x10fc,	16,	{0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x90, 0x7f, 0xe1, 0xe0, 0xff, 0xec, 0x24, 0xf8, 0xfe, 0x74, 0x01} },
+{ 0x110c,	16,	{0xa8, 0x06, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x4f, 0x90, 0x7f, 0xe1, 0xf0, 0x90, 0x02} },
+{ 0x111c,	16,	{0xae, 0xe0, 0x04, 0xf0, 0x80, 0x03, 0x7f, 0xff, 0x22, 0x90, 0x00, 0x04, 0x12, 0x9b, 0x8b, 0x25} },
+{ 0x112c,	16,	{0x4c, 0xf5, 0x4c, 0xe4, 0x35, 0x4b, 0xf5, 0x4b, 0x90, 0x00, 0x05, 0x12, 0x9b, 0x8b, 0xfe, 0xe4} },
+{ 0x113c,	16,	{0x25, 0x4c, 0xf5, 0x4c, 0xee, 0x35, 0x4b, 0xf5, 0x4b, 0x02, 0x11, 0xc4, 0xab, 0x4d, 0xaa, 0x4e} },
+{ 0x114c,	16,	{0xa9, 0x4f, 0x90, 0x00, 0x03, 0x12, 0x9b, 0x8b, 0xff, 0x64, 0x02, 0x60, 0x05, 0xef, 0x64, 0x03} },
+{ 0x115c,	16,	{0x70, 0x60, 0x90, 0x00, 0x02, 0x12, 0x9b, 0x8b, 0xff, 0x54, 0x7f, 0xfc, 0xd3, 0x94, 0x07, 0x50} },
+{ 0x116c,	16,	{0x4e, 0xef, 0x30, 0xe7, 0x1e, 0x90, 0x7f, 0xde, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80} },
+{ 0x117c,	16,	{0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xde, 0xf0, 0x90, 0x7f, 0xac, 0xe0, 0x4e} },
+{ 0x118c,	16,	{0xf0, 0x80, 0x35, 0x90, 0x7f, 0xdf, 0xe0, 0xff, 0x74, 0x01, 0xa8, 0x04, 0x08, 0x80, 0x02, 0xc3} },
+{ 0x119c,	16,	{0x33, 0xd8, 0xfc, 0xfe, 0x4f, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xad, 0xe0, 0x4e, 0xf0, 0xec} },
+{ 0x11ac,	16,	{0x25, 0xe0, 0x24, 0xc5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xec, 0xf0, 0x80, 0x09, 0x7f} },
+{ 0x11bc,	16,	{0xff, 0x22, 0x7f, 0xff, 0x22, 0x7f, 0xff, 0x22, 0x74, 0x07, 0x25, 0x4f, 0xf5, 0x4f, 0xe4, 0x35} },
+{ 0x11cc,	16,	{0x4e, 0xf5, 0x4e, 0x02, 0x10, 0x5d, 0x20, 0x03, 0x0d, 0x90, 0x02, 0xae, 0xe0, 0x60, 0x07, 0x90} },
+{ 0x11dc,	8,	{0x7f, 0xae, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0x00} },
+{ 0x11e4,	1,	{0x22} },
+{ 0x11e5,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33} },
+{ 0x11f5,	7,	{0xd8, 0xfc, 0x42, 0x3a, 0x7f, 0x00, 0x22} },
+{ 0x11fc,	3,	{0x00, 0x03, 0x15} },
+{ 0x1200,	16,	{0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40, 0x10, 0x07, 0x01, 0x80, 0x42, 0x00, 0x01, 0x02} },
+{ 0x1210,	16,	{0x03, 0x01, 0x09, 0x02, 0x58, 0x00, 0x01, 0x01, 0x04, 0x80, 0x3c, 0x09, 0x04, 0x00, 0x00, 0x0a} },
+{ 0x1220,	16,	{0xff, 0xff, 0xff, 0x05, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40} },
+{ 0x1230,	16,	{0x00, 0x00, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1240,	16,	{0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1250,	16,	{0x84, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x87, 0x02} },
+{ 0x1260,	16,	{0x40, 0x00, 0x00, 0x07, 0x05, 0x07, 0x02, 0x40, 0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x24, 0x03} },
+{ 0x1270,	16,	{0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x20, 0x00} },
+{ 0x1280,	16,	{0x54, 0x00, 0x65, 0x00, 0x63, 0x00, 0x68, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x1290,	16,	{0x2e, 0x00, 0x18, 0x03, 0x57, 0x00, 0x68, 0x00, 0x69, 0x00, 0x74, 0x00, 0x65, 0x00, 0x48, 0x00} },
+{ 0x12a0,	16,	{0x45, 0x00, 0x41, 0x00, 0x54, 0x00, 0x2d, 0x00, 0x34, 0x00, 0x1a, 0x03, 0x58, 0x00, 0x58, 0x00} },
+{ 0x12b0,	16,	{0x2d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x2d, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00, 0x58, 0x00} },
+{ 0x12c0,	16,	{0x58, 0x00, 0x58, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
+{ 0x12d0,	16,	{0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
+{ 0x12e0,	16,	{0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
+{ 0x12f0,	16,	{0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
+{ 0x1300,	16,	{0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
+{ 0x1310,	2,	{0x00, 0x00} },
+{ 0x1312,	16,	{0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0xc0, 0xd0} },
+{ 0x1322,	16,	{0x75, 0x86, 0x00, 0x75, 0xd0, 0x18, 0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xf5, 0xf0, 0x70, 0x11} },
+{ 0x1332,	16,	{0xd0, 0xd0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0} },
+{ 0x1342,	16,	{0x32, 0x75, 0x86, 0x00, 0x10, 0xf0, 0x0b, 0x10, 0xf1, 0x12, 0x10, 0xf2, 0x19, 0x10, 0xf3, 0x20} },
+{ 0x1352,	16,	{0x80, 0xd4, 0xe5, 0x27, 0x70, 0x03, 0x75, 0x27, 0x14, 0x02, 0x13, 0x7c, 0xe5, 0x28, 0x70, 0x03} },
+{ 0x1362,	16,	{0x75, 0x28, 0x14, 0x02, 0x15, 0x0d, 0xe5, 0x29, 0x70, 0x03, 0x75, 0x29, 0x14, 0x02, 0x16, 0x9e} },
+{ 0x1372,	16,	{0xe5, 0x2a, 0x70, 0x03, 0x75, 0x2a, 0x14, 0x02, 0x18, 0x2f, 0x90, 0x20, 0x02, 0xe0, 0x54, 0x3f} },
+{ 0x1382,	16,	{0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14, 0x60, 0x09, 0x02, 0x13} },
+{ 0x1392,	16,	{0x43, 0x02, 0x14, 0x65, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5, 0x36, 0x02, 0x13, 0x43} },
+{ 0x13a2,	16,	{0x43, 0x82, 0x04, 0xe0, 0x43, 0x2c, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x05} },
+{ 0x13b2,	16,	{0xe0, 0x42, 0x32, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13, 0x43, 0x30, 0xe1, 0x02} },
+{ 0x13c2,	16,	{0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe0, 0x0a, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x04, 0xe0} },
+{ 0x13d2,	16,	{0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74, 0x00, 0xf0, 0x90, 0x20} },
+{ 0x13e2,	16,	{0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86} },
+{ 0x13f2,	16,	{0x90, 0x7e, 0x80, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f} },
+{ 0x1402,	16,	{0xe5, 0xe5, 0x3c, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0} },
+{ 0x1412,	16,	{0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x90} },
+{ 0x1422,	16,	{0x7f, 0xb7, 0xed, 0xf0, 0x90, 0x20, 0x01, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x7f, 0x40} },
+{ 0x1432,	16,	{0x90, 0x7e, 0x80, 0x05, 0x86, 0x90, 0x20, 0x00, 0xe5, 0x84, 0xfe, 0x24, 0x05, 0xfd, 0x8d, 0x84} },
+{ 0x1442,	16,	{0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xef, 0x05} },
+{ 0x1452,	16,	{0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xb7, 0xf0, 0x05, 0x86, 0xa3, 0xe0, 0x54, 0xfe, 0xf0} },
+{ 0x1462,	16,	{0x02, 0x13, 0x43, 0x53, 0x2c, 0xfa, 0xe5, 0x22, 0x60, 0x08, 0x75, 0x22, 0x00, 0xd2, 0xe7, 0xfe} },
+{ 0x1472,	16,	{0x80, 0x0a, 0x90, 0x7f, 0xc7, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x14, 0xff, 0x90, 0x20, 0x50, 0x74} },
+{ 0x1482,	16,	{0x00, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
+{ 0x1492,	16,	{0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7e, 0x40, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0} },
+{ 0x14a2,	16,	{0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0, 0x24, 0x38, 0xf0, 0x05} },
+{ 0x14b2,	16,	{0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60, 0x30, 0x03, 0x03, 0x03} },
+{ 0x14c2,	16,	{0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0} },
+{ 0x14d2,	16,	{0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11, 0x8b, 0x22, 0x90, 0x7f} },
+{ 0x14e2,	16,	{0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80, 0x1b, 0xe0, 0xde, 0xfd} },
+{ 0x14f2,	16,	{0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x90, 0x20, 0x01} },
+{ 0x1502,	16,	{0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xc7, 0xf0, 0x02, 0x13, 0x43, 0x90, 0x20, 0x0a, 0xe0, 0x54} },
+{ 0x1512,	16,	{0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14, 0x60, 0x09, 0x02} },
+{ 0x1522,	16,	{0x13, 0x43, 0x02, 0x15, 0xf6, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5, 0x37, 0x02, 0x13} },
+{ 0x1532,	16,	{0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2d, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82, 0xf8, 0x43, 0x82} },
+{ 0x1542,	16,	{0x05, 0xe0, 0x42, 0x33, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13, 0x43, 0x30, 0xe1} },
+{ 0x1552,	16,	{0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe1, 0x0a, 0x53, 0x82, 0xf8, 0x43, 0x82, 0x04} },
+{ 0x1562,	16,	{0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74, 0x01, 0xf0, 0x90} },
+{ 0x1572,	16,	{0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05} },
+{ 0x1582,	16,	{0x86, 0x90, 0x7e, 0x00, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90} },
+{ 0x1592,	16,	{0x7f, 0xe5, 0xe5, 0x3d, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0} },
+{ 0x15a2,	16,	{0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
+{ 0x15b2,	16,	{0x90, 0x7f, 0xb9, 0xed, 0xf0, 0x90, 0x20, 0x09, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x7f} },
+{ 0x15c2,	16,	{0x40, 0x90, 0x7e, 0x00, 0x05, 0x86, 0x90, 0x20, 0x08, 0xe5, 0x84, 0xfe, 0x24, 0x05, 0xfd, 0x8d} },
+{ 0x15d2,	16,	{0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05, 0x86, 0xdf, 0xef} },
+{ 0x15e2,	16,	{0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xb9, 0xf0, 0x05, 0x86, 0xa3, 0xe0, 0x54, 0xfe} },
+{ 0x15f2,	16,	{0xf0, 0x02, 0x13, 0x43, 0x53, 0x2d, 0xfa, 0xe5, 0x23, 0x60, 0x08, 0x75, 0x23, 0x00, 0xd2, 0xe7} },
+{ 0x1602,	16,	{0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xc9, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x16, 0x90, 0x90, 0x20, 0x50} },
+{ 0x1612,	16,	{0x74, 0x01, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0} },
+{ 0x1622,	16,	{0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0xc0, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84} },
+{ 0x1632,	16,	{0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0, 0x24, 0x38, 0xf0} },
+{ 0x1642,	16,	{0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60, 0x30, 0x03, 0x03} },
+{ 0x1652,	16,	{0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0} },
+{ 0x1662,	16,	{0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11, 0x8b, 0x23, 0x90} },
+{ 0x1672,	16,	{0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80, 0x1b, 0xe0, 0xde} },
+{ 0x1682,	14,	{0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
+{ 0x1690,	16,	{0x90, 0x20, 0x09, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xc9, 0xf0, 0x02, 0x13, 0x43, 0x90, 0x20} },
+{ 0x16a0,	16,	{0x12, 0xe0, 0x54, 0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5, 0x14} },
+{ 0x16b0,	16,	{0x60, 0x09, 0x02, 0x13, 0x43, 0x02, 0x17, 0x87, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0xf5} },
+{ 0x16c0,	16,	{0x38, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2e, 0x01, 0x02, 0x13, 0x43, 0x53, 0x82} },
+{ 0x16d0,	16,	{0xf8, 0x43, 0x82, 0x05, 0xe0, 0x42, 0x34, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02, 0x13} },
+{ 0x16e0,	16,	{0x43, 0x30, 0xe1, 0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe2, 0x0a, 0x53, 0x82, 0xf8} },
+{ 0x16f0,	16,	{0x43, 0x82, 0x04, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50, 0x74} },
+{ 0x1700,	16,	{0x02, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
+{ 0x1710,	16,	{0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x80, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84, 0xf0} },
+{ 0x1720,	16,	{0x05, 0x86, 0x90, 0x7f, 0xe5, 0xe5, 0x3e, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0, 0xf0} },
+{ 0x1730,	16,	{0xf0, 0xf0, 0xf0, 0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58} },
+{ 0x1740,	16,	{0x74, 0x00, 0xf0, 0x90, 0x7f, 0xbb, 0xed, 0xf0, 0x90, 0x20, 0x11, 0xe0, 0x54, 0xfe, 0xf0, 0x02} },
+{ 0x1750,	16,	{0x13, 0x43, 0x7f, 0x40, 0x90, 0x7d, 0x80, 0x05, 0x86, 0x90, 0x20, 0x10, 0xe5, 0x84, 0xfe, 0x24} },
+{ 0x1760,	16,	{0x05, 0xfd, 0x8d, 0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3, 0x05} },
+{ 0x1770,	16,	{0x86, 0xdf, 0xef, 0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xbb, 0xf0, 0x05, 0x86, 0xa3} },
+{ 0x1780,	16,	{0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x53, 0x2e, 0xfa, 0xe5, 0x24, 0x60, 0x08, 0x75, 0x24} },
+{ 0x1790,	16,	{0x00, 0xd2, 0xe7, 0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xcb, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x18, 0x21} },
+{ 0x17a0,	16,	{0x90, 0x20, 0x50, 0x74, 0x02, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0} },
+{ 0x17b0,	16,	{0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x40, 0x05, 0x86, 0xe5, 0x85, 0xf0} },
+{ 0x17c0,	16,	{0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86, 0xe0} },
+{ 0x17d0,	16,	{0x24, 0x38, 0xf0, 0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78, 0x60} },
+{ 0x17e0,	16,	{0x30, 0x03, 0x03, 0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0, 0xe0} },
+{ 0x17f0,	16,	{0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70, 0x11} },
+{ 0x1800,	16,	{0x8b, 0x24, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0, 0x80} },
+{ 0x1810,	16,	{0x1b, 0xe0, 0xde, 0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00} },
+{ 0x1820,	16,	{0xf0, 0x90, 0x20, 0x11, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xcb, 0xf0, 0x02, 0x13, 0x43, 0x90} },
+{ 0x1830,	16,	{0x20, 0x1a, 0xe0, 0x54, 0x3f, 0x20, 0xe2, 0x3a, 0x20, 0xe1, 0x0b, 0x20, 0xe4, 0x0b, 0x20, 0xe5} },
+{ 0x1840,	16,	{0x14, 0x60, 0x09, 0x02, 0x13, 0x43, 0x02, 0x19, 0x18, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0} },
+{ 0x1850,	16,	{0xf5, 0x39, 0x02, 0x13, 0x43, 0x43, 0x82, 0x04, 0xe0, 0x43, 0x2f, 0x01, 0x02, 0x13, 0x43, 0x53} },
+{ 0x1860,	16,	{0x82, 0xf8, 0x43, 0x82, 0x05, 0xe0, 0x42, 0x35, 0x53, 0x82, 0xfb, 0xe0, 0x54, 0xfb, 0xf0, 0x02} },
+{ 0x1870,	16,	{0x13, 0x43, 0x30, 0xe1, 0x02, 0x80, 0xe8, 0xf5, 0x85, 0xe5, 0x3b, 0x30, 0xe3, 0x0a, 0x53, 0x82} },
+{ 0x1880,	16,	{0xf8, 0x43, 0x82, 0x04, 0xe0, 0x54, 0xfe, 0xf0, 0xe5, 0x85, 0x20, 0xe3, 0x56, 0x90, 0x20, 0x50} },
+{ 0x1890,	16,	{0x74, 0x03, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x40, 0xf0} },
+{ 0x18a0,	16,	{0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7d, 0x00, 0x05, 0x86, 0xe5, 0x85, 0xf0, 0xa3, 0xe5, 0x84} },
+{ 0x18b0,	16,	{0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xe5, 0x3f, 0xfd, 0x03, 0x03, 0x03, 0xfe, 0xf0, 0xf0, 0xf0} },
+{ 0x18c0,	16,	{0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xde, 0xf6, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20} },
+{ 0x18d0,	16,	{0x58, 0x74, 0x00, 0xf0, 0x90, 0x7f, 0xbd, 0xed, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x54, 0xfe, 0xf0} },
+{ 0x18e0,	16,	{0x02, 0x13, 0x43, 0x7f, 0x40, 0x90, 0x7d, 0x00, 0x05, 0x86, 0x90, 0x20, 0x18, 0xe5, 0x84, 0xfe} },
+{ 0x18f0,	16,	{0x24, 0x05, 0xfd, 0x8d, 0x84, 0xe0, 0x8e, 0x84, 0x30, 0xe0, 0x09, 0xe0, 0x05, 0x86, 0xf0, 0xa3} },
+{ 0x1900,	16,	{0x05, 0x86, 0xdf, 0xef, 0x05, 0x86, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0x7f, 0xbd, 0xf0, 0x05, 0x86} },
+{ 0x1910,	16,	{0xa3, 0xe0, 0x54, 0xfe, 0xf0, 0x02, 0x13, 0x43, 0x53, 0x2f, 0xfa, 0xe5, 0x25, 0x60, 0x08, 0x75} },
+{ 0x1920,	16,	{0x25, 0x00, 0xd2, 0xe7, 0xfe, 0x80, 0x0a, 0x90, 0x7f, 0xcd, 0xe0, 0xfe, 0x70, 0x03, 0x02, 0x19} },
+{ 0x1930,	16,	{0xb2, 0x90, 0x20, 0x50, 0x74, 0x03, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xe2} },
+{ 0x1940,	16,	{0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xe3, 0x05, 0x86, 0x90, 0x7c, 0xc0, 0x05, 0x86, 0xe5, 0x85} },
+{ 0x1950,	16,	{0xf0, 0xa3, 0xe5, 0x84, 0xf0, 0x05, 0x86, 0x90, 0x7f, 0xe5, 0xee, 0x30, 0xe7, 0x08, 0x05, 0x86} },
+{ 0x1960,	16,	{0xe0, 0x24, 0x38, 0xf0, 0x05, 0x86, 0xee, 0x54, 0x7f, 0xfe, 0x54, 0x07, 0xfb, 0xee, 0x54, 0x78} },
+{ 0x1970,	16,	{0x60, 0x30, 0x03, 0x03, 0x03, 0x30, 0xe3, 0x04, 0x74, 0x07, 0x7b, 0x08, 0xfd, 0xfc, 0xe0, 0xe0} },
+{ 0x1980,	16,	{0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xdd, 0xf6, 0xeb, 0xfe, 0x60, 0x19, 0xec, 0x64, 0x07, 0x70} },
+{ 0x1990,	16,	{0x11, 0x8b, 0x25, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74, 0x00, 0xf0} },
+{ 0x19a0,	16,	{0x80, 0x1b, 0xe0, 0xde, 0xfd, 0x90, 0x7f, 0xe2, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x20, 0x58, 0x74} },
+{ 0x19b0,	16,	{0x00, 0xf0, 0x90, 0x20, 0x19, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0x7f, 0xcd, 0xf0, 0x02, 0x13, 0x43} },
+{ 0x19c0,	1,	{0x32} },
+{ 0x19c1,	4,	{0xad, 0x07, 0xac, 0x06} },
+{ 0x19c5,	16,	{0x79, 0x06, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb} },
+{ 0x19d5,	16,	{0x4a, 0x70, 0x03, 0x02, 0x1b, 0x09, 0xe9, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x1a, 0xdb, 0x90} },
+{ 0x19e5,	16,	{0x19, 0xeb, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x1a, 0xb9, 0x02, 0x1a, 0x71, 0x02, 0x1a, 0x5a, 0x02} },
+{ 0x19f5,	16,	{0x1a, 0x40, 0x02, 0x1a, 0x2f, 0x02, 0x1a, 0x1a, 0x02, 0x1a, 0x00, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x1a05,	16,	{0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6} },
+{ 0x1a15,	16,	{0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x19, 0x8d, 0x82, 0x8c, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x0a} },
+{ 0x1a25,	16,	{0xa3, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x02, 0x1a, 0xdb, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
+{ 0x1a35,	16,	{0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x19, 0x02, 0x1a, 0xdb, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x1a45,	16,	{0x80, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa1, 0x90, 0x7f, 0xa6} },
+{ 0x1a55,	16,	{0xf0, 0x19, 0x02, 0x1a, 0xdb, 0xeb, 0x64, 0x01, 0x4a, 0x70, 0x08, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x1a65,	16,	{0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xf5, 0x54, 0x19, 0x80, 0x6a, 0xed, 0x24, 0x04, 0xf5} },
+{ 0x1a75,	16,	{0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0x64, 0x02, 0x4e, 0x70, 0x08, 0x90, 0x7f} },
+{ 0x1a85,	16,	{0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x19, 0x90, 0x7f, 0xa6, 0xe0, 0xff, 0xed, 0x24, 0x06, 0xf5, 0x82} },
+{ 0x1a95,	16,	{0xe4, 0x3c, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x1aa5,	16,	{0xef, 0xf0, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12} },
+{ 0x1ab5,	16,	{0x9b, 0xb8, 0x80, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xff} },
+{ 0x1ac5,	16,	{0xed, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3c, 0xf5, 0x83, 0xe0, 0xfa, 0xa3, 0xe0, 0xf5, 0x82, 0x8a} },
+{ 0x1ad5,	16,	{0x83, 0xef, 0xf0, 0x7f, 0x08, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x54, 0x30, 0xe0, 0xf7, 0x30} },
+{ 0x1ae5,	16,	{0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xe9, 0xd3, 0x94, 0x02, 0x50, 0x03, 0x02} },
+{ 0x1af5,	16,	{0x19, 0xc7, 0xe5, 0x54, 0x30, 0xe1, 0x03, 0x02, 0x19, 0xc7, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40} },
+{ 0x1b05,	6,	{0xf0, 0x7f, 0x07, 0x22, 0x7f, 0x08} },
+{ 0x1b0b,	1,	{0x22} },
+{ 0x1b0c,	16,	{0x7f, 0x05, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x02, 0x7d, 0xff, 0x12, 0x81, 0xe0, 0x7f, 0x05} },
+{ 0x1b1c,	13,	{0x7e, 0x00, 0x12, 0x09, 0x23, 0x7f, 0x03, 0x7d, 0xff, 0x12, 0x81, 0xe0, 0x22} },
+{ 0x1b29,	16,	{0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0} },
+{ 0x8000,	4,	{0x8e, 0x54, 0x8f, 0x55} },
+{ 0x8004,	16,	{0x75, 0x56, 0x03, 0xe5, 0x55, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xfe} },
+{ 0x8014,	16,	{0xa3, 0xe0, 0x4e, 0x70, 0x03, 0x02, 0x81, 0x0e, 0xe5, 0x56, 0x60, 0x4e, 0x14, 0x60, 0x38, 0x14} },
+{ 0x8024,	16,	{0x60, 0x20, 0x14, 0x60, 0x03, 0x02, 0x80, 0xb2, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
+{ 0x8034,	16,	{0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90, 0x7f, 0xa6, 0xf0} },
+{ 0x8044,	16,	{0x80, 0x6c, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0xc3, 0x94, 0x20, 0x40, 0x09, 0xa3, 0xa3} },
+{ 0x8054,	16,	{0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x57, 0x15, 0x56, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3} },
+{ 0x8064,	16,	{0xa3, 0xe0, 0xa3, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x44, 0xe5, 0x55, 0x24, 0x06, 0xf5, 0x82} },
+{ 0x8074,	16,	{0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5} },
+{ 0x8084,	16,	{0x83, 0xe0, 0x90, 0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe5, 0x55, 0x24} },
+{ 0x8094,	16,	{0x04, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0x74, 0xff, 0xf5, 0xf0, 0x12, 0x9b, 0xb8, 0x85} },
+{ 0x80a4,	16,	{0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xb8, 0x90, 0x7f} },
+{ 0x80b4,	16,	{0xa5, 0xe0, 0xf5, 0x57, 0x30, 0xe0, 0xf7, 0x30, 0xe2, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06} },
+{ 0x80c4,	16,	{0x22, 0xe5, 0x57, 0x20, 0xe1, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22} },
+{ 0x80d4,	16,	{0xe5, 0x56, 0x70, 0x31, 0x7f, 0x01, 0x7e, 0x00, 0x12, 0x09, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x80e4,	16,	{0x80, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x25, 0xe0, 0x44, 0xa0, 0x90} },
+{ 0x80f4,	16,	{0x7f, 0xa6, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xf5, 0x57, 0x30, 0xe0, 0xf7, 0x30, 0xe1, 0xd5, 0x75} },
+{ 0x8104,	12,	{0x56, 0x03, 0x02, 0x80, 0x07, 0x15, 0x56, 0x02, 0x80, 0x07, 0x7f, 0x08} },
+{ 0x8110,	1,	{0x22} },
+{ 0x8111,	2,	{0xac, 0x07} },
+{ 0x8113,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xec, 0x25, 0xe0, 0x44, 0x41, 0x90, 0x7f, 0xa6, 0xf0} },
+{ 0x8123,	16,	{0x7b, 0x3c, 0xaf, 0x03, 0x1b, 0xef, 0x70, 0x16, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90} },
+{ 0x8133,	16,	{0x7f, 0xa6, 0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x60, 0xd4, 0x80, 0xf8, 0x90, 0x7f} },
+{ 0x8143,	16,	{0xa5, 0xe0, 0xfd, 0x30, 0xe0, 0xdc, 0x20, 0xe1, 0x09, 0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f} },
+{ 0x8153,	16,	{0xf9, 0x22, 0xed, 0x30, 0xe2, 0x0c, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f} },
+{ 0x8163,	16,	{0xfa, 0x22, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0x7b, 0x1e} },
+{ 0x8173,	16,	{0xaf, 0x03, 0x1b, 0xef, 0x70, 0x16, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6} },
+{ 0x8183,	16,	{0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x60, 0x86, 0x80, 0xf8, 0x90, 0x7f, 0xa5, 0xe0} },
+{ 0x8193,	16,	{0xfd, 0x20, 0xe0, 0xdc, 0x7b, 0x3c, 0xaf, 0x03, 0x1b, 0xef, 0x70, 0x19, 0x90, 0x7f, 0xa5, 0xe0} },
+{ 0x81a3,	16,	{0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0x7d, 0x32, 0xaf, 0x05, 0x1d, 0xef, 0x70, 0x03} },
+{ 0x81b3,	16,	{0x02, 0x81, 0x13, 0x80, 0xf5, 0x90, 0x7f, 0xa5, 0xe0, 0xfd, 0x30, 0xe0, 0xd9, 0x30, 0xe2, 0x09} },
+{ 0x81c3,	16,	{0xe0, 0x44, 0x40, 0xf0, 0x7e, 0xff, 0x7f, 0xfa, 0x22, 0xc2, 0xaf, 0x90, 0x7f, 0xa5, 0xe0, 0x44} },
+{ 0x81d3,	12,	{0x40, 0xf0, 0x90, 0x7f, 0xa6, 0xe0, 0xfd, 0xd2, 0xaf, 0xff, 0x7e, 0x00} },
+{ 0x81df,	1,	{0x22} },
+{ 0x81e0,	2,	{0xae, 0x07} },
+{ 0x81e2,	16,	{0x7c, 0x02, 0xec, 0x14, 0x60, 0x15, 0x14, 0x70, 0x1e, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0} },
+{ 0x81f2,	16,	{0xee, 0x25, 0xe0, 0x44, 0x40, 0x90, 0x7f, 0xa6, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xa6, 0xed, 0xf0} },
+{ 0x8202,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x90, 0x7f, 0xa5, 0xe0, 0xfb, 0x30, 0xe0, 0xf8, 0xbc} },
+{ 0x8212,	16,	{0x02, 0x0a, 0x20, 0xe1, 0x07, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x07, 0x22, 0xeb, 0x30, 0xe2, 0x0a} },
+{ 0x8222,	14,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x06, 0x22, 0xdc, 0xb6, 0x7f, 0x08} },
+{ 0x8230,	1,	{0x22} },
+{ 0x8231,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc2, 0xa9, 0x90, 0x03, 0x00, 0x74, 0x19, 0xf0, 0xd2, 0xa9} },
+{ 0x8241,	15,	{0x53, 0x91, 0x7f, 0x90, 0x01, 0xc4, 0xe4, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x8250,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xf5} },
+{ 0x8260,	16,	{0x83, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x5e, 0x74, 0xbf} },
+{ 0x8270,	16,	{0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x44, 0x10, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3} },
+{ 0x8280,	16,	{0xa3, 0xa3, 0xe4, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xf0, 0xf9, 0xed, 0x60, 0x1d, 0x74, 0x01} },
+{ 0x8290,	16,	{0x7e, 0x00, 0xa8, 0x07, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0xe4} },
+{ 0x82a0,	16,	{0xef, 0x55, 0x3b, 0x60, 0x04, 0x79, 0x09, 0x80, 0x02, 0x79, 0x0d, 0x8b, 0x82, 0x8a, 0x83, 0xa3} },
+{ 0x82b0,	16,	{0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x8b, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xe0, 0x54, 0xef, 0xf0, 0x8b} },
+{ 0x82c0,	16,	{0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x5e, 0xf0, 0xae, 0x02, 0xaf, 0x03, 0x8f, 0x82, 0x8e} },
+{ 0x82d0,	4,	{0x83, 0xa3, 0xe9, 0xf0} },
+{ 0x82d4,	1,	{0x22} },
+{ 0x82d5,	4,	{0x8f, 0x5e, 0x8d, 0x5f} },
+{ 0x82d9,	16,	{0xe4, 0xf5, 0x60, 0x74, 0x3c, 0x2f, 0xf8, 0x76, 0x08, 0xe5, 0x5e, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
+{ 0x82e9,	16,	{0x02, 0xf5, 0x82, 0xe4, 0x34, 0x03, 0xf5, 0x83, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe} },
+{ 0x82f9,	16,	{0xa3, 0xe0, 0xff, 0x7b, 0x80, 0x7a, 0x25, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x9c, 0xea, 0x50} },
+{ 0x8309,	16,	{0x3c, 0xe5, 0x5e, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34, 0x03, 0xf5, 0x83} },
+{ 0x8319,	16,	{0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x96, 0x78} },
+{ 0x8329,	16,	{0x00, 0xc3, 0x12, 0x9c, 0xea, 0x40, 0x0c, 0x75, 0x60, 0x40, 0x74, 0x3c, 0x25, 0x5e, 0xf8, 0x76} },
+{ 0x8339,	16,	{0x10, 0x80, 0x0a, 0x75, 0x60, 0x80, 0x74, 0x3c, 0x25, 0x5e, 0xf8, 0x76, 0x38, 0xe5, 0x60, 0x45} },
+{ 0x8349,	16,	{0x5f, 0x44, 0x01, 0xff, 0xe5, 0x5e, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x8359,	5,	{0x20, 0xf5, 0x83, 0xef, 0xf0} },
+{ 0x835e,	1,	{0x22} },
+{ 0x835f,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x54, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x836f,	16,	{0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x55, 0x8f, 0x56, 0xe5, 0x54, 0x25, 0xe0, 0x24, 0xc6, 0xf5} },
+{ 0x837f,	16,	{0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x0f, 0xe5, 0x54, 0x25, 0xe0, 0x24, 0xc7} },
+{ 0x838f,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x74, 0x22, 0x25, 0x54, 0xf8, 0xe4, 0xf6} },
+{ 0x839f,	16,	{0xe5, 0x56, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x55, 0xf5, 0x83, 0xe0, 0x44, 0x03, 0xf0, 0xaf} },
+{ 0x83af,	16,	{0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0xaf, 0x54, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x85, 0x56, 0x82} },
+{ 0x83bf,	16,	{0x85, 0x55, 0x83, 0xa3, 0xa3, 0xe0, 0x20, 0xe0, 0x22, 0xe0, 0xff, 0xe5, 0x56, 0x24, 0x05, 0xf5} },
+{ 0x83cf,	16,	{0x82, 0xe4, 0x35, 0x55, 0xf5, 0x83, 0xe0, 0xe5, 0x56, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x55} },
+{ 0x83df,	16,	{0xf5, 0x83, 0xe0, 0xff, 0xaf, 0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x74, 0xf8, 0x25, 0x54, 0xf5} },
+{ 0x83ef,	16,	{0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x54, 0x25, 0xe0, 0xff, 0xc3, 0x74, 0x0c} },
+{ 0x83ff,	16,	{0x9f, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xaf, 0x82, 0xfe} },
+{ 0x840f,	16,	{0xe5, 0x54, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xee, 0xf0, 0xa3} },
+{ 0x841f,	16,	{0xef, 0xf0, 0xaf, 0x54, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42} },
+{ 0x842f,	3,	{0x30, 0x7f, 0x00} },
+{ 0x8432,	1,	{0x22} },
+{ 0x8433,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x54, 0xff, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0x74, 0xf8} },
+{ 0x8443,	16,	{0x25, 0x54, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x54, 0x75, 0xf0, 0x08} },
+{ 0x8453,	16,	{0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x56, 0x8f, 0x57, 0xf5, 0x83} },
+{ 0x8463,	16,	{0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf} },
+{ 0x8473,	16,	{0x54, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0xe5, 0x57, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x56, 0xf5} },
+{ 0x8483,	16,	{0x83, 0xe0, 0x30, 0xe0, 0x09, 0x85, 0x57, 0x82, 0x85, 0x56, 0x83, 0xe0, 0xf5, 0x55, 0xaf, 0x54} },
+{ 0x8493,	16,	{0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4, 0x52, 0x30, 0xe5, 0x54} },
+{ 0x84a3,	16,	{0x25, 0xe0, 0x24, 0xc6, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x0f, 0xe5} },
+{ 0x84b3,	16,	{0x54, 0x25, 0xe0, 0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x7f, 0x00} },
+{ 0x84c3,	1,	{0x22} },
+{ 0x84c4,	4,	{0x8e, 0x54, 0x8f, 0x55} },
+{ 0x84c8,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x56, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82} },
+{ 0x84d8,	16,	{0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x54, 0x03, 0x70, 0x23, 0x85, 0x55, 0x82, 0x8e, 0x83, 0xa3} },
+{ 0x84e8,	16,	{0xe0, 0x30, 0xe0, 0x07, 0xaf, 0x56, 0x7d, 0x02, 0x12, 0x82, 0xd5, 0x85, 0x55, 0x82, 0x85, 0x54} },
+{ 0x84f8,	15,	{0x83, 0xa3, 0xe0, 0x30, 0xe1, 0x07, 0xaf, 0x56, 0x7d, 0x04, 0x12, 0x82, 0xd5, 0x7f, 0x00} },
+{ 0x8507,	1,	{0x22} },
+{ 0x8508,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0xa3, 0xa3, 0xa3, 0xe0, 0xfc, 0xed} },
+{ 0x8518,	16,	{0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x8528,	16,	{0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0} },
+{ 0x8538,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0xe0, 0xfd, 0xec, 0x6d, 0xd0} },
+{ 0x8548,	16,	{0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f} },
+{ 0x8558,	16,	{0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82} },
+{ 0x8568,	16,	{0x8e, 0x83, 0xa3, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0} },
+{ 0x8578,	16,	{0xfc, 0xed, 0x6c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xc0, 0x83, 0xc0} },
+{ 0x8588,	16,	{0x82, 0xe0, 0xfd, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xff, 0xed, 0x6f, 0xd0, 0x82, 0xd0} },
+{ 0x8598,	3,	{0x83, 0xf0, 0x22} },
+{ 0x859b,	16,	{0x79, 0x0d, 0x8e, 0x54, 0x8f, 0x55, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x0d, 0xa4, 0x24} },
+{ 0x85ab,	16,	{0xf4, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xaf, 0x82, 0xfe, 0xad, 0x01, 0x19, 0xed, 0x60, 0x24, 0x0f} },
+{ 0x85bb,	16,	{0xef, 0xac, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe0, 0xfd, 0x05, 0x55, 0xe5} },
+{ 0x85cb,	16,	{0x55, 0xaa, 0x54, 0x70, 0x02, 0x05, 0x54, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xe0, 0x6d, 0x60, 0xd9} },
+{ 0x85db,	5,	{0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x85e0,	1,	{0x22} },
+{ 0x85e1,	4,	{0x8e, 0x54, 0x8f, 0x55} },
+{ 0x85e5,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xf5, 0x5b, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82} },
+{ 0x85f5,	16,	{0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x5c, 0x8f, 0x5d, 0xaa, 0x06, 0xa9, 0x55, 0x7b, 0x01, 0xc0} },
+{ 0x8605,	16,	{0x03, 0xc0, 0x01, 0xe5, 0x5b, 0x75, 0xf0, 0x0d, 0xa4, 0x24, 0x01, 0xf9, 0x74, 0x03, 0x35, 0xf0} },
+{ 0x8615,	16,	{0xa8, 0x01, 0xfc, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x0d, 0x12, 0x9b, 0x49} },
+{ 0x8625,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8635,	16,	{0xe0, 0xff, 0x7b, 0x08, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xd3, 0x12, 0x9c, 0xea, 0x40, 0x10} },
+{ 0x8645,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0x12, 0x9d, 0x31, 0x00, 0x00, 0x00, 0x08, 0x80, 0x2e} },
+{ 0x8655,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8665,	16,	{0xe0, 0xff, 0x7b, 0x00, 0x7a, 0x08, 0x79, 0x07, 0x78, 0x00, 0xc3, 0x12, 0x9c, 0xea, 0x50, 0x0e} },
+{ 0x8675,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0x12, 0x9d, 0x31, 0x00, 0x07, 0x08, 0x00, 0x85, 0x55} },
+{ 0x8685,	16,	{0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xa3, 0xe0, 0xfb} },
+{ 0x8695,	16,	{0x7f, 0x00, 0x7e, 0x50, 0x7d, 0x46, 0x7c, 0x00, 0x12, 0x9c, 0x58, 0x8f, 0x59, 0x8e, 0x58, 0x8d} },
+{ 0x86a5,	16,	{0x57, 0x8c, 0x56, 0x7b, 0x0a, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0x12, 0x9c, 0x58, 0xaf, 0x03} },
+{ 0x86b5,	16,	{0x8f, 0x5a, 0xaf, 0x59, 0xae, 0x58, 0xad, 0x57, 0xac, 0x56, 0x7b, 0x0a, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x86c5,	16,	{0x78, 0x00, 0x12, 0x9c, 0x58, 0x8f, 0x59, 0x8e, 0x58, 0x8d, 0x57, 0x8c, 0x56, 0xe5, 0x5a, 0xc3} },
+{ 0x86d5,	16,	{0x94, 0x05, 0x40, 0x15, 0xe5, 0x59, 0x24, 0x01, 0xf5, 0x59, 0xe4, 0x35, 0x58, 0xf5, 0x58, 0xe4} },
+{ 0x86e5,	16,	{0x35, 0x57, 0xf5, 0x57, 0xe4, 0x35, 0x56, 0xf5, 0x56, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3} },
+{ 0x86f5,	16,	{0xe4, 0xf0, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85} },
+{ 0x8705,	16,	{0x5d, 0x82, 0x85, 0x5c, 0x83, 0xe5, 0x59, 0xf0, 0xaf, 0x59, 0xae, 0x58, 0xad, 0x57, 0xac, 0x56} },
+{ 0x8715,	16,	{0x78, 0x08, 0x12, 0x9c, 0xfb, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xef, 0xf0, 0x85, 0x5d} },
+{ 0x8725,	16,	{0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xe4, 0xf5, 0x5a, 0xe5, 0x55} },
+{ 0x8735,	16,	{0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xb4, 0x62, 0x05, 0x43, 0x5a} },
+{ 0x8745,	16,	{0x0a, 0x80, 0x10, 0xef, 0xb4, 0x72, 0x05, 0x43, 0x5a, 0x08, 0x80, 0x07, 0xef, 0xb4, 0x74, 0x03} },
+{ 0x8755,	16,	{0x43, 0x5a, 0x02, 0xe5, 0x55, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff} },
+{ 0x8765,	16,	{0x30, 0xe3, 0x03, 0x43, 0x5a, 0x80, 0xef, 0x30, 0xe7, 0x12, 0x43, 0x5a, 0x40, 0xe5, 0x5d, 0x24} },
+{ 0x8775,	16,	{0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x55, 0x24, 0x0b} },
+{ 0x8785,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0x20, 0xe1, 0x03, 0x30, 0xe4, 0x23, 0xaf} },
+{ 0x8795,	16,	{0x5b, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x42, 0x3b, 0xe5, 0x5d} },
+{ 0x87a5,	16,	{0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0xe4, 0xf5, 0x5a} },
+{ 0x87b5,	16,	{0x80, 0x10, 0xaf, 0x5b, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf4} },
+{ 0x87c5,	16,	{0x52, 0x3b, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0x74, 0xbf, 0xf0, 0x85, 0x5d} },
+{ 0x87d5,	16,	{0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xe4, 0xf0, 0xe5, 0x5a, 0xf0, 0xe5, 0x55, 0x24, 0x0a, 0xf5} },
+{ 0x87e5,	16,	{0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x87f5,	16,	{0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x55, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83} },
+{ 0x8805,	16,	{0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5} },
+{ 0x8815,	16,	{0x55, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x06} },
+{ 0x8825,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x55, 0x24, 0x09, 0xf5, 0x82, 0xe4} },
+{ 0x8835,	16,	{0x35, 0x54, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x5d, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5} },
+{ 0x8845,	16,	{0x83, 0xef, 0xf0, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe4, 0xf0, 0x85, 0x5d} },
+{ 0x8855,	16,	{0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xf0, 0xaf, 0x5b, 0x7d, 0x06, 0x12, 0x82, 0xd5, 0x75, 0x5a} },
+{ 0x8865,	16,	{0x08, 0xe5, 0x55, 0x24, 0x0c, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x43} },
+{ 0x8875,	16,	{0x5a, 0x10, 0xe5, 0x5d, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x5c, 0xf5, 0x83, 0xe0, 0x54, 0x03} },
+{ 0x8885,	16,	{0x45, 0x5a, 0xf0, 0xe5, 0x55, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5, 0x83, 0xe0, 0x14} },
+{ 0x8895,	16,	{0xff, 0x25, 0xe0, 0x25, 0xe0, 0xff, 0xe5, 0x55, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x54, 0xf5} },
+{ 0x88a5,	16,	{0x83, 0xe0, 0x24, 0xfb, 0x4f, 0xf5, 0x5a, 0xe5, 0x55, 0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x54} },
+{ 0x88b5,	16,	{0xf5, 0x83, 0xe0, 0x24, 0xd0, 0x60, 0x15, 0x14, 0x60, 0x17, 0x24, 0xc2, 0x60, 0x09, 0x24, 0x0a} },
+{ 0x88c5,	16,	{0x70, 0x12, 0x43, 0x5a, 0x18, 0x80, 0x0d, 0x43, 0x5a, 0x08, 0x80, 0x08, 0x43, 0x5a, 0x38, 0x80} },
+{ 0x88d5,	16,	{0x03, 0x43, 0x5a, 0x28, 0x85, 0x5d, 0x82, 0x85, 0x5c, 0x83, 0xa3, 0xa3, 0xa3, 0xe5, 0x5a, 0xf0} },
+{ 0x88e5,	9,	{0xaf, 0x5b, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x7f, 0x00} },
+{ 0x88ee,	1,	{0x22} },
+{ 0x88ef,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x14, 0xff, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4} },
+{ 0x88ff,	16,	{0x34, 0x20, 0xad, 0x82, 0xfc, 0x90, 0x01, 0x2c, 0x74, 0x08, 0xf0, 0xef, 0x04, 0xa3, 0xf0, 0xe4} },
+{ 0x890f,	16,	{0xa3, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5} },
+{ 0x891f,	16,	{0x83, 0xe0, 0x90, 0x01, 0x2f, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0xf5, 0x82} },
+{ 0x892f,	16,	{0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x1e, 0x90, 0x01, 0x30, 0xf0, 0x74, 0x2c, 0x2f, 0xf8} },
+{ 0x893f,	16,	{0xe6, 0xa3, 0xf0, 0x74, 0x01, 0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x54} },
+{ 0x894f,	16,	{0x7f, 0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xe5, 0x54, 0x5f} },
+{ 0x895f,	16,	{0x90, 0x01, 0x32, 0xf0, 0x7e, 0x01, 0x7f, 0x2c, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e} },
+{ 0x896f,	11,	{0x00, 0x75, 0x5d, 0x00, 0x7d, 0x07, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x897a,	1,	{0x22} },
+{ 0x897b,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x898b,	16,	{0xaf, 0x82, 0xfe, 0x90, 0x01, 0x33, 0x74, 0x0a, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xe5, 0x82, 0x24} },
+{ 0x899b,	16,	{0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x90, 0x01, 0x34, 0xf0, 0x7e, 0x01, 0x7f} },
+{ 0x89ab,	16,	{0x33, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x02, 0x12} },
+{ 0x89bb,	4,	{0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x89bf,	1,	{0x22} },
+{ 0x89c0,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x89d0,	16,	{0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x89e0,	16,	{0xf5, 0x83, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x89f0,	11,	{0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0xf0, 0x7f, 0x00} },
+{ 0x89fb,	1,	{0x22} },
+{ 0x89fc,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x8a0c,	16,	{0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0f, 0xed, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x3c} },
+{ 0x8a1c,	16,	{0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xae, 0x04, 0xaf, 0x05, 0xef, 0x24, 0x04, 0xf5} },
+{ 0x8a2c,	11,	{0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x00} },
+{ 0x8a37,	1,	{0x22} },
+{ 0x8a38,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0xf8, 0xf5, 0x82, 0xe4, 0x34, 0x1f} },
+{ 0x8a48,	16,	{0xad, 0x82, 0xfc, 0x8f, 0x82, 0xa3, 0xe0, 0x60, 0x0d, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3} },
+{ 0x8a58,	16,	{0xe0, 0x44, 0x40, 0xf0, 0x80, 0x0f, 0xae, 0x04, 0xaf, 0x05, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3} },
+{ 0x8a68,	7,	{0xa3, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x00} },
+{ 0x8a6f,	1,	{0x22} },
+{ 0x8a70,	4,	{0x8e, 0x54, 0x8f, 0x55} },
+{ 0x8a74,	16,	{0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xe0, 0xf5, 0x58, 0x8f, 0x82, 0x8e, 0x83, 0xe0, 0x24, 0xfe, 0x60} },
+{ 0x8a84,	16,	{0x16, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x28, 0x24, 0x03, 0x70, 0x2e, 0x7e, 0x7e, 0x7f, 0x80, 0x75} },
+{ 0x8a94,	16,	{0x56, 0x7e, 0x75, 0x57, 0x80, 0x80, 0x22, 0x7e, 0x7e, 0x7f, 0x00, 0x75, 0x56, 0x7e, 0x75, 0x57} },
+{ 0x8aa4,	16,	{0x00, 0x80, 0x16, 0x7e, 0x7d, 0x7f, 0x80, 0x75, 0x56, 0x7d, 0x75, 0x57, 0x80, 0x80, 0x0a, 0x7e} },
+{ 0x8ab4,	16,	{0x7d, 0x7f, 0x00, 0x75, 0x56, 0x7d, 0x75, 0x57, 0x00, 0xe5, 0x58, 0x70, 0x20, 0x85, 0x57, 0x82} },
+{ 0x8ac4,	16,	{0x85, 0x56, 0x83, 0x74, 0xff, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
+{ 0x8ad4,	16,	{0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x80, 0x4d, 0xe5, 0x55, 0x24} },
+{ 0x8ae4,	16,	{0x02, 0xff, 0xe4, 0x35, 0x54, 0xfe, 0xe5, 0x58, 0x60, 0x23, 0x0f, 0xef, 0xac, 0x06, 0x70, 0x01} },
+{ 0x8af4,	16,	{0x0e, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe0, 0xfd, 0x05, 0x57, 0xe5, 0x57, 0xaa, 0x56, 0x70, 0x02} },
+{ 0x8b04,	16,	{0x05, 0x56, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xed, 0xf0, 0x15, 0x58, 0x80, 0xd9, 0x85, 0x55, 0x82} },
+{ 0x8b14,	16,	{0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x25, 0xe0, 0x24} },
+{ 0x8b24,	12,	{0xb5, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x7f, 0x00} },
+{ 0x8b30,	1,	{0x22} },
+{ 0x8b31,	16,	{0xef, 0x24, 0x05, 0xf5, 0x55, 0xe4, 0x3e, 0xf5, 0x54, 0x90, 0x01, 0x35, 0x74, 0x07, 0xf0, 0x90} },
+{ 0x8b41,	16,	{0x01, 0x7a, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x36, 0xf0, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3} },
+{ 0x8b51,	16,	{0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0x8e, 0x56, 0xf5, 0x57, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8b61,	16,	{0xe0, 0x24, 0x9e, 0x60, 0x61, 0x24, 0xf9, 0x60, 0x0e, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8c, 0x12} },
+{ 0x8b71,	16,	{0x24, 0x14, 0x60, 0x03, 0x02, 0x8c, 0x5e, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe} },
+{ 0x8b81,	16,	{0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f, 0xf5, 0x59, 0x74, 0x01, 0x9e, 0xf5, 0x58, 0xd3, 0xe5, 0x59} },
+{ 0x8b91,	16,	{0x94, 0x40, 0xe5, 0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x40, 0xd3, 0xe5} },
+{ 0x8ba1,	16,	{0x57, 0x95, 0x59, 0xe5, 0x56, 0x95, 0x58, 0x50, 0x03, 0x02, 0x8c, 0x61, 0xae, 0x58, 0xaf, 0x59} },
+{ 0x8bb1,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e} },
+{ 0x8bc1,	16,	{0x56, 0xf5, 0x57, 0x02, 0x8c, 0x61, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3} },
+{ 0x8bd1,	16,	{0xe0, 0xff, 0xc3, 0x74, 0x30, 0x9f, 0xf5, 0x59, 0xe4, 0x9e, 0xf5, 0x58, 0xd3, 0xe5, 0x59, 0x94} },
+{ 0x8be1,	16,	{0x10, 0xe5, 0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x10, 0xd3, 0xe5, 0x57} },
+{ 0x8bf1,	16,	{0x95, 0x59, 0xe5, 0x56, 0x95, 0x58, 0x40, 0x68, 0xae, 0x58, 0xaf, 0x59, 0x85, 0x55, 0x82, 0x85} },
+{ 0x8c01,	16,	{0x54, 0x83, 0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x56, 0xf5, 0x57, 0x80} },
+{ 0x8c11,	16,	{0x4f, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0xe4, 0x9f} },
+{ 0x8c21,	16,	{0xf5, 0x59, 0xe4, 0x9e, 0xf5, 0x58, 0x45, 0x59, 0x60, 0x0b, 0xd3, 0xe5, 0x59, 0x94, 0x40, 0xe5} },
+{ 0x8c31,	16,	{0x58, 0x94, 0x00, 0x40, 0x06, 0x75, 0x58, 0x00, 0x75, 0x59, 0x40, 0xd3, 0xe5, 0x57, 0x95, 0x59} },
+{ 0x8c41,	16,	{0xe5, 0x56, 0x95, 0x58, 0x40, 0x17, 0xae, 0x58, 0xaf, 0x59, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8c51,	16,	{0xa3, 0xa3, 0xa3, 0xee, 0xf0, 0xfe, 0xa3, 0xef, 0xf0, 0x8e, 0x56, 0xf5, 0x57, 0x7f, 0x01, 0x22} },
+{ 0x8c61,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xe0, 0x24, 0x9e, 0x70, 0x03, 0x02, 0x8d, 0x21, 0x24, 0xf9} },
+{ 0x8c71,	16,	{0x60, 0x58, 0x24, 0xf1, 0x70, 0x03, 0x02, 0x8d, 0x71, 0x24, 0x14, 0x60, 0x03, 0x02, 0x8d, 0xb5} },
+{ 0x8c81,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xd3, 0x94, 0xff, 0xee} },
+{ 0x8c91,	16,	{0x94, 0x00, 0x40, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x75, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57} },
+{ 0x8ca1,	16,	{0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x70, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x75, 0xe0} },
+{ 0x8cb1,	16,	{0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b} },
+{ 0x8cc1,	16,	{0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83} },
+{ 0x8cd1,	16,	{0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x80, 0xee, 0x94, 0x00, 0x50, 0x03, 0x02, 0x8d} },
+{ 0x8ce1,	16,	{0xb5, 0xd3, 0xef, 0x94, 0xff, 0xee, 0x94, 0x00, 0x40, 0x03, 0x02, 0x8d, 0xb5, 0x90, 0x01, 0x76} },
+{ 0x8cf1,	16,	{0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x70, 0x03, 0x02} },
+{ 0x8d01,	16,	{0x8d, 0xb5, 0x90, 0x01, 0x76, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a} },
+{ 0x8d11,	16,	{0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd2} },
+{ 0x8d21,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xc3, 0x94, 0x20, 0xee} },
+{ 0x8d31,	16,	{0x94, 0x00, 0x50, 0x03, 0x02, 0x8d, 0xb5, 0xd3, 0xef, 0x94, 0x2f, 0xee, 0x94, 0x00, 0x50, 0x74} },
+{ 0x8d41,	16,	{0x90, 0x01, 0x77, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e} },
+{ 0x8d51,	16,	{0x60, 0x62, 0x90, 0x01, 0x77, 0xe0, 0xff, 0x04, 0xf0, 0xa8, 0x07, 0xe6, 0xff, 0x90, 0x01, 0x7a} },
+{ 0x8d61,	16,	{0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xef, 0xf0, 0x80, 0xd5} },
+{ 0x8d71,	16,	{0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0x01, 0x78, 0xcf, 0xf0} },
+{ 0x8d81,	16,	{0xa3, 0xef, 0xf0, 0xe5, 0x57, 0x15, 0x57, 0xae, 0x56, 0x70, 0x02, 0x15, 0x56, 0x4e, 0x60, 0x24} },
+{ 0x8d91,	16,	{0x90, 0x01, 0x78, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0} },
+{ 0x8da1,	16,	{0xff, 0x90, 0x01, 0x7a, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83} },
+{ 0x8db1,	16,	{0xef, 0xf0, 0x80, 0xcf, 0x7e, 0x01, 0x7f, 0x35, 0x85, 0x55, 0x82, 0x85, 0x54, 0x83, 0xa3, 0xa3} },
+{ 0x8dc1,	16,	{0xa3, 0xe0, 0xa3, 0xe0, 0x04, 0xfd, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75} },
+{ 0x8dd1,	7,	{0x5d, 0x00, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x8dd8,	1,	{0x22} },
+{ 0x8dd9,	16,	{0x8e, 0x61, 0x8f, 0x62, 0x8c, 0x63, 0x8d, 0x64, 0xaf, 0x03, 0x1b, 0xef, 0x60, 0x24, 0x05, 0x62} },
+{ 0x8de9,	16,	{0xe5, 0x62, 0xae, 0x61, 0x70, 0x02, 0x05, 0x61, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05} },
+{ 0x8df9,	16,	{0x64, 0xe5, 0x64, 0xac, 0x63, 0x70, 0x02, 0x05, 0x63, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0} },
+{ 0x8e09,	3,	{0x80, 0xd6, 0x22} },
+{ 0x8e0c,	16,	{0x8d, 0x5c, 0xab, 0x07, 0xaa, 0x06, 0xaf, 0x60, 0xae, 0x5f, 0xad, 0x5e, 0xac, 0x5d, 0xec, 0x4d} },
+{ 0x8e1c,	16,	{0x4e, 0x4f, 0x60, 0x1c, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x1c, 0x7f, 0xff, 0x7e, 0xff, 0x7d} },
+{ 0x8e2c,	16,	{0xff, 0x7c, 0xff, 0x78, 0x5d, 0x12, 0x9d, 0x0e, 0xec, 0x4d, 0x4e, 0x4f, 0x60, 0x09, 0x80, 0xe4} },
+{ 0x8e3c,	16,	{0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0xf9, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x16, 0xaf, 0x03} },
+{ 0x8e4c,	16,	{0xae, 0x02, 0x7c, 0x7b, 0x7d, 0x80, 0xab, 0x5c, 0x12, 0x8d, 0xd9, 0x90, 0x7f, 0xc3, 0xe5, 0x5c} },
+{ 0x8e5c,	7,	{0xf0, 0x7f, 0x01, 0x22, 0x7f, 0x00, 0x22} },
+{ 0x8e63,	16,	{0x90, 0x01, 0x84, 0x74, 0x0b, 0xf0, 0x90, 0x20, 0x70, 0xe0, 0x54, 0xf0, 0xff, 0xc4, 0x54, 0x0f} },
+{ 0x8e73,	16,	{0x90, 0x01, 0x85, 0xf0, 0x90, 0x11, 0xfd, 0xe4, 0x93, 0x90, 0x01, 0x86, 0xf0, 0x90, 0x11, 0xfe} },
+{ 0x8e83,	16,	{0xe4, 0x93, 0x90, 0x01, 0x87, 0xf0, 0xe4, 0x90, 0x01, 0x7c, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3} },
+{ 0x8e93,	16,	{0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0x88, 0xf0, 0x7e} },
+{ 0x8ea3,	16,	{0x01, 0x7f, 0x7c, 0x12, 0x19, 0xc1, 0x7e, 0x01, 0x7f, 0x84, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00} },
+{ 0x8eb3,	13,	{0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x14, 0x12, 0x8e, 0x0c, 0x7f, 0x00} },
+{ 0x8ec0,	1,	{0x22} },
+{ 0x8ec1,	4,	{0x8e, 0x4b, 0x8f, 0x4c} },
+{ 0x8ec5,	16,	{0x85, 0x4b, 0x4e, 0x85, 0x4c, 0x4f, 0xe5, 0x4f, 0x24, 0x01, 0xf5, 0x53, 0xe4, 0x35, 0x4e, 0xf5} },
+{ 0x8ed5,	16,	{0x52, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xe0, 0x14, 0xb4, 0x0f, 0x00, 0x40, 0x03, 0x02, 0x8f} },
+{ 0x8ee5,	16,	{0xd6, 0x90, 0x8e, 0xed, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x8f, 0x1a, 0x02, 0x8f, 0x26, 0x02, 0x8f} },
+{ 0x8ef5,	16,	{0x32, 0x02, 0x8f, 0x5c, 0x02, 0x8f, 0x67, 0x02, 0x8f, 0x72, 0x02, 0x8f, 0x7d, 0x02, 0x8f, 0x88} },
+{ 0x8f05,	16,	{0x02, 0x8f, 0x93, 0x02, 0x8f, 0x9e, 0x02, 0x8f, 0xa9, 0x02, 0x8f, 0xb0, 0x02, 0x8f, 0xd6, 0x02} },
+{ 0x8f15,	16,	{0x8f, 0xbb, 0x02, 0x8f, 0xc6, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x83, 0x5f, 0x8f, 0x4d, 0x02, 0x8f} },
+{ 0x8f25,	16,	{0xd6, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x84, 0x33, 0x8f, 0x4d, 0x02, 0x8f, 0xd6, 0x85, 0x52, 0x50} },
+{ 0x8f35,	16,	{0x85, 0x53, 0x51, 0xe5, 0x51, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x50, 0xfe, 0x12, 0x85, 0x08, 0xaf} },
+{ 0x8f45,	16,	{0x51, 0xae, 0x50, 0x12, 0x85, 0x9b, 0xef, 0x70, 0x03, 0x02, 0x8f, 0xd6, 0xaf, 0x51, 0xae, 0x50} },
+{ 0x8f55,	16,	{0x12, 0x85, 0xe1, 0x8f, 0x4d, 0x80, 0x7a, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0xc0, 0x8f, 0x4d} },
+{ 0x8f65,	16,	{0x80, 0x6f, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0xfc, 0x8f, 0x4d, 0x80, 0x64, 0xaf, 0x53, 0xae} },
+{ 0x8f75,	16,	{0x52, 0x12, 0x8a, 0x38, 0x8f, 0x4d, 0x80, 0x59, 0xaf, 0x4c, 0xae, 0x4b, 0x12, 0x8b, 0x31, 0x8f} },
+{ 0x8f85,	16,	{0x4d, 0x80, 0x4e, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x88, 0xef, 0x8f, 0x4d, 0x80, 0x43, 0xaf, 0x53} },
+{ 0x8f95,	16,	{0xae, 0x52, 0x12, 0x84, 0xc4, 0x8f, 0x4d, 0x80, 0x38, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x89, 0x7b} },
+{ 0x8fa5,	16,	{0x8f, 0x4d, 0x80, 0x2d, 0x12, 0x8e, 0x63, 0x8f, 0x4d, 0x80, 0x26, 0xaf, 0x53, 0xae, 0x52, 0x12} },
+{ 0x8fb5,	16,	{0x11, 0xe5, 0x8f, 0x4d, 0x80, 0x1b, 0xaf, 0x53, 0xae, 0x52, 0x12, 0x8a, 0x70, 0x8f, 0x4d, 0x80} },
+{ 0x8fc5,	16,	{0x10, 0xaf, 0x4c, 0xae, 0x4b, 0x7c, 0x02, 0x7d, 0xaf, 0x7b, 0x40, 0x12, 0x8d, 0xd9, 0xe4, 0xf5} },
+{ 0x8fd5,	16,	{0x4d, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xe0, 0xff, 0x14, 0x24, 0xfa, 0x50, 0x04, 0x24, 0xfe} },
+{ 0x8fe5,	16,	{0x70, 0x2b, 0x90, 0x01, 0x98, 0x74, 0x10, 0xf0, 0xa3, 0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x8ff5,	16,	{0x83, 0xe0, 0x90, 0x01, 0x9a, 0xf0, 0x7e, 0x01, 0x7f, 0x98, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00} },
+{ 0x9005,	15,	{0x75, 0x5e, 0x00, 0x75, 0x5d, 0x00, 0x7d, 0x03, 0x12, 0x8e, 0x0c, 0x8f, 0x4d, 0xaf, 0x4d} },
+{ 0x9014,	1,	{0x22} },
+{ 0x9015,	8,	{0x8f, 0x4e, 0x8e, 0x4d, 0x8d, 0x4c, 0x8c, 0x4b} },
+{ 0x901d,	16,	{0x75, 0x55, 0x01, 0x75, 0x56, 0x9c, 0xe4, 0xf5, 0x54, 0xaf, 0x50, 0x15, 0x50, 0xef, 0x70, 0x03} },
+{ 0x902d,	16,	{0x02, 0x90, 0xb3, 0xaf, 0x4f, 0xe4, 0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xaf, 0x4e} },
+{ 0x903d,	16,	{0xae, 0x4d, 0xad, 0x4c, 0xac, 0x4b, 0x12, 0x9c, 0x58, 0xaf, 0x03, 0x8f, 0x53, 0xaf, 0x4e, 0xae} },
+{ 0x904d,	16,	{0x4d, 0xad, 0x4c, 0xac, 0x4b, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xaf, 0x4f, 0xe4} },
+{ 0x905d,	16,	{0xfc, 0xfd, 0xfe, 0xf8, 0xf9, 0xfa, 0xab, 0x07, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04} },
+{ 0x906d,	16,	{0x12, 0x9c, 0x58, 0x8f, 0x4e, 0x8e, 0x4d, 0x8d, 0x4c, 0x8c, 0x4b, 0xe5, 0x53, 0x24, 0x30, 0xf5} },
+{ 0x907d,	16,	{0x53, 0xd3, 0x94, 0x39, 0x40, 0x06, 0x74, 0x07, 0x25, 0x53, 0xf5, 0x53, 0x05, 0x56, 0xe5, 0x56} },
+{ 0x908d,	16,	{0xae, 0x55, 0x70, 0x02, 0x05, 0x55, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x05, 0x56, 0xe5} },
+{ 0x909d,	16,	{0x56, 0xae, 0x55, 0x70, 0x02, 0x05, 0x55, 0x14, 0xf5, 0x82, 0x8e, 0x83, 0xe5, 0x53, 0xf0, 0x05} },
+{ 0x90ad,	16,	{0x54, 0x05, 0x54, 0x02, 0x90, 0x26, 0xe5, 0x56, 0x15, 0x56, 0x70, 0x02, 0x15, 0x55, 0xaf, 0x54} },
+{ 0x90bd,	16,	{0x15, 0x54, 0xef, 0x60, 0x23, 0xe5, 0x56, 0x15, 0x56, 0xae, 0x55, 0x70, 0x02, 0x15, 0x55, 0xf5} },
+{ 0x90cd,	16,	{0x82, 0x8e, 0x83, 0xe0, 0xff, 0x05, 0x52, 0xe5, 0x52, 0xac, 0x51, 0x70, 0x02, 0x05, 0x51, 0x14} },
+{ 0x90dd,	8,	{0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x80, 0xd6} },
+{ 0x90e5,	1,	{0x22} },
+{ 0x90e6,	16,	{0xe4, 0x90, 0x01, 0xc9, 0xf0, 0x7e, 0x01, 0x7f, 0xca, 0x90, 0x01, 0xbe, 0xee, 0xf0, 0xa3, 0xef} },
+{ 0x90f6,	10,	{0xf0, 0x90, 0x01, 0xc2, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x9100,	16,	{0xaa, 0x07, 0xa9, 0x05, 0x90, 0x01, 0xc9, 0xe0, 0xc3, 0x94, 0x40, 0x50, 0x61, 0xac, 0x02, 0x74} },
+{ 0x9110,	16,	{0x01, 0x7e, 0x00, 0xa8, 0x04, 0x08, 0x80, 0x05, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff} },
+{ 0x9120,	16,	{0xe4, 0xef, 0x55, 0x30, 0x60, 0x45, 0xea, 0x04, 0xff, 0x90, 0x01, 0xc2, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x9130,	16,	{0xfd, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0xa3, 0xe9, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3} },
+{ 0x9140,	16,	{0xeb, 0xf0, 0x90, 0x01, 0xc2, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9b, 0xb8, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x9150,	16,	{0x94, 0x87, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0xc2, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0xca} },
+{ 0x9160,	16,	{0xf0, 0xc2, 0xaf, 0x90, 0x01, 0xc9, 0xe0, 0x04, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x9170,	1,	{0x22} },
+{ 0x9171,	16,	{0x90, 0x01, 0xc9, 0xe0, 0xd3, 0x94, 0x00, 0x40, 0x55, 0x90, 0x01, 0xbe, 0xe0, 0xfc, 0xa3, 0xe0} },
+{ 0x9181,	16,	{0xaa, 0x04, 0xf9, 0x7b, 0x01, 0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0xaa, 0x06, 0xa9, 0x07, 0xa8} },
+{ 0x9191,	16,	{0x01, 0xac, 0x02, 0xad, 0x03, 0xd0, 0x01, 0xd0, 0x02, 0xd0, 0x03, 0x7e, 0x00, 0x7f, 0x03, 0x12} },
+{ 0x91a1,	16,	{0x9b, 0x49, 0x90, 0x01, 0xbe, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x9b, 0xb8, 0xfc, 0xd3, 0xe5, 0xf0} },
+{ 0x91b1,	16,	{0x94, 0x87, 0xec, 0x94, 0x02, 0x40, 0x0a, 0x90, 0x01, 0xbe, 0x74, 0x01, 0xf0, 0xa3, 0x74, 0xca} },
+{ 0x91c1,	16,	{0xf0, 0xc2, 0xaf, 0x90, 0x01, 0xc9, 0xe0, 0x14, 0xf0, 0xd2, 0xaf, 0x7f, 0x01, 0x22, 0x7f, 0x00} },
+{ 0x91d1,	1,	{0x22} },
+{ 0x91d2,	16,	{0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x5e, 0x7e, 0x7b, 0x7f, 0x80, 0x75, 0x50, 0x7b, 0x75, 0x51} },
+{ 0x91e2,	16,	{0x80, 0xe5, 0x51, 0x24, 0x01, 0xff, 0xe4, 0x35, 0x50, 0xa9, 0x07, 0x7b, 0x01, 0x8b, 0x52, 0xf5} },
+{ 0x91f2,	16,	{0x53, 0x89, 0x54, 0xfe, 0x12, 0x91, 0x71, 0xef, 0x60, 0x3b, 0xab, 0x52, 0xaa, 0x53, 0xa9, 0x54} },
+{ 0x9202,	16,	{0x12, 0x9b, 0x72, 0x14, 0xff, 0x90, 0x00, 0x01, 0x12, 0x9b, 0x8b, 0xb4, 0x02, 0x16, 0xc2, 0xaf} },
+{ 0x9212,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x44} },
+{ 0x9222,	16,	{0x04, 0xf0, 0xd2, 0xaf, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0x74, 0x0d, 0xf0, 0x90, 0x7f, 0xc3} },
+{ 0x9232,	5,	{0x74, 0x04, 0xf0, 0xd2, 0xaf} },
+{ 0x9237,	1,	{0x22} },
+{ 0x9238,	16,	{0x12, 0x91, 0xd2, 0xe4, 0xf5, 0x4b, 0x74, 0x36, 0x25, 0x4b, 0xf8, 0xe6, 0x54, 0xf0, 0xf5, 0x4c} },
+{ 0x9248,	16,	{0x74, 0xc5, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5, 0x83, 0xe0, 0x65, 0x4c, 0xff, 0xc4} },
+{ 0x9258,	16,	{0x54, 0x0f, 0xf5, 0x4d, 0x60, 0x22, 0x74, 0xc5, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x01, 0xf5} },
+{ 0x9268,	16,	{0x83, 0xe5, 0x4c, 0xf0, 0xaf, 0x4b, 0x7d, 0x01, 0xe5, 0x4c, 0x45, 0x4d, 0xfb, 0x12, 0x91, 0x00} },
+{ 0x9278,	16,	{0xef, 0x70, 0x05, 0x12, 0x91, 0xd2, 0x80, 0xec, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40} },
+{ 0x9288,	16,	{0xb5, 0x12, 0x91, 0xd2, 0xe5, 0x3a, 0x60, 0x48, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8} },
+{ 0x9298,	16,	{0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x55, 0x3a, 0x60, 0x29, 0xe5, 0x4b} },
+{ 0x92a8,	16,	{0x75, 0xf0, 0x08, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xf5, 0x83, 0xe0, 0x30, 0xe6} },
+{ 0x92b8,	16,	{0x16, 0xaf, 0x4b, 0x7d, 0x04, 0x7b, 0x80, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05, 0x12, 0x91, 0xd2} },
+{ 0x92c8,	16,	{0x80, 0xef, 0xe5, 0x4c, 0xf4, 0x52, 0x3a, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0xbb} },
+{ 0x92d8,	16,	{0x90, 0x03, 0x00, 0xe0, 0x60, 0x03, 0x02, 0x93, 0xa5, 0x74, 0x19, 0xf0, 0x7f, 0x02, 0x12, 0x81} },
+{ 0x92e8,	16,	{0x11, 0x8e, 0x4e, 0x8f, 0x4f, 0xc3, 0xe5, 0x4e, 0x64, 0x80, 0x94, 0x80, 0x40, 0xee, 0x90, 0x01} },
+{ 0x92f8,	16,	{0xbc, 0xe0, 0x65, 0x4f, 0xf0, 0x60, 0x37, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8, 0x07} },
+{ 0x9308,	16,	{0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x90, 0x01, 0xbc, 0xe0, 0x55, 0x4c, 0x60} },
+{ 0x9318,	16,	{0x14, 0xaf, 0x4b, 0x7d, 0x08, 0xe5, 0x4c, 0x55, 0x4f, 0xfb, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05} },
+{ 0x9328,	16,	{0x12, 0x91, 0xd2, 0x80, 0xec, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0xcc, 0x90, 0x01} },
+{ 0x9338,	16,	{0xbc, 0xe5, 0x4f, 0xf0, 0xe4, 0xf5, 0x4b, 0xc2, 0xaf, 0x74, 0x32, 0x25, 0x4b, 0xf8, 0xe6, 0xf5} },
+{ 0x9348,	16,	{0x4c, 0xe4, 0xf6, 0xd2, 0xaf, 0x53, 0x4c, 0x1e, 0xe5, 0x4c, 0x60, 0x11, 0xaf, 0x4b, 0x7d, 0x02} },
+{ 0x9358,	16,	{0xab, 0x4c, 0x12, 0x91, 0x00, 0xef, 0x70, 0x05, 0x12, 0x91, 0xd2, 0x80, 0xef, 0x74, 0x2c, 0x25} },
+{ 0x9368,	16,	{0x4b, 0xf8, 0xe6, 0xf5, 0x4c, 0x74, 0xfc, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83} },
+{ 0x9378,	16,	{0xe0, 0x65, 0x4c, 0x60, 0x11, 0xaf, 0x4b, 0x7d, 0x04, 0xab, 0x4c, 0x12, 0x91, 0x00, 0xef, 0x70} },
+{ 0x9388,	16,	{0x05, 0x12, 0x91, 0xd2, 0x80, 0xef, 0x74, 0xfc, 0x25, 0x4b, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5} },
+{ 0x9398,	16,	{0x83, 0xe5, 0x4c, 0xf0, 0x05, 0x4b, 0xe5, 0x4b, 0xc3, 0x94, 0x04, 0x40, 0x9a, 0x12, 0x91, 0xd2} },
+{ 0x93a8,	1,	{0x22} },
+{ 0x93a9,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x64, 0x02, 0x93, 0xf0} },
+{ 0x93b5,	16,	{0x02, 0x05, 0xa3, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x93c5,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x93d5,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x93e5,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x94, 0x35, 0xe4, 0x7e} },
+{ 0x93f5,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x9405,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x9415,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x9425,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x9435,	16,	{0x60, 0x24, 0x02, 0x8a, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x81, 0x82, 0x84, 0x88} },
+{ 0x9445,	16,	{0x90, 0xa0, 0xc0, 0xc1, 0xc2, 0xc4, 0xc8, 0xd0, 0xe0, 0xe1, 0xe2, 0xe4, 0xe8, 0xf0, 0xf1, 0xf2} },
+{ 0x9455,	8,	{0xf4, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xfe, 0xff} },
+{ 0x945d,	1,	{0x00} },
+{ 0x945e,	11,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x18} },
+{ 0x9469,	16,	{0x90, 0x20, 0x60, 0xe0, 0x54, 0x0f, 0xfe, 0x30, 0xe0, 0x05, 0x90, 0x20, 0x02, 0xe0, 0xff, 0xee} },
+{ 0x9479,	16,	{0x30, 0xe1, 0x05, 0x90, 0x20, 0x0a, 0xe0, 0xff, 0xee, 0x30, 0xe2, 0x05, 0x90, 0x20, 0x12, 0xe0} },
+{ 0x9489,	16,	{0xff, 0xee, 0x30, 0xe3, 0x05, 0x90, 0x20, 0x1a, 0xe0, 0xff, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x1e} },
+{ 0x9499,	10,	{0x04, 0xe4, 0xf0, 0x80, 0x05, 0x90, 0x01, 0xc4, 0xee, 0xf0} },
+{ 0x94a3,	9,	{0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x94ac,	2,	{0xa9, 0x03} },
+{ 0x94ae,	16,	{0xef, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xab, 0x82, 0xfa, 0xe5} },
+{ 0x94be,	16,	{0x57, 0x45, 0x58, 0xf5, 0x59, 0xe9, 0x60, 0x14, 0x8a, 0x83, 0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82} },
+{ 0x94ce,	16,	{0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x4d, 0xf0, 0xe4, 0xfe, 0x80, 0x13, 0xeb, 0x24, 0x04, 0xf5} },
+{ 0x94de,	16,	{0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0xff, 0xed, 0xf4, 0xfc, 0xef, 0x5c, 0xf0, 0xae, 0x59, 0xeb} },
+{ 0x94ee,	16,	{0x24, 0x06, 0xf5, 0x82, 0xe4, 0x3a, 0xf5, 0x83, 0xe0, 0x55, 0x59, 0xfc, 0xb5, 0x06, 0x03, 0xaf} },
+{ 0x94fe,	16,	{0x05, 0x22, 0xe5, 0x57, 0x5c, 0xfe, 0xe5, 0x58, 0x5c, 0xfd, 0xe9, 0x60, 0x16, 0xee, 0x70, 0x04} },
+{ 0x950e,	16,	{0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0xae, 0x07, 0xed, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f} },
+{ 0x951e,	16,	{0x00, 0xad, 0x07, 0xee, 0x60, 0x03, 0xaf, 0x57, 0x22, 0xed, 0x60, 0x03, 0xaf, 0x58, 0x22, 0x7f} },
+{ 0x952e,	1,	{0x00} },
+{ 0x952f,	1,	{0x22} },
+{ 0x9530,	16,	{0x75, 0x50, 0x02, 0x75, 0x51, 0xb0, 0x90, 0x03, 0x35, 0x74, 0x0f, 0xf0, 0x85, 0x51, 0x82, 0x85} },
+{ 0x9540,	16,	{0x50, 0x83, 0xe0, 0xff, 0x90, 0x03, 0x36, 0xf0, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xa3, 0xe0} },
+{ 0x9550,	16,	{0x90, 0x03, 0x37, 0xf0, 0xa3, 0x74, 0xff, 0xf0, 0x75, 0x52, 0x03, 0x75, 0x53, 0x39, 0xef, 0x14} },
+{ 0x9560,	16,	{0xb4, 0x0b, 0x00, 0x40, 0x03, 0x02, 0x99, 0x98, 0x90, 0x95, 0x6f, 0xf8, 0x28, 0x28, 0x73, 0x02} },
+{ 0x9570,	16,	{0x95, 0x90, 0x02, 0x96, 0x2f, 0x02, 0x97, 0x34, 0x02, 0x97, 0x54, 0x02, 0x97, 0x54, 0x02, 0x97} },
+{ 0x9580,	16,	{0xef, 0x02, 0x98, 0x2a, 0x02, 0x98, 0x4f, 0x02, 0x99, 0x0d, 0x02, 0x99, 0x39, 0x02, 0x99, 0x65} },
+{ 0x9590,	16,	{0xe4, 0xf5, 0x4b, 0xe5, 0x4b, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20} },
+{ 0x95a0,	16,	{0xaf, 0x82, 0xf5, 0x4e, 0x8f, 0x4f, 0xe4, 0xff, 0xe4, 0xfe, 0xef, 0x60, 0x10, 0x74, 0x8a, 0x2e} },
+{ 0x95b0,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf4, 0xf5, 0x4c, 0x80, 0x0d, 0x74, 0x8a, 0x2e} },
+{ 0x95c0,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0xf5, 0x4c, 0xe5, 0x4f, 0x24, 0x07, 0xf5, 0x82} },
+{ 0x95d0,	16,	{0xe4, 0x35, 0x4e, 0xf5, 0x83, 0xe5, 0x4c, 0xf0, 0xe0, 0xf5, 0x4d, 0x65, 0x4c, 0x60, 0x38, 0xe4} },
+{ 0x95e0,	16,	{0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xfd, 0x05, 0x53, 0xe5, 0x53, 0xaa, 0x52, 0x70, 0x02} },
+{ 0x95f0,	16,	{0x05, 0x52, 0x14, 0xf5, 0x82, 0x8a, 0x83, 0xed, 0xf0, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52, 0x70} },
+{ 0x9600,	16,	{0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xe5, 0x4c, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x9610,	16,	{0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0x0e, 0xbe, 0x24, 0x8f, 0x0f, 0xef, 0x64, 0x02, 0x70} },
+{ 0x9620,	16,	{0x87, 0x05, 0x4b, 0xe5, 0x4b, 0x64, 0x04, 0x60, 0x03, 0x02, 0x95, 0x93, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x9630,	16,	{0xf5, 0x4b, 0xaf, 0x4b, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0x05, 0x4b, 0xe5, 0x4b, 0xd3, 0x94, 0x03} },
+{ 0x9640,	16,	{0x40, 0xf0, 0x90, 0x00, 0x04, 0x74, 0x94, 0xf0, 0xa3, 0x74, 0x5e, 0xf0, 0xe4, 0xf5, 0x4d, 0x7e} },
+{ 0x9650,	16,	{0x20, 0x7f, 0x00, 0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0xf5, 0x4b, 0xaf, 0x4b, 0x74, 0x01, 0xa8} },
+{ 0x9660,	16,	{0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0xf5, 0x4c, 0x90, 0x01, 0xc4, 0xf0, 0x90, 0x01} },
+{ 0x9670,	16,	{0xc0, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0x74, 0x02} },
+{ 0x9680,	16,	{0xf0, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x4c, 0x34, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0} },
+{ 0x9690,	16,	{0x70, 0xef, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xff, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52} },
+{ 0x96a0,	16,	{0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x96b0,	16,	{0x83, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x01, 0xc4, 0xf0, 0x75, 0x4d, 0xff, 0x90, 0x01, 0xc4, 0xe0} },
+{ 0x96c0,	16,	{0xff, 0x60, 0x37, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04, 0xfe, 0x05, 0x53, 0xe5, 0x53} },
+{ 0x96d0,	16,	{0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xee, 0xf0, 0x05, 0x53, 0xe5} },
+{ 0x96e0,	16,	{0x53, 0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x85, 0x53} },
+{ 0x96f0,	16,	{0x82, 0x85, 0x52, 0x83, 0xe5, 0x4c, 0xf0, 0x75, 0x4d, 0xff, 0xe5, 0x4d, 0x70, 0x16, 0x74, 0x08} },
+{ 0x9700,	16,	{0x25, 0x4f, 0xf5, 0x4f, 0xe4, 0x35, 0x4e, 0xf5, 0x4e, 0x05, 0x4b, 0xe5, 0x4b, 0x64, 0x04, 0x60} },
+{ 0x9710,	16,	{0x03, 0x02, 0x96, 0x5b, 0xe4, 0xf5, 0x4b, 0xaf, 0x4b, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x05, 0x4b} },
+{ 0x9720,	16,	{0xe5, 0x4b, 0xd3, 0x94, 0x03, 0x40, 0xf0, 0x90, 0x00, 0x04, 0x74, 0x13, 0xf0, 0xa3, 0x74, 0x12} },
+{ 0x9730,	16,	{0xf0, 0x02, 0x99, 0x9e, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xa3, 0xe0, 0x14, 0xff, 0x74, 0x01} },
+{ 0x9740,	16,	{0xa8, 0x07, 0x08, 0x80, 0x02, 0xc3, 0x33, 0xd8, 0xfc, 0x90, 0x02, 0xf7, 0xf0, 0x90, 0x01, 0xc4} },
+{ 0x9750,	16,	{0xf0, 0x02, 0x99, 0x9e, 0x90, 0x01, 0xc0, 0x74, 0x03, 0xf0, 0xa3, 0x74, 0xe8, 0xf0, 0xe4, 0xf5} },
+{ 0x9760,	16,	{0x4d, 0x90, 0x02, 0xf7, 0xe0, 0xff, 0x90, 0x01, 0xc4, 0xe0, 0xb5, 0x07, 0x19, 0x90, 0x01, 0xc0} },
+{ 0x9770,	16,	{0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xea, 0x90, 0x03, 0x38, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52} },
+{ 0x9780,	16,	{0x83, 0x74, 0xff, 0xf0, 0xf5, 0x4d, 0xe5, 0x4d, 0x60, 0x03, 0x02, 0x99, 0x9e, 0x90, 0x01, 0xc0} },
+{ 0x9790,	16,	{0xf0, 0xa3, 0x74, 0x96, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70, 0xf6, 0x7f} },
+{ 0x97a0,	16,	{0x02, 0x12, 0x81, 0x11, 0xc3, 0xee, 0x64, 0x80, 0x94, 0x80, 0x40, 0xf3, 0xef, 0x54, 0x0f, 0xf5} },
+{ 0x97b0,	16,	{0x4d, 0x90, 0x02, 0xf7, 0xe0, 0x55, 0x4d, 0x70, 0x04, 0x7f, 0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f} },
+{ 0x97c0,	16,	{0x4c, 0x85, 0x51, 0x82, 0x85, 0x50, 0x83, 0xe0, 0xb4, 0x05, 0x0c, 0xe5, 0x4c, 0x70, 0x04, 0x7f} },
+{ 0x97d0,	16,	{0x01, 0x80, 0x02, 0x7f, 0x00, 0x8f, 0x4c, 0xe5, 0x4c, 0x70, 0x03, 0x02, 0x99, 0x9e, 0xe4, 0x90} },
+{ 0x97e0,	16,	{0x03, 0x38, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52, 0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x97f0,	16,	{0xff, 0xfd, 0x12, 0x82, 0x50, 0x7e, 0x20, 0x7f, 0x00, 0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0x85} },
+{ 0x9800,	16,	{0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0x44, 0x80, 0xf0, 0x85, 0x4f, 0x82, 0x85} },
+{ 0x9810,	16,	{0x4e, 0x83, 0x74, 0x01, 0xf0, 0xa3, 0xe4, 0xf0, 0x85, 0x4f, 0x82, 0x85, 0x4e, 0x83, 0xa3, 0xa3} },
+{ 0x9820,	16,	{0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0xd2, 0x04, 0x02, 0x99, 0x9e, 0xc2, 0x04, 0x7e, 0x20, 0x7f, 0x00} },
+{ 0x9830,	16,	{0x75, 0x4e, 0x20, 0x75, 0x4f, 0x00, 0xe5, 0x4f, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x4e, 0xf5} },
+{ 0x9840,	16,	{0x83, 0xe0, 0x30, 0xe6, 0xf1, 0xe4, 0xff, 0x7d, 0x01, 0x12, 0x82, 0x50, 0x02, 0x99, 0x9e, 0xe4} },
+{ 0x9850,	16,	{0xf5, 0x4d, 0xf5, 0x4b, 0xaf, 0x4b, 0xe4, 0xfd, 0x12, 0x82, 0x50, 0xe5, 0x4b, 0x75, 0xf0, 0x08} },
+{ 0x9860,	16,	{0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xaf, 0x82, 0xf5, 0x4e, 0x8f, 0x4f, 0xf5, 0x83} },
+{ 0x9870,	16,	{0xe5, 0x82, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xaf} },
+{ 0x9880,	16,	{0x4b, 0x7d, 0x01, 0x7b, 0x01, 0x75, 0x57, 0x80, 0x75, 0x58, 0x40, 0x12, 0x94, 0xac, 0x8f, 0x4d} },
+{ 0x9890,	16,	{0xe5, 0x4d, 0x70, 0x11, 0xaf, 0x4b, 0x7d, 0x02, 0x7b, 0x01, 0x75, 0x57, 0x10, 0x75, 0x58, 0x20} },
+{ 0x98a0,	16,	{0x12, 0x94, 0xac, 0x8f, 0x4d, 0xe5, 0x4d, 0x70, 0x10, 0xaf, 0x4b, 0x7d, 0x01, 0xfb, 0x75, 0x57} },
+{ 0x98b0,	16,	{0x80, 0x75, 0x58, 0x40, 0x12, 0x94, 0xac, 0x8f, 0x4d, 0xe5, 0x4d, 0x70, 0x10, 0xaf, 0x4b, 0x7d} },
+{ 0x98c0,	16,	{0x02, 0xfb, 0x75, 0x57, 0x10, 0x75, 0x58, 0x20, 0x12, 0x94, 0xac, 0x8f, 0x4d, 0xaf, 0x4b, 0x7d} },
+{ 0x98d0,	16,	{0x01, 0x12, 0x82, 0x50, 0xe5, 0x4d, 0x60, 0x26, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0xe5, 0x4b, 0x04} },
+{ 0x98e0,	16,	{0xff, 0x05, 0x53, 0xe5, 0x53, 0xac, 0x52, 0x70, 0x02, 0x05, 0x52, 0x14, 0xf5, 0x82, 0x8c, 0x83} },
+{ 0x98f0,	16,	{0xef, 0xf0, 0x85, 0x53, 0x82, 0x85, 0x52, 0x83, 0xe5, 0x4d, 0xf0, 0x02, 0x99, 0x9e, 0x05, 0x4b} },
+{ 0x9900,	16,	{0xe5, 0x4b, 0xd3, 0x94, 0x03, 0x50, 0x03, 0x02, 0x98, 0x54, 0x02, 0x99, 0x9e, 0xe4, 0x90, 0x03} },
+{ 0x9910,	16,	{0x59, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0x74} },
+{ 0x9920,	16,	{0x1b, 0xf0, 0xa3, 0x74, 0x29, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08} },
+{ 0x9930,	16,	{0x60, 0x6c, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0x80, 0x65, 0xe4, 0x90, 0x03, 0x59, 0xf0, 0xa3, 0xf0} },
+{ 0x9940,	16,	{0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xa3, 0xe5, 0x52, 0xf0, 0xa3, 0xe5} },
+{ 0x9950,	16,	{0x53, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x19, 0xc1, 0xef, 0x64, 0x08, 0x60, 0x40, 0xe4, 0x90} },
+{ 0x9960,	16,	{0x03, 0x38, 0xf0, 0x80, 0x39, 0xe4, 0x90, 0x03, 0x59, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0} },
+{ 0x9970,	16,	{0xa3, 0xf0, 0xa3, 0x74, 0x10, 0xf0, 0xe5, 0x51, 0x24, 0x02, 0x90, 0x03, 0x60, 0xf0, 0xe4, 0x35} },
+{ 0x9980,	16,	{0x50, 0x90, 0x03, 0x5f, 0xf0, 0x7e, 0x03, 0x7f, 0x59, 0x12, 0x80, 0x00, 0xef, 0x64, 0x08, 0x60} },
+{ 0x9990,	16,	{0x0d, 0xe4, 0x90, 0x03, 0x38, 0xf0, 0x80, 0x06, 0x90, 0x03, 0x38, 0x74, 0x01, 0xf0, 0x90, 0x01} },
+{ 0x99a0,	16,	{0xc0, 0xe4, 0xf0, 0xa3, 0x74, 0x0a, 0xf0, 0x90, 0x01, 0xc0, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x70} },
+{ 0x99b0,	16,	{0xf6, 0x7e, 0x03, 0x7f, 0x35, 0x75, 0x60, 0x00, 0x75, 0x5f, 0x00, 0x75, 0x5e, 0x00, 0x75, 0x5d} },
+{ 0x99c0,	11,	{0x00, 0x7d, 0x24, 0x12, 0x8e, 0x0c, 0xe4, 0x90, 0x02, 0xaf, 0xf0} },
+{ 0x99cb,	1,	{0x22} },
+{ 0x99cc,	16,	{0xe4, 0xff, 0x74, 0xf8, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02} },
+{ 0x99dc,	16,	{0x9a, 0x6f, 0x74, 0x36, 0x2f, 0xf8, 0xe6, 0x20, 0xe5, 0x03, 0x02, 0x9a, 0x6f, 0xef, 0x75, 0xf0} },
+{ 0x99ec,	16,	{0x08, 0xa4, 0x24, 0x00, 0xf5, 0x82, 0xe4, 0x34, 0x20, 0xad, 0x82, 0xfc, 0xf5, 0x83, 0xe5, 0x82} },
+{ 0x99fc,	16,	{0x24, 0x05, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0xe0, 0x54, 0x60, 0x64, 0x60, 0x70, 0x63} },
+{ 0x9a0c,	16,	{0xef, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe4, 0x75, 0xf0, 0x01} },
+{ 0x9a1c,	16,	{0x12, 0x9b, 0xce, 0x85, 0xf0, 0x82, 0xf5, 0x83, 0xe0, 0x8d, 0x82, 0x8c, 0x83, 0xf0, 0x74, 0xf8} },
+{ 0x9a2c,	16,	{0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xe0, 0x14, 0xf0, 0x70, 0x36, 0xef, 0x25, 0xe0} },
+{ 0x9a3c,	16,	{0x24, 0xc7, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0xef, 0x25, 0xe0, 0xfe, 0xc3} },
+{ 0x9a4c,	16,	{0x74, 0x0c, 0x9e, 0x75, 0xf0, 0x40, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x7b, 0xad} },
+{ 0x9a5c,	16,	{0x82, 0xfc, 0xef, 0x25, 0xe0, 0x24, 0xef, 0xf5, 0x82, 0xe4, 0x34, 0x02, 0xf5, 0x83, 0xec, 0xf0} },
+{ 0x9a6c,	12,	{0xa3, 0xed, 0xf0, 0x0f, 0xef, 0x64, 0x04, 0x60, 0x03, 0x02, 0x99, 0xce} },
+{ 0x9a78,	1,	{0x22} },
+{ 0x9a79,	16,	{0xe7, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e} },
+{ 0x9a89,	16,	{0x88, 0x82, 0x8c, 0x83, 0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08} },
+{ 0x9a99,	16,	{0xdf, 0xfa, 0x80, 0x78, 0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83} },
+{ 0x9aa9,	16,	{0xe3, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x64, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf6, 0x08} },
+{ 0x9ab9,	16,	{0xdf, 0xfa, 0x80, 0x58, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0xa3, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x4c} },
+{ 0x9ac9,	16,	{0x80, 0xd2, 0x80, 0xfa, 0x80, 0xc6, 0x80, 0xd4, 0x80, 0x69, 0x80, 0xf2, 0x80, 0x33, 0x80, 0x10} },
+{ 0x9ad9,	16,	{0x80, 0xa6, 0x80, 0xea, 0x80, 0x9a, 0x80, 0xa8, 0x80, 0xda, 0x80, 0xe2, 0x80, 0xca, 0x80, 0x33} },
+{ 0x9ae9,	16,	{0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83} },
+{ 0x9af9,	16,	{0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xe9, 0xde, 0xe7, 0x80} },
+{ 0x9b09,	16,	{0x0d, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf6, 0x08, 0xdf, 0xf9, 0xec, 0xfa, 0xa9, 0xf0} },
+{ 0x9b19,	16,	{0xed, 0xfb, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xec, 0xfa, 0xe0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc} },
+{ 0x9b29,	16,	{0xc5, 0x83, 0xcc, 0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xcc, 0xc5, 0x83, 0xcc, 0xdf, 0xea, 0xde} },
+{ 0x9b39,	16,	{0xe8, 0x80, 0xdb, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc} },
+{ 0x9b49,	16,	{0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xc2, 0xf5, 0x82, 0xeb, 0x24, 0x02, 0xb4} },
+{ 0x9b59,	16,	{0x04, 0x00, 0x50, 0xb8, 0x23, 0x23, 0x45, 0x82, 0xf5, 0x82, 0xef, 0x4e, 0x60, 0xae, 0xef, 0x60} },
+{ 0x9b69,	9,	{0x01, 0x0e, 0xe5, 0x82, 0x23, 0x90, 0x9a, 0xc9, 0x73} },
+{ 0x9b72,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x9b82,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9b8b,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x9b9b,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x9bab,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x9bb8,	16,	{0xc5, 0xf0, 0xf8, 0xa3, 0xe0, 0x28, 0xf0, 0xc5, 0xf0, 0xf8, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02} },
+{ 0x9bc8,	6,	{0x15, 0x83, 0xe0, 0x38, 0xf0, 0x22} },
+{ 0x9bce,	16,	{0xa3, 0xf8, 0xe0, 0xc5, 0xf0, 0x25, 0xf0, 0xf0, 0xe5, 0x82, 0x15, 0x82, 0x70, 0x02, 0x15, 0x83} },
+{ 0x9bde,	6,	{0xe0, 0xc8, 0x38, 0xf0, 0xe8, 0x22} },
+{ 0x9be4,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x9bf4,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x9c04,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x9c14,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x9c1c,	16,	{0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc} },
+{ 0x9c2c,	16,	{0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, 0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40} },
+{ 0x9c3c,	16,	{0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, 0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6} },
+{ 0x9c4c,	16,	{0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, 0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9} },
+{ 0x9c5c,	16,	{0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, 0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb} },
+{ 0x9c6c,	16,	{0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb} },
+{ 0x9c7c,	16,	{0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, 0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9} },
+{ 0x9c8c,	16,	{0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc} },
+{ 0x9c9c,	16,	{0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, 0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a} },
+{ 0x9cac,	16,	{0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, 0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f} },
+{ 0x9cbc,	16,	{0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, 0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07} },
+{ 0x9ccc,	16,	{0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, 0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8} },
+{ 0x9cdc,	14,	{0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, 0xfa, 0xe4, 0xc8, 0xf9, 0x22} },
+{ 0x9cea,	16,	{0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x9cfa,	1,	{0x22} },
+{ 0x9cfb,	16,	{0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, 0xee, 0x13, 0xfe, 0xef, 0x13, 0xff} },
+{ 0x9d0b,	3,	{0xd8, 0xf1, 0x22} },
+{ 0x9d0e,	16,	{0x08, 0x08, 0x08, 0xe6, 0xcf, 0x2f, 0xf6, 0x18, 0xe6, 0xce, 0x3e, 0xf6, 0x18, 0xe6, 0xcd, 0x3d} },
+{ 0x9d1e,	7,	{0xf6, 0x18, 0xe6, 0xcc, 0x3c, 0xf6, 0x22} },
+{ 0x9d25,	12,	{0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x22} },
+{ 0x9d31,	16,	{0xa8, 0x82, 0x85, 0x83, 0xf0, 0xd0, 0x83, 0xd0, 0x82, 0x12, 0x9d, 0x48, 0x12, 0x9d, 0x48, 0x12} },
+{ 0x9d41,	16,	{0x9d, 0x48, 0x12, 0x9d, 0x48, 0xe4, 0x73, 0xe4, 0x93, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83} },
+{ 0x9d51,	16,	{0xc8, 0xc5, 0x82, 0xc8, 0xf0, 0xa3, 0xc5, 0x83, 0xc5, 0xf0, 0xc5, 0x83, 0xc8, 0xc5, 0x82, 0xc8} },
+{ 0x9d61,	1,	{0x22} },
+{ 0xffff,	0,	{0x00} }
+};
+
+#ifdef DEBUG
+static const struct whiteheat_hex_record whiteheat_loader[] = {
+{ 0x0000,	3,	{0x02, 0x09, 0x8d} },
+{ 0x0033,	3,	{0x02, 0x0e, 0x70} },
+{ 0x0043,	3,	{0x02, 0x0b, 0x00} },
+{ 0x004b,	3,	{0x02, 0x05, 0xb3} },
+{ 0x0100,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x54, 0x10, 0xff, 0xc4, 0x54, 0x0f, 0x44, 0x50, 0xf5, 0x0f, 0x13, 0xe4} },
+{ 0x0110,	16,	{0x33, 0xf5, 0x11, 0x90, 0x7f, 0xe9, 0xe0, 0x24, 0x5e, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x03} },
+{ 0x0120,	16,	{0x7c, 0x90, 0x01, 0x28, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x01, 0xbc, 0x02, 0x01, 0xbc, 0x02, 0x01} },
+{ 0x0130,	16,	{0x91, 0x02, 0x01, 0x3d, 0x02, 0x01, 0x53, 0x02, 0x01, 0x6f, 0x02, 0x01, 0x9a, 0x90, 0x7f, 0x00} },
+{ 0x0140,	16,	{0xe5, 0x11, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0150,	16,	{0x02, 0x03, 0x7c, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x90, 0x7f, 0x00, 0xf0, 0x90} },
+{ 0x0160,	16,	{0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03, 0x7c, 0x12} },
+{ 0x0170,	16,	{0x0a, 0x89, 0x50, 0x07, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x00, 0x74, 0x0f} },
+{ 0x0180,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03} },
+{ 0x0190,	16,	{0x7c, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0f, 0x02, 0x03, 0x7c, 0x90, 0x7f, 0x00, 0x74, 0x07, 0xf0} },
+{ 0x01a0,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xe8, 0x7e} },
+{ 0x01b0,	16,	{0x03, 0x12, 0x0d, 0xd5, 0xd2, 0x06, 0x12, 0x0d, 0x0d, 0x02, 0x03, 0x7c, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x01c0,	16,	{0x75, 0x29, 0x00, 0xf5, 0x2a, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x29, 0x90, 0x7f, 0xee, 0xe0} },
+{ 0x01d0,	16,	{0x75, 0x2b, 0x00, 0xf5, 0x2c, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x2b, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x01e0,	16,	{0x64, 0xc0, 0x60, 0x03, 0x02, 0x02, 0xc9, 0xe5, 0x2c, 0x45, 0x2b, 0x70, 0x03, 0x02, 0x03, 0x7c} },
+{ 0x01f0,	16,	{0xc3, 0xe5, 0x2c, 0x94, 0x40, 0xe5, 0x2b, 0x94, 0x00, 0x50, 0x08, 0x85, 0x2b, 0x2d, 0x85, 0x2c} },
+{ 0x0200,	16,	{0x2e, 0x80, 0x06, 0x75, 0x2d, 0x00, 0x75, 0x2e, 0x40, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70} },
+{ 0x0210,	16,	{0x34, 0xf5, 0x31, 0xf5, 0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5, 0x31, 0x95, 0x2d, 0x50, 0x5c} },
+{ 0x0220,	16,	{0xe5, 0x2a, 0x25, 0x32, 0xf5, 0x82, 0xe5, 0x31, 0x35, 0x29, 0xf5, 0x83, 0xe0, 0xff, 0x74, 0x00} },
+{ 0x0230,	16,	{0x25, 0x32, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70} },
+{ 0x0240,	16,	{0x02, 0x05, 0x31, 0x80, 0xd0, 0xe4, 0xf5, 0x31, 0xf5, 0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5} },
+{ 0x0250,	16,	{0x31, 0x95, 0x2d, 0x50, 0x18, 0x74, 0x00, 0x25, 0x32, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83} },
+{ 0x0260,	16,	{0x74, 0xcd, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70, 0x02, 0x05, 0x31, 0x80, 0xdd, 0xaf, 0x2a, 0xae} },
+{ 0x0270,	16,	{0x29, 0xad, 0x2e, 0x7a, 0x7f, 0x79, 0x00, 0x7b, 0x00, 0x12, 0x0b, 0xf4, 0x90, 0x7f, 0xb5, 0xe5} },
+{ 0x0280,	16,	{0x2e, 0xf0, 0xe5, 0x2e, 0x25, 0x2a, 0xf5, 0x2a, 0xe5, 0x2d, 0x35, 0x29, 0xf5, 0x29, 0xc3, 0xe5} },
+{ 0x0290,	16,	{0x2c, 0x95, 0x2e, 0xf5, 0x2c, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0x90, 0x7f, 0x92, 0xe0, 0xff} },
+{ 0x02a0,	16,	{0xc4, 0x54, 0x0f, 0x75, 0x2f, 0x00, 0xf5, 0x30, 0xd3, 0x94, 0x00, 0xe5, 0x2f, 0x94, 0x00, 0x50} },
+{ 0x02b0,	16,	{0x0c, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xb4} },
+{ 0x02c0,	16,	{0xe0, 0x20, 0xe2, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xe8, 0xe0, 0x64, 0x40, 0x60} },
+{ 0x02d0,	16,	{0x03, 0x02, 0x03, 0x7c, 0xe5, 0x2c, 0x45, 0x2b, 0x70, 0x03, 0x02, 0x03, 0x7c, 0xe4, 0x90, 0x7f} },
+{ 0x02e0,	16,	{0xc5, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x75, 0x2f, 0x00, 0xf5, 0x30, 0xd3} },
+{ 0x02f0,	16,	{0x94, 0x00, 0xe5, 0x2f, 0x94, 0x00, 0x50, 0x09, 0x90, 0x7f, 0xc4, 0xe0, 0x30, 0xe1, 0x09, 0x80} },
+{ 0x0300,	16,	{0xf7, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe3, 0xf9, 0x90, 0x7f, 0xc5, 0xe0, 0x75, 0x2d, 0x00, 0xf5} },
+{ 0x0310,	16,	{0x2e, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70, 0x38, 0x90, 0x20, 0x6b, 0xf0, 0xf5, 0x31, 0xf5} },
+{ 0x0320,	16,	{0x32, 0xc3, 0xe5, 0x32, 0x95, 0x2e, 0xe5, 0x31, 0x95, 0x2d, 0x50, 0x34, 0x74, 0xc0, 0x25, 0x32} },
+{ 0x0330,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7e, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x2a, 0x25, 0x32, 0xf5, 0x82, 0xe5} },
+{ 0x0340,	16,	{0x31, 0x35, 0x29, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x32, 0xe5, 0x32, 0x70, 0x02, 0x05, 0x31, 0x80} },
+{ 0x0350,	16,	{0xd0, 0xaf, 0x2a, 0xae, 0x29, 0xad, 0x2e, 0x7a, 0x7e, 0x79, 0xc0, 0x7b, 0xc0, 0x12, 0x0c, 0x80} },
+{ 0x0360,	16,	{0xe5, 0x2e, 0x25, 0x2a, 0xf5, 0x2a, 0xe5, 0x2d, 0x35, 0x29, 0xf5, 0x29, 0xc3, 0xe5, 0x2c, 0x95} },
+{ 0x0370,	13,	{0x2e, 0xf5, 0x2c, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0x02, 0x02, 0xd4, 0xc3} },
+{ 0x037d,	1,	{0x22} },
+{ 0x037e,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x56, 0x14, 0x70, 0x03, 0x02, 0x04, 0xd2, 0x24} },
+{ 0x038e,	16,	{0xfe, 0x70, 0x03, 0x02, 0x05, 0x46, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x50, 0x14, 0x70, 0x03} },
+{ 0x039e,	16,	{0x02, 0x04, 0x4a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3e, 0x14, 0x70, 0x03, 0x02, 0x04, 0x44, 0x24} },
+{ 0x03ae,	16,	{0x05, 0x60, 0x03, 0x02, 0x05, 0x9a, 0x12, 0x0e, 0x7b, 0x40, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f} },
+{ 0x03be,	16,	{0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x11, 0x90} },
+{ 0x03ce,	16,	{0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x03de,	16,	{0xff, 0x12, 0x0b, 0x58, 0x8b, 0x26, 0x8a, 0x27, 0x89, 0x28, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02} },
+{ 0x03ee,	16,	{0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90} },
+{ 0x03fe,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x0c} },
+{ 0x040e,	16,	{0x3f, 0x8b, 0x26, 0x8a, 0x27, 0x89, 0x28, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f} },
+{ 0x041e,	16,	{0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x042e,	16,	{0x44, 0x01, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xab} },
+{ 0x043e,	16,	{0x12, 0x0e, 0x52, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x60, 0x02, 0x05, 0xab, 0x12, 0x0a, 0xf7, 0x02} },
+{ 0x044e,	16,	{0x05, 0xab, 0x12, 0x08, 0xf1, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x7d, 0x40, 0x03, 0x02, 0x05, 0xab} },
+{ 0x045e,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
+{ 0x046e,	16,	{0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x02, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
+{ 0x047e,	16,	{0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0xe4, 0x90, 0x7f, 0x00} },
+{ 0x048e,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x049e,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x04ae,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
+{ 0x04be,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x04ce,	16,	{0xf0, 0x02, 0x05, 0xab, 0x12, 0x0e, 0x7f, 0x40, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x04de,	16,	{0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xea, 0xe0, 0xb4} },
+{ 0x04ee,	16,	{0x01, 0x05, 0xc2, 0x00, 0x02, 0x05, 0xab, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05} },
+{ 0x04fe,	16,	{0xab, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4} },
+{ 0x050e,	16,	{0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f} },
+{ 0x051e,	16,	{0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f} },
+{ 0x052e,	16,	{0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x6e, 0x90} },
+{ 0x053e,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x65, 0x12, 0x0e, 0x81, 0x50, 0x60, 0x90, 0x7f, 0xe8} },
+{ 0x054e,	16,	{0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x54, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
+{ 0x055e,	16,	{0xd2, 0x00, 0x80, 0x49, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x40, 0x90, 0x7f, 0xea} },
+{ 0x056e,	16,	{0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
+{ 0x057e,	16,	{0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
+{ 0x058e,	16,	{0xf0, 0x80, 0x1a, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x11, 0xe4, 0x90, 0x20, 0x6a} },
+{ 0x059e,	16,	{0xf0, 0x12, 0x01, 0x00, 0x50, 0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4} },
+{ 0x05ae,	4,	{0xe0, 0x44, 0x02, 0xf0} },
+{ 0x05b2,	1,	{0x22} },
+{ 0x05b3,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x05c3,	16,	{0xd0, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0x7f, 0xa5} },
+{ 0x05d3,	16,	{0xe0, 0x30, 0xe2, 0x06, 0x75, 0x0d, 0x06, 0x02, 0x06, 0x7f, 0x90, 0x7f, 0xa5, 0xe0, 0x20, 0xe1} },
+{ 0x05e3,	16,	{0x0c, 0xe5, 0x0d, 0x64, 0x02, 0x60, 0x06, 0x75, 0x0d, 0x07, 0x02, 0x06, 0x7f, 0xaf, 0x0d, 0xef} },
+{ 0x05f3,	16,	{0x24, 0xfe, 0x60, 0x48, 0x14, 0x60, 0x2c, 0x24, 0xfe, 0x60, 0x77, 0x24, 0x04, 0x60, 0x03, 0x02} },
+{ 0x0603,	16,	{0x06, 0x7f, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xaf, 0x0c, 0x05, 0x0c, 0x8f, 0x82, 0x75, 0x83} },
+{ 0x0613,	16,	{0x00, 0x12, 0x07, 0x85, 0x90, 0x7f, 0xa6, 0xf0, 0xe5, 0x0c, 0x65, 0x08, 0x70, 0x5e, 0x75, 0x0d} },
+{ 0x0623,	16,	{0x05, 0x80, 0x59, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e} },
+{ 0x0633,	16,	{0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 0xb2, 0x75, 0x0d, 0x02, 0x80, 0x40, 0xe5, 0x08, 0x24, 0xfe} },
+{ 0x0643,	16,	{0xb5, 0x0c, 0x07, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0xe5, 0x08, 0x14, 0xb5, 0x0c, 0x0a} },
+{ 0x0653,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09} },
+{ 0x0663,	16,	{0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e, 0x82, 0x75, 0x83, 0x00, 0x12, 0x07, 0xb2, 0x05, 0x0c} },
+{ 0x0673,	16,	{0x80, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x53, 0x91, 0xdf, 0xd0} },
+{ 0x0683,	16,	{0x07, 0xd0, 0x06, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x86, 0xd0} },
+{ 0x0693,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x069d,	16,	{0xc2, 0x04, 0xd2, 0x05, 0xe4, 0xf5, 0x25, 0xc2, 0x03, 0xc2, 0x00, 0xc2, 0x02, 0xc2, 0x01, 0x12} },
+{ 0x06ad,	16,	{0x0e, 0x74, 0xd2, 0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9} },
+{ 0x06bd,	16,	{0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0x90} },
+{ 0x06cd,	16,	{0x7f, 0x93, 0x74, 0x30, 0xf0, 0x12, 0x0a, 0x19, 0x75, 0x24, 0x48, 0x75, 0x23, 0x92, 0x75, 0x22} },
+{ 0x06dd,	16,	{0x00, 0x75, 0x21, 0x00, 0xe4, 0xff, 0xfe, 0x7e, 0x05, 0x90, 0x20, 0x68, 0x74, 0x01, 0xf0, 0xa3} },
+{ 0x06ed,	16,	{0xde, 0xfc, 0x7e, 0x00, 0x7f, 0x05, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae} },
+{ 0x06fd,	16,	{0xe0, 0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0x12, 0x0e, 0x68, 0x30, 0x01, 0x0a, 0xe4, 0x90, 0x20, 0x69} },
+{ 0x070d,	16,	{0xf0, 0x12, 0x03, 0x7e, 0xc2, 0x01, 0x30, 0x04, 0x1a, 0x12, 0x0e, 0x77, 0x50, 0x13, 0x12, 0x09} },
+{ 0x071d,	16,	{0x00, 0x30, 0x00, 0x07, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0xf3, 0x12, 0x0d, 0x8b, 0x12, 0x0e} },
+{ 0x072d,	16,	{0x79, 0xc2, 0x03, 0x7f, 0xff, 0x7e, 0xff, 0x7d, 0xff, 0x7c, 0xff, 0x78, 0x21, 0x12, 0x08, 0x1d} },
+{ 0x073d,	16,	{0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xc3, 0x12, 0x08, 0x0c, 0x70, 0x1b, 0x75, 0x24} },
+{ 0x074d,	16,	{0x48, 0x75, 0x23, 0x92, 0xf5, 0x22, 0xf5, 0x21, 0x63, 0x25, 0xff, 0x90, 0x20, 0x68, 0xe5, 0x25} },
+{ 0x075d,	14,	{0xf0, 0xa3, 0x74, 0x01, 0xf0, 0xa3, 0xf0, 0xa3, 0xf0, 0x12, 0x08, 0xff, 0x80, 0x9b} },
+{ 0x076b,	1,	{0x22} },
+{ 0x076c,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x077c,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0785,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x0795,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x07a5,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x07b2,	16,	{0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0} },
+{ 0x07c2,	16,	{0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8} },
+{ 0x07d2,	2,	{0xf2, 0x22} },
+{ 0x07d4,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x07e4,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x07f4,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x0804,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x080c,	16,	{0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x081c,	1,	{0x22} },
+{ 0x081d,	16,	{0x08, 0x08, 0x08, 0xe6, 0x2f, 0xff, 0xf6, 0x18, 0xe6, 0x3e, 0xfe, 0xf6, 0x18, 0xe6, 0x3d, 0xfd} },
+{ 0x082d,	7,	{0xf6, 0x18, 0xe6, 0x3c, 0xfc, 0xf6, 0x22} },
+{ 0x0834,	4,	{0x8c, 0x34, 0x8d, 0x35} },
+{ 0x0838,	16,	{0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0xe4, 0xf5, 0x36, 0xf5, 0x37, 0xc3, 0xe5, 0x37, 0x95} },
+{ 0x0848,	16,	{0x35, 0xe5, 0x36, 0x95, 0x34, 0x50, 0x69, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5} },
+{ 0x0858,	16,	{0x83, 0x74, 0xff, 0xf0, 0xf4, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36} },
+{ 0x0868,	16,	{0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36} },
+{ 0x0878,	16,	{0x3e, 0xf5, 0x83, 0x74, 0xaa, 0xf0, 0x64, 0xaa, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x37, 0xf5} },
+{ 0x0888,	16,	{0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0x74, 0x55, 0xf0, 0x64, 0x55, 0x60, 0x02, 0xc3, 0x22, 0xad} },
+{ 0x0898,	16,	{0x37, 0xe5, 0x37, 0x2f, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xed, 0xf0, 0xfc, 0xac, 0x05} },
+{ 0x08a8,	16,	{0xed, 0x6c, 0x60, 0x02, 0xc3, 0x22, 0x05, 0x37, 0xe5, 0x37, 0x70, 0x02, 0x05, 0x36, 0x80, 0x8c} },
+{ 0x08b8,	16,	{0xe4, 0xf5, 0x36, 0xf5, 0x37, 0xc3, 0xe5, 0x37, 0x95, 0x35, 0xe5, 0x36, 0x95, 0x34, 0x50, 0x27} },
+{ 0x08c8,	16,	{0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xe0, 0x65, 0x37, 0x60, 0x02, 0xc3} },
+{ 0x08d8,	16,	{0x22, 0xef, 0x25, 0x37, 0xf5, 0x82, 0xe5, 0x36, 0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x37, 0xe5} },
+{ 0x08e8,	8,	{0x37, 0x70, 0x02, 0x05, 0x36, 0x80, 0xce, 0xd3} },
+{ 0x08f0,	1,	{0x22} },
+{ 0x08f1,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x10, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x08ff,	1,	{0x22} },
+{ 0x0900,	9,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x097d,	16,	{0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x098d,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x3a, 0x02, 0x09, 0xd4} },
+{ 0x0999,	16,	{0x02, 0x06, 0x9d, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x09a9,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x09b9,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x09c9,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0e, 0x2d, 0xe4, 0x7e} },
+{ 0x09d9,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x09e9,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x09f9,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x0a09,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x0a19,	16,	{0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0a29,	16,	{0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0d, 0xd5, 0x90, 0x7f} },
+{ 0x0a39,	16,	{0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a49,	16,	{0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05} },
+{ 0x0a59,	16,	{0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a69,	16,	{0x12, 0x0d, 0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d} },
+{ 0x0a79,	16,	{0xd5, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d, 0xd5, 0x22} },
+{ 0x0a89,	16,	{0x75, 0x33, 0x01, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x01, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x0e} },
+{ 0x0a99,	16,	{0x7d, 0x00, 0x7c, 0x01, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12} },
+{ 0x0aa9,	16,	{0x0e, 0x18, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x02, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x80, 0x7d} },
+{ 0x0ab9,	16,	{0x00, 0x7c, 0x80, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0e} },
+{ 0x0ac9,	16,	{0x18, 0xe5, 0x33, 0x60, 0x1b, 0x7f, 0x03, 0x12, 0x0e, 0x18, 0x7f, 0x00, 0x7e, 0x20, 0x7d, 0x40} },
+{ 0x0ad9,	16,	{0x7c, 0x5b, 0x12, 0x08, 0x34, 0xe4, 0x33, 0xf5, 0x33, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0e, 0x18} },
+{ 0x0ae9,	13,	{0xe5, 0x33, 0x60, 0x05, 0xe4, 0xff, 0x12, 0x0e, 0x18, 0xe5, 0x33, 0x24, 0xff} },
+{ 0x0af6,	1,	{0x22} },
+{ 0x0af7,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x10, 0xd3, 0x22} },
+{ 0x0aff,	1,	{0x32} },
+{ 0x0b00,	16,	{0x02, 0x0d, 0xa5, 0x00, 0x02, 0x0d, 0xec, 0x00, 0x02, 0x0d, 0x70, 0x00, 0x02, 0x0d, 0xbd, 0x00} },
+{ 0x0b10,	16,	{0x02, 0x0e, 0x02, 0x00, 0x02, 0x0a, 0xff, 0x00, 0x02, 0x0e, 0x83, 0x00, 0x02, 0x0e, 0x84, 0x00} },
+{ 0x0b20,	16,	{0x02, 0x0e, 0x85, 0x00, 0x02, 0x0e, 0x86, 0x00, 0x02, 0x0e, 0x87, 0x00, 0x02, 0x0e, 0x88, 0x00} },
+{ 0x0b30,	16,	{0x02, 0x0e, 0x89, 0x00, 0x02, 0x0e, 0x8a, 0x00, 0x02, 0x0e, 0x8b, 0x00, 0x02, 0x0e, 0x8c, 0x00} },
+{ 0x0b40,	16,	{0x02, 0x0e, 0x8d, 0x00, 0x02, 0x0e, 0x8e, 0x00, 0x02, 0x0e, 0x8f, 0x00, 0x02, 0x0e, 0x90, 0x00} },
+{ 0x0b50,	8,	{0x02, 0x0e, 0x91, 0x00, 0x02, 0x0e, 0x92, 0x00} },
+{ 0x0b58,	16,	{0xe4, 0xfe, 0x75, 0x2b, 0xff, 0x75, 0x2c, 0x11, 0x75, 0x2d, 0x12, 0xab, 0x2b, 0xaa, 0x2c, 0xa9} },
+{ 0x0b68,	16,	{0x2d, 0x90, 0x00, 0x01, 0x12, 0x07, 0x85, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0b78,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x07, 0xd4, 0x85, 0xf0, 0x29, 0xf5, 0x2a, 0x62, 0x29} },
+{ 0x0b88,	16,	{0xe5, 0x29, 0x62, 0x2a, 0xe5, 0x2a, 0x62, 0x29, 0x29, 0xfd, 0xe5, 0x29, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0b98,	14,	{0x2b, 0xff, 0xf5, 0x2c, 0x89, 0x2d, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0ba6,	1,	{0x22} },
+{ 0x0ba7,	6,	{0xab, 0x07, 0xaa, 0x06, 0xac, 0x05} },
+{ 0x0bad,	16,	{0xe4, 0xfd, 0xe5, 0x11, 0x60, 0x11, 0xea, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24, 0x10, 0xf5, 0x82} },
+{ 0x0bbd,	16,	{0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xeb, 0xae, 0x05, 0x0d, 0x74, 0x10, 0x2e, 0xf5, 0x82} },
+{ 0x0bcd,	16,	{0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xeb, 0xf0, 0xaf, 0x05, 0x0d, 0x74, 0x10, 0x2f, 0xf5, 0x82, 0xe4} },
+{ 0x0bdd,	16,	{0x34, 0x0f, 0xf5, 0x83, 0xec, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f, 0x7b, 0x10, 0x12, 0x0d, 0x51, 0x7f} },
+{ 0x0bed,	6,	{0x0a, 0x7e, 0x00, 0x12, 0x0d, 0xd5} },
+{ 0x0bf3,	1,	{0x22} },
+{ 0x0bf4,	10,	{0x8e, 0x33, 0x8f, 0x34, 0x8d, 0x35, 0x8a, 0x36, 0x8b, 0x37} },
+{ 0x0bfe,	16,	{0xe4, 0xfd, 0xf5, 0x38, 0xe5, 0x11, 0x60, 0x12, 0xe5, 0x33, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24} },
+{ 0x0c0e,	16,	{0x13, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x34, 0xae, 0x05, 0x0d, 0x74} },
+{ 0x0c1e,	16,	{0x13, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xe5, 0x34, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f} },
+{ 0x0c2e,	16,	{0x7b, 0x13, 0x12, 0x0d, 0x51, 0xaf, 0x0f, 0xad, 0x35, 0xab, 0x37, 0xaa, 0x36, 0x12, 0x0d, 0x32} },
+{ 0x0c3e,	1,	{0x22} },
+{ 0x0c3f,	2,	{0x8f, 0x29} },
+{ 0x0c41,	16,	{0xe4, 0xf5, 0x2a, 0x75, 0x2b, 0xff, 0x75, 0x2c, 0x11, 0x75, 0x2d, 0x32, 0xab, 0x2b, 0xaa, 0x2c} },
+{ 0x0c51,	16,	{0xa9, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x07, 0x85, 0xb4, 0x03, 0x1d, 0xaf, 0x2a, 0x05, 0x2a, 0xef} },
+{ 0x0c61,	16,	{0xb5, 0x29, 0x01, 0x22, 0x12, 0x07, 0x6c, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x0c71,	14,	{0x2b, 0xff, 0xf5, 0x2c, 0x89, 0x2d, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0c7f,	1,	{0x22} },
+{ 0x0c80,	10,	{0x8e, 0x33, 0x8f, 0x34, 0x8d, 0x35, 0x8a, 0x36, 0x8b, 0x37} },
+{ 0x0c8a,	16,	{0xe4, 0xf5, 0x38, 0xe5, 0x38, 0xc3, 0x95, 0x35, 0x50, 0x20, 0x05, 0x34, 0xe5, 0x34, 0xae, 0x33} },
+{ 0x0c9a,	16,	{0x70, 0x02, 0x05, 0x33, 0x14, 0xff, 0xe5, 0x37, 0x25, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x36, 0xf5} },
+{ 0x0caa,	10,	{0x83, 0xe0, 0xfd, 0x12, 0x0b, 0xa7, 0x05, 0x38, 0x80, 0xd9} },
+{ 0x0cb4,	1,	{0x22} },
+{ 0x0cb5,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x25, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0cc5,	16,	{0x44, 0x01, 0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a} },
+{ 0x0cd5,	13,	{0x0a, 0x89, 0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x03, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0ce2,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0cf2,	16,	{0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a, 0x0a, 0x89} },
+{ 0x0d02,	11,	{0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x01, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0d0d,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x06, 0x04, 0xe0, 0x44} },
+{ 0x0d1d,	16,	{0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x0d, 0xd5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x0d2d,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x0d32,	16,	{0x12, 0x0c, 0xb5, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d42,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d51,	16,	{0x12, 0x0c, 0xe2, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d61,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d70,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0d80,	11,	{0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d8b,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x12, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x14, 0x7e, 0x00, 0x12} },
+{ 0x0d9b,	10,	{0x0d, 0xd5, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x0da5,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0db5,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dbd,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x03, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x0dcd,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dd5,	16,	{0x8e, 0x39, 0x8f, 0x3a, 0xe5, 0x3a, 0x15, 0x3a, 0xae, 0x39, 0x70, 0x02, 0x15, 0x39, 0x4e, 0x60} },
+{ 0x0de5,	7,	{0x05, 0x12, 0x0e, 0x41, 0x80, 0xee, 0x22} },
+{ 0x0dec,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0} },
+{ 0x0dfc,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e02,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0e12,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0e18,	16,	{0xae, 0x07, 0x7f, 0x21, 0x7d, 0x01, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xab, 0x82} },
+{ 0x0e28,	5,	{0xfa, 0x12, 0x0d, 0x51, 0x22} },
+{ 0x0e2d,	16,	{0x50, 0x0f, 0x00, 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0x88, 0x83, 0xc6} },
+{ 0x0e3d,	3,	{0xa1, 0x86, 0x8e} },
+{ 0x0e40,	1,	{0x00} },
+{ 0x0e41,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x0e51,	1,	{0x22} },
+{ 0x0e52,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x0e, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x0e60,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0e, 0xd3, 0x22} },
+{ 0x0e68,	8,	{0xe4, 0xf5, 0x0d, 0xd2, 0xe9, 0xd2, 0xaf, 0x22} },
+{ 0x0e70,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x0e74,	3,	{0xd2, 0x00, 0x22} },
+{ 0x0e77,	2,	{0xd3, 0x22} },
+{ 0x0e79,	2,	{0xd3, 0x22} },
+{ 0x0e7b,	2,	{0xd3, 0x22} },
+{ 0x0e7d,	2,	{0xd3, 0x22} },
+{ 0x0e7f,	2,	{0xd3, 0x22} },
+{ 0x0e81,	2,	{0xd3, 0x22} },
+{ 0x0e83,	1,	{0x32} },
+{ 0x0e84,	1,	{0x32} },
+{ 0x0e85,	1,	{0x32} },
+{ 0x0e86,	1,	{0x32} },
+{ 0x0e87,	1,	{0x32} },
+{ 0x0e88,	1,	{0x32} },
+{ 0x0e89,	1,	{0x32} },
+{ 0x0e8a,	1,	{0x32} },
+{ 0x0e8b,	1,	{0x32} },
+{ 0x0e8c,	1,	{0x32} },
+{ 0x0e8d,	1,	{0x32} },
+{ 0x0e8e,	1,	{0x32} },
+{ 0x0e8f,	1,	{0x32} },
+{ 0x0e90,	1,	{0x32} },
+{ 0x0e91,	1,	{0x32} },
+{ 0x0e92,	1,	{0x32} },
+{ 0x1100,	16,	{0x12, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x47, 0x05, 0x10, 0x27, 0x01, 0x00, 0x01, 0x02} },
+{ 0x1110,	16,	{0x00, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x03, 0xa0, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02} },
+{ 0x1120,	16,	{0xff, 0x00, 0x00, 0x04, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1130,	16,	{0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x26, 0x03, 0x41, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x68, 0x00} },
+{ 0x1140,	16,	{0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x43, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x73, 0x00} },
+{ 0x1150,	16,	{0x2c, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x28, 0x03, 0x46, 0x00} },
+{ 0x1160,	16,	{0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00} },
+{ 0x1170,	16,	{0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00} },
+{ 0x1180,	16,	{0x6b, 0x00, 0x73, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
+{ 0x1190,	16,	{0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
+{ 0x11a0,	16,	{0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
+{ 0x11b0,	16,	{0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
+{ 0x11c0,	16,	{0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
+{ 0x11d0,	2,	{0x00, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
+
+#else
+
+static const struct whiteheat_hex_record whiteheat_loader[] = {
+{ 0x0000,	3,	{0x02, 0x09, 0x8d} },
+{ 0x0033,	3,	{0x02, 0x08, 0xfb} },
+{ 0x0043,	3,	{0x02, 0x0b, 0x00} },
+{ 0x004b,	3,	{0x02, 0x05, 0xaa} },
+{ 0x0100,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x54, 0x10, 0xff, 0xc4, 0x54, 0x0f, 0x44, 0x50, 0xf5, 0x0f, 0x13, 0xe4} },
+{ 0x0110,	16,	{0x33, 0xf5, 0x11, 0x90, 0x7f, 0xe9, 0xe0, 0x24, 0x5e, 0xb4, 0x07, 0x00, 0x40, 0x03, 0x02, 0x03} },
+{ 0x0120,	16,	{0x78, 0x90, 0x01, 0x28, 0xf8, 0x28, 0x28, 0x73, 0x02, 0x01, 0xbc, 0x02, 0x01, 0xbc, 0x02, 0x01} },
+{ 0x0130,	16,	{0x91, 0x02, 0x01, 0x3d, 0x02, 0x01, 0x53, 0x02, 0x01, 0x6f, 0x02, 0x01, 0x9a, 0x90, 0x7f, 0x00} },
+{ 0x0140,	16,	{0xe5, 0x11, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x0150,	16,	{0x02, 0x03, 0x78, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x90, 0x7f, 0x00, 0xf0, 0x90} },
+{ 0x0160,	16,	{0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03, 0x78, 0x12} },
+{ 0x0170,	16,	{0x0a, 0x89, 0x50, 0x07, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0x80, 0x06, 0x90, 0x7f, 0x00, 0x74, 0x0f} },
+{ 0x0180,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x02, 0x03} },
+{ 0x0190,	16,	{0x78, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0f, 0x02, 0x03, 0x78, 0x90, 0x7f, 0x00, 0x74, 0x07, 0xf0} },
+{ 0x01a0,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x7f, 0xe8, 0x7e} },
+{ 0x01b0,	16,	{0x03, 0x12, 0x0d, 0x94, 0xd2, 0x06, 0x12, 0x0c, 0xcc, 0x02, 0x03, 0x78, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x01c0,	16,	{0x75, 0x28, 0x00, 0xf5, 0x29, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x28, 0x90, 0x7f, 0xee, 0xe0} },
+{ 0x01d0,	16,	{0x75, 0x2a, 0x00, 0xf5, 0x2b, 0xa3, 0xe0, 0xfe, 0xe4, 0xee, 0x42, 0x2a, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x01e0,	16,	{0x64, 0xc0, 0x60, 0x03, 0x02, 0x02, 0xc9, 0xe5, 0x2b, 0x45, 0x2a, 0x70, 0x03, 0x02, 0x03, 0x78} },
+{ 0x01f0,	16,	{0xc3, 0xe5, 0x2b, 0x94, 0x40, 0xe5, 0x2a, 0x94, 0x00, 0x50, 0x08, 0x85, 0x2a, 0x2c, 0x85, 0x2b} },
+{ 0x0200,	16,	{0x2d, 0x80, 0x06, 0x75, 0x2c, 0x00, 0x75, 0x2d, 0x40, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70} },
+{ 0x0210,	16,	{0x34, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31, 0x95, 0x2d, 0xe5, 0x30, 0x95, 0x2c, 0x50, 0x5c} },
+{ 0x0220,	16,	{0xe5, 0x29, 0x25, 0x31, 0xf5, 0x82, 0xe5, 0x30, 0x35, 0x28, 0xf5, 0x83, 0xe0, 0xff, 0x74, 0x00} },
+{ 0x0230,	16,	{0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70} },
+{ 0x0240,	16,	{0x02, 0x05, 0x30, 0x80, 0xd0, 0xe4, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31, 0x95, 0x2d, 0xe5} },
+{ 0x0250,	16,	{0x30, 0x95, 0x2c, 0x50, 0x18, 0x74, 0x00, 0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83} },
+{ 0x0260,	16,	{0x74, 0xcd, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70, 0x02, 0x05, 0x30, 0x80, 0xdd, 0xaf, 0x29, 0xae} },
+{ 0x0270,	16,	{0x28, 0xad, 0x2d, 0x7a, 0x7f, 0x79, 0x00, 0x7b, 0x00, 0x12, 0x0b, 0xf4, 0x90, 0x7f, 0xb5, 0xe5} },
+{ 0x0280,	16,	{0x2d, 0xf0, 0xe5, 0x2d, 0x25, 0x29, 0xf5, 0x29, 0xe5, 0x2c, 0x35, 0x28, 0xf5, 0x28, 0xc3, 0xe5} },
+{ 0x0290,	16,	{0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0xe5, 0x2a, 0x95, 0x2c, 0xf5, 0x2a, 0x90, 0x7f, 0x92, 0xe0, 0xff} },
+{ 0x02a0,	16,	{0xc4, 0x54, 0x0f, 0x75, 0x2e, 0x00, 0xf5, 0x2f, 0xd3, 0x94, 0x00, 0xe5, 0x2e, 0x94, 0x00, 0x50} },
+{ 0x02b0,	16,	{0x0c, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe1, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xb4} },
+{ 0x02c0,	16,	{0xe0, 0x20, 0xe2, 0x03, 0x02, 0x01, 0xe7, 0x80, 0xf4, 0x90, 0x7f, 0xe8, 0xe0, 0x64, 0x40, 0x60} },
+{ 0x02d0,	16,	{0x03, 0x02, 0x03, 0x78, 0xe5, 0x2b, 0x45, 0x2a, 0x70, 0x03, 0x02, 0x03, 0x78, 0xe4, 0x90, 0x7f} },
+{ 0x02e0,	16,	{0xc5, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0xff, 0xc4, 0x54, 0x0f, 0x75, 0x2e, 0x00, 0xf5, 0x2f, 0xd3} },
+{ 0x02f0,	16,	{0x94, 0x00, 0xe5, 0x2e, 0x94, 0x00, 0x50, 0x09, 0x90, 0x7f, 0xc4, 0xe0, 0x30, 0xe1, 0x09, 0x80} },
+{ 0x0300,	16,	{0xf7, 0x90, 0x7f, 0xb4, 0xe0, 0x20, 0xe3, 0xf9, 0x90, 0x7f, 0xc5, 0xe0, 0x75, 0x2c, 0x00, 0xf5} },
+{ 0x0310,	16,	{0x2d, 0x90, 0x7f, 0xe9, 0xe0, 0x64, 0xa3, 0x70, 0x34, 0xf5, 0x30, 0xf5, 0x31, 0xc3, 0xe5, 0x31} },
+{ 0x0320,	16,	{0x95, 0x2d, 0xe5, 0x30, 0x95, 0x2c, 0x50, 0x34, 0x74, 0xc0, 0x25, 0x31, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0330,	1,	{0x7e} },
+{ 0x0331,	16,	{0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x29, 0x25, 0x31, 0xf5, 0x82, 0xe5, 0x30, 0x35, 0x28, 0xf5, 0x83} },
+{ 0x0341,	16,	{0xef, 0xf0, 0x05, 0x31, 0xe5, 0x31, 0x70, 0x02, 0x05, 0x30, 0x80, 0xd0, 0xaf, 0x29, 0xae, 0x28} },
+{ 0x0351,	16,	{0xad, 0x2d, 0x7a, 0x7e, 0x79, 0xc0, 0x7b, 0xc0, 0x12, 0x0c, 0x3f, 0xe5, 0x2d, 0x25, 0x29, 0xf5} },
+{ 0x0361,	16,	{0x29, 0xe5, 0x2c, 0x35, 0x28, 0xf5, 0x28, 0xc3, 0xe5, 0x2b, 0x95, 0x2d, 0xf5, 0x2b, 0xe5, 0x2a} },
+{ 0x0371,	9,	{0x95, 0x2c, 0xf5, 0x2a, 0x02, 0x02, 0xd4, 0xc3, 0x22} },
+{ 0x037a,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x70, 0x03, 0x02, 0x04, 0x52, 0x14, 0x70, 0x03, 0x02, 0x04, 0xce, 0x24} },
+{ 0x038a,	16,	{0xfe, 0x70, 0x03, 0x02, 0x05, 0x42, 0x24, 0xfb, 0x70, 0x03, 0x02, 0x04, 0x4c, 0x14, 0x70, 0x03} },
+{ 0x039a,	16,	{0x02, 0x04, 0x46, 0x14, 0x70, 0x03, 0x02, 0x04, 0x3a, 0x14, 0x70, 0x03, 0x02, 0x04, 0x40, 0x24} },
+{ 0x03aa,	16,	{0x05, 0x60, 0x03, 0x02, 0x05, 0x96, 0x12, 0x0e, 0x44, 0x40, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f} },
+{ 0x03ba,	16,	{0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x16, 0x14, 0x60, 0x40, 0x24, 0x02, 0x70, 0x69, 0x74, 0x11, 0x90} },
+{ 0x03ca,	16,	{0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0} },
+{ 0x03da,	16,	{0xff, 0x12, 0x0b, 0x58, 0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02} },
+{ 0x03ea,	16,	{0xee, 0x90, 0x7f, 0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90} },
+{ 0x03fa,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x08} },
+{ 0x040a,	16,	{0xba, 0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0xea, 0x49, 0x60, 0x11, 0xae, 0x02, 0xee, 0x90, 0x7f} },
+{ 0x041a,	16,	{0xd4, 0xf0, 0xaf, 0x01, 0xef, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x042a,	16,	{0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05, 0xa2} },
+{ 0x043a,	16,	{0x12, 0x0e, 0x1f, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x2d, 0x02, 0x05, 0xa2, 0x12, 0x0a, 0xf7, 0x02} },
+{ 0x044a,	16,	{0x05, 0xa2, 0x12, 0x0e, 0x11, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x46, 0x40, 0x03, 0x02, 0x05, 0xa2} },
+{ 0x045a,	16,	{0x90, 0x7f, 0xe8, 0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2} },
+{ 0x046a,	16,	{0x00, 0xe4, 0x33, 0xff, 0x25, 0xe0, 0xff, 0xa2, 0x02, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0} },
+{ 0x047a,	16,	{0xe4, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0xe4, 0x90, 0x7f, 0x00} },
+{ 0x048a,	16,	{0xf0, 0xa3, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x049a,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x04aa,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3} },
+{ 0x04ba,	16,	{0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01} },
+{ 0x04ca,	16,	{0xf0, 0x02, 0x05, 0xa2, 0x12, 0x0e, 0x48, 0x40, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xe8, 0xe0} },
+{ 0x04da,	16,	{0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xea, 0xe0, 0xb4} },
+{ 0x04ea,	16,	{0x01, 0x05, 0xc2, 0x00, 0x02, 0x05, 0xa2, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x05} },
+{ 0x04fa,	16,	{0xa2, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4} },
+{ 0x050a,	16,	{0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f} },
+{ 0x051a,	16,	{0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff, 0x13, 0x13, 0x13, 0x54, 0x1f} },
+{ 0x052a,	16,	{0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x69, 0x90} },
+{ 0x053a,	16,	{0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x60, 0x12, 0x0e, 0x4a, 0x50, 0x5b, 0x90, 0x7f, 0xe8} },
+{ 0x054a,	16,	{0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4f, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
+{ 0x055a,	16,	{0xd2, 0x00, 0x80, 0x44, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x3b, 0x90, 0x7f, 0xea} },
+{ 0x056a,	16,	{0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
+{ 0x057a,	16,	{0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
+{ 0x058a,	16,	{0xf0, 0x80, 0x15, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x0c, 0x12, 0x01, 0x00, 0x50} },
+{ 0x059a,	16,	{0x07, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x22} },
+{ 0x05aa,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xc0} },
+{ 0x05ba,	16,	{0xd0, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x06, 0xc0, 0x07, 0x90, 0x7f, 0xa5} },
+{ 0x05ca,	16,	{0xe0, 0x30, 0xe2, 0x06, 0x75, 0x0d, 0x06, 0x02, 0x06, 0x76, 0x90, 0x7f, 0xa5, 0xe0, 0x20, 0xe1} },
+{ 0x05da,	16,	{0x0c, 0xe5, 0x0d, 0x64, 0x02, 0x60, 0x06, 0x75, 0x0d, 0x07, 0x02, 0x06, 0x76, 0xaf, 0x0d, 0xef} },
+{ 0x05ea,	16,	{0x24, 0xfe, 0x60, 0x48, 0x14, 0x60, 0x2c, 0x24, 0xfe, 0x60, 0x77, 0x24, 0x04, 0x60, 0x03, 0x02} },
+{ 0x05fa,	16,	{0x06, 0x76, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xaf, 0x0c, 0x05, 0x0c, 0x8f, 0x82, 0x75, 0x83} },
+{ 0x060a,	16,	{0x00, 0x12, 0x08, 0x22, 0x90, 0x7f, 0xa6, 0xf0, 0xe5, 0x0c, 0x65, 0x08, 0x70, 0x5e, 0x75, 0x0d} },
+{ 0x061a,	16,	{0x05, 0x80, 0x59, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09, 0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e} },
+{ 0x062a,	16,	{0x82, 0x75, 0x83, 0x00, 0x12, 0x08, 0x4f, 0x75, 0x0d, 0x02, 0x80, 0x40, 0xe5, 0x08, 0x24, 0xfe} },
+{ 0x063a,	16,	{0xb5, 0x0c, 0x07, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x20, 0xf0, 0xe5, 0x08, 0x14, 0xb5, 0x0c, 0x0a} },
+{ 0x064a,	16,	{0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x90, 0x7f, 0xa6, 0xe0, 0xab, 0x09} },
+{ 0x065a,	16,	{0xaa, 0x0a, 0xa9, 0x0b, 0xae, 0x0c, 0x8e, 0x82, 0x75, 0x83, 0x00, 0x12, 0x08, 0x4f, 0x05, 0x0c} },
+{ 0x066a,	16,	{0x80, 0x0a, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x40, 0xf0, 0xe4, 0xf5, 0x0d, 0x53, 0x91, 0xdf, 0xd0} },
+{ 0x067a,	16,	{0x07, 0xd0, 0x06, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x86, 0xd0} },
+{ 0x068a,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0694,	16,	{0x8c, 0x33, 0x8d, 0x34, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0xe4, 0xf5, 0x35, 0xf5, 0x36} },
+{ 0x06a4,	16,	{0xc3, 0xe5, 0x36, 0x95, 0x34, 0xe5, 0x35, 0x95, 0x33, 0x50, 0x69, 0xef, 0x25, 0x36, 0xf5, 0x82} },
+{ 0x06b4,	16,	{0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0xff, 0xf0, 0xf4, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36} },
+{ 0x06c4,	16,	{0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe4, 0xf0, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36} },
+{ 0x06d4,	16,	{0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0xaa, 0xf0, 0x64, 0xaa, 0x60, 0x02, 0xc3, 0x22} },
+{ 0x06e4,	16,	{0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0x74, 0x55, 0xf0, 0x64, 0x55, 0x60} },
+{ 0x06f4,	16,	{0x02, 0xc3, 0x22, 0xad, 0x36, 0xe5, 0x36, 0x2f, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xed} },
+{ 0x0704,	16,	{0xf0, 0xfc, 0xac, 0x05, 0xed, 0x6c, 0x60, 0x02, 0xc3, 0x22, 0x05, 0x36, 0xe5, 0x36, 0x70, 0x02} },
+{ 0x0714,	16,	{0x05, 0x35, 0x80, 0x8c, 0xe4, 0xf5, 0x35, 0xf5, 0x36, 0xc3, 0xe5, 0x36, 0x95, 0x34, 0xe5, 0x35} },
+{ 0x0724,	16,	{0x95, 0x33, 0x50, 0x27, 0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe0, 0x65} },
+{ 0x0734,	16,	{0x36, 0x60, 0x02, 0xc3, 0x22, 0xef, 0x25, 0x36, 0xf5, 0x82, 0xe5, 0x35, 0x3e, 0xf5, 0x83, 0xe4} },
+{ 0x0744,	13,	{0xf0, 0x05, 0x36, 0xe5, 0x36, 0x70, 0x02, 0x05, 0x35, 0x80, 0xce, 0xd3, 0x22} },
+{ 0x0751,	16,	{0xc2, 0x04, 0xd2, 0x05, 0xc2, 0x03, 0xc2, 0x00, 0xc2, 0x02, 0xc2, 0x01, 0x12, 0x0e, 0x3d, 0xd2} },
+{ 0x0761,	16,	{0xe8, 0x43, 0xd8, 0x20, 0x90, 0x7f, 0xab, 0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f} },
+{ 0x0771,	16,	{0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0x95, 0xe0, 0x44, 0xc0, 0xf0, 0x90, 0x7f, 0x93, 0x74} },
+{ 0x0781,	16,	{0x30, 0xf0, 0x12, 0x0a, 0x19, 0x90, 0x7f, 0xaf, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0xe0} },
+{ 0x0791,	16,	{0x44, 0x0d, 0xf0, 0xd2, 0xaf, 0x12, 0x0e, 0x35, 0x20, 0x01, 0x42, 0x75, 0x24, 0x00, 0x75, 0x23} },
+{ 0x07a1,	16,	{0x00, 0x75, 0x22, 0x00, 0x75, 0x21, 0x00, 0x7f, 0x48, 0x7e, 0x92, 0x7d, 0x00, 0x7c, 0x00, 0xab} },
+{ 0x07b1,	16,	{0x24, 0xaa, 0x23, 0xa9, 0x22, 0xa8, 0x21, 0xc3, 0x12, 0x08, 0xa9, 0x50, 0xdb, 0x20, 0x01, 0xd8} },
+{ 0x07c1,	16,	{0x7a, 0x00, 0x79, 0x00, 0x78, 0x00, 0xe5, 0x24, 0x24, 0x01, 0xf5, 0x24, 0xea, 0x35, 0x23, 0xf5} },
+{ 0x07d1,	16,	{0x23, 0xe9, 0x35, 0x22, 0xf5, 0x22, 0xe8, 0x35, 0x21, 0xf5, 0x21, 0x80, 0xca, 0x30, 0x01, 0x05} },
+{ 0x07e1,	16,	{0x12, 0x03, 0x7a, 0xc2, 0x01, 0x30, 0x04, 0x1a, 0x12, 0x0e, 0x40, 0x50, 0x13, 0x12, 0x09, 0x00} },
+{ 0x07f1,	16,	{0x30, 0x00, 0x07, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0xf3, 0x12, 0x0d, 0x4a, 0x12, 0x0e, 0x42} },
+{ 0x0801,	8,	{0xc2, 0x03, 0x12, 0x08, 0xff, 0x80, 0xd6, 0x22} },
+{ 0x0809,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x0819,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x0822,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x0832,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x0842,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x084f,	16,	{0xf8, 0xbb, 0x01, 0x0d, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe8, 0xf0} },
+{ 0x085f,	16,	{0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xc8, 0xf6, 0x22, 0xbb, 0xfe, 0x05, 0xe9, 0x25, 0x82, 0xc8} },
+{ 0x086f,	2,	{0xf2, 0x22} },
+{ 0x0871,	16,	{0xbb, 0x01, 0x10, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0xf5, 0xf0} },
+{ 0x0881,	16,	{0xa3, 0xe0, 0x22, 0x50, 0x09, 0xe9, 0x25, 0x82, 0xf8, 0x86, 0xf0, 0x08, 0xe6, 0x22, 0xbb, 0xfe} },
+{ 0x0891,	16,	{0x0a, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0xf5, 0xf0, 0x08, 0xe2, 0x22, 0xe5, 0x83, 0x2a, 0xf5, 0x83} },
+{ 0x08a1,	8,	{0xe9, 0x93, 0xf5, 0xf0, 0xa3, 0xe9, 0x93, 0x22} },
+{ 0x08a9,	16,	{0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, 0xf0, 0xe8, 0x9c, 0x45, 0xf0} },
+{ 0x08b9,	1,	{0x22} },
+{ 0x08ba,	2,	{0x8f, 0x28} },
+{ 0x08bc,	16,	{0xe4, 0xf5, 0x29, 0x75, 0x2a, 0xff, 0x75, 0x2b, 0x11, 0x75, 0x2c, 0x32, 0xab, 0x2a, 0xaa, 0x2b} },
+{ 0x08cc,	16,	{0xa9, 0x2c, 0x90, 0x00, 0x01, 0x12, 0x08, 0x22, 0xb4, 0x03, 0x1d, 0xaf, 0x29, 0x05, 0x29, 0xef} },
+{ 0x08dc,	16,	{0xb5, 0x28, 0x01, 0x22, 0x12, 0x08, 0x09, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x08ec,	14,	{0x2a, 0xff, 0xf5, 0x2b, 0x89, 0x2c, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x08fa,	1,	{0x22} },
+{ 0x08fb,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x08ff,	1,	{0x22} },
+{ 0x0900,	9,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x74} },
+{ 0x097d,	16,	{0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x098d,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x39, 0x02, 0x09, 0xd4} },
+{ 0x0999,	16,	{0x02, 0x07, 0x51, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x09a9,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x09b9,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x09c9,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x0d, 0xec, 0xe4, 0x7e} },
+{ 0x09d9,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x09e9,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x09f9,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x0a09,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x0a19,	16,	{0xe4, 0x90, 0x7f, 0x9c, 0xf0, 0x7f, 0x0a, 0xfe, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0x74, 0x89} },
+{ 0x0a29,	16,	{0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xcf, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x0d, 0x94, 0x90, 0x7f} },
+{ 0x0a39,	16,	{0x96, 0xe0, 0x54, 0xfe, 0xf0, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a49,	16,	{0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x02, 0xf0, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0x05} },
+{ 0x0a59,	16,	{0x7e, 0x00, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x05, 0x7e, 0x00} },
+{ 0x0a69,	16,	{0x12, 0x0d, 0x94, 0x90, 0x7f, 0x96, 0xe0, 0x54, 0xbf, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d} },
+{ 0x0a79,	16,	{0x94, 0x90, 0x7f, 0x96, 0xe0, 0x44, 0x40, 0xf0, 0x7f, 0x32, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x22} },
+{ 0x0a89,	16,	{0x75, 0x32, 0x01, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x01, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x0e} },
+{ 0x0a99,	16,	{0x7d, 0x00, 0x7c, 0x01, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12} },
+{ 0x0aa9,	16,	{0x0d, 0xd7, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x02, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x80, 0x7d} },
+{ 0x0ab9,	16,	{0x00, 0x7c, 0x80, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0d} },
+{ 0x0ac9,	16,	{0xd7, 0xe5, 0x32, 0x60, 0x1b, 0x7f, 0x03, 0x12, 0x0d, 0xd7, 0x7f, 0x00, 0x7e, 0x20, 0x7d, 0x40} },
+{ 0x0ad9,	16,	{0x7c, 0x5b, 0x12, 0x06, 0x94, 0xe4, 0x33, 0xf5, 0x32, 0x70, 0x05, 0x7f, 0x0f, 0x12, 0x0d, 0xd7} },
+{ 0x0ae9,	14,	{0xe5, 0x32, 0x60, 0x05, 0xe4, 0xff, 0x12, 0x0d, 0xd7, 0xe5, 0x32, 0x24, 0xff, 0x22} },
+{ 0x0af7,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x10, 0xd3, 0x22} },
+{ 0x0aff,	1,	{0x32} },
+{ 0x0b00,	16,	{0x02, 0x0d, 0x64, 0x00, 0x02, 0x0d, 0xab, 0x00, 0x02, 0x0d, 0x2f, 0x00, 0x02, 0x0d, 0x7c, 0x00} },
+{ 0x0b10,	16,	{0x02, 0x0d, 0xc1, 0x00, 0x02, 0x0a, 0xff, 0x00, 0x02, 0x0e, 0x4c, 0x00, 0x02, 0x0e, 0x4d, 0x00} },
+{ 0x0b20,	16,	{0x02, 0x0e, 0x4e, 0x00, 0x02, 0x0e, 0x4f, 0x00, 0x02, 0x0e, 0x50, 0x00, 0x02, 0x0e, 0x51, 0x00} },
+{ 0x0b30,	16,	{0x02, 0x0e, 0x52, 0x00, 0x02, 0x0e, 0x53, 0x00, 0x02, 0x0e, 0x54, 0x00, 0x02, 0x0e, 0x55, 0x00} },
+{ 0x0b40,	16,	{0x02, 0x0e, 0x56, 0x00, 0x02, 0x0e, 0x57, 0x00, 0x02, 0x0e, 0x58, 0x00, 0x02, 0x0e, 0x59, 0x00} },
+{ 0x0b50,	8,	{0x02, 0x0e, 0x5a, 0x00, 0x02, 0x0e, 0x5b, 0x00} },
+{ 0x0b58,	16,	{0xe4, 0xfe, 0x75, 0x2a, 0xff, 0x75, 0x2b, 0x11, 0x75, 0x2c, 0x12, 0xab, 0x2a, 0xaa, 0x2b, 0xa9} },
+{ 0x0b68,	16,	{0x2c, 0x90, 0x00, 0x01, 0x12, 0x08, 0x22, 0x64, 0x02, 0x70, 0x2d, 0xad, 0x06, 0x0e, 0xed, 0xb5} },
+{ 0x0b78,	16,	{0x07, 0x01, 0x22, 0x90, 0x00, 0x02, 0x12, 0x08, 0x71, 0x85, 0xf0, 0x28, 0xf5, 0x29, 0x62, 0x28} },
+{ 0x0b88,	16,	{0xe5, 0x28, 0x62, 0x29, 0xe5, 0x29, 0x62, 0x28, 0x29, 0xfd, 0xe5, 0x28, 0x3a, 0xa9, 0x05, 0x75} },
+{ 0x0b98,	14,	{0x2a, 0xff, 0xf5, 0x2b, 0x89, 0x2c, 0x80, 0xc3, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x0ba6,	1,	{0x22} },
+{ 0x0ba7,	16,	{0xab, 0x07, 0xaa, 0x06, 0xac, 0x05, 0xe4, 0xfd, 0xe5, 0x11, 0x60, 0x11, 0xea, 0xff, 0xae, 0x05} },
+{ 0x0bb7,	16,	{0x0d, 0xee, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xef, 0xf0, 0xeb, 0xae, 0x05} },
+{ 0x0bc7,	16,	{0x0d, 0x74, 0x10, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xeb, 0xf0, 0xaf, 0x05, 0x0d} },
+{ 0x0bd7,	16,	{0x74, 0x10, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xf5, 0x83, 0xec, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f} },
+{ 0x0be7,	13,	{0x7b, 0x10, 0x12, 0x0d, 0x10, 0x7f, 0x0a, 0x7e, 0x00, 0x12, 0x0d, 0x94, 0x22} },
+{ 0x0bf4,	16,	{0x8e, 0x32, 0x8f, 0x33, 0x8d, 0x34, 0x8a, 0x35, 0x8b, 0x36, 0xe4, 0xfd, 0xf5, 0x37, 0xe5, 0x11} },
+{ 0x0c04,	16,	{0x60, 0x12, 0xe5, 0x32, 0xff, 0xae, 0x05, 0x0d, 0xee, 0x24, 0x13, 0xf5, 0x82, 0xe4, 0x34, 0x0f} },
+{ 0x0c14,	16,	{0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x33, 0xae, 0x05, 0x0d, 0x74, 0x13, 0x2e, 0xf5, 0x82, 0xe4, 0x34} },
+{ 0x0c24,	16,	{0x0f, 0xf5, 0x83, 0xe5, 0x33, 0xf0, 0xaf, 0x0f, 0x7a, 0x0f, 0x7b, 0x13, 0x12, 0x0d, 0x10, 0xaf} },
+{ 0x0c34,	11,	{0x0f, 0xad, 0x34, 0xab, 0x36, 0xaa, 0x35, 0x12, 0x0c, 0xf1, 0x22} },
+{ 0x0c3f,	16,	{0x8e, 0x32, 0x8f, 0x33, 0x8d, 0x34, 0x8a, 0x35, 0x8b, 0x36, 0xe4, 0xf5, 0x37, 0xe5, 0x37, 0xc3} },
+{ 0x0c4f,	16,	{0x95, 0x34, 0x50, 0x20, 0x05, 0x33, 0xe5, 0x33, 0xae, 0x32, 0x70, 0x02, 0x05, 0x32, 0x14, 0xff} },
+{ 0x0c5f,	16,	{0xe5, 0x36, 0x25, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x35, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x0b, 0xa7} },
+{ 0x0c6f,	5,	{0x05, 0x37, 0x80, 0xd9, 0x22} },
+{ 0x0c74,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x25, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0c84,	16,	{0x44, 0x01, 0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a} },
+{ 0x0c94,	13,	{0x0a, 0x89, 0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x03, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0ca1,	16,	{0xa9, 0x07, 0xe5, 0x0d, 0x70, 0x23, 0x90, 0x7f, 0xa5, 0xe0, 0x44, 0x80, 0xf0, 0xe9, 0x25, 0xe0} },
+{ 0x0cb1,	16,	{0x90, 0x7f, 0xa6, 0xf0, 0x8d, 0x08, 0xaf, 0x03, 0xa9, 0x07, 0x75, 0x09, 0x01, 0x8a, 0x0a, 0x89} },
+{ 0x0cc1,	11,	{0x0b, 0xe4, 0xf5, 0x0c, 0x75, 0x0d, 0x01, 0xd3, 0x22, 0xc3, 0x22} },
+{ 0x0ccc,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x06, 0x04, 0xe0, 0x44} },
+{ 0x0cdc,	16,	{0x02, 0xf0, 0x7f, 0xd0, 0x7e, 0x07, 0x12, 0x0d, 0x94, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x0cec,	5,	{0xe0, 0x44, 0x04, 0xf0, 0x22} },
+{ 0x0cf1,	16,	{0x12, 0x0c, 0x74, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d01,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d10,	16,	{0x12, 0x0c, 0xa1, 0xe5, 0x0d, 0x24, 0xfa, 0x60, 0x10, 0x14, 0x60, 0x07, 0x24, 0x07, 0x70, 0xf3} },
+{ 0x0d20,	15,	{0x7f, 0x08, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x07, 0x22, 0xe4, 0xf5, 0x0d, 0x7f, 0x06, 0x22} },
+{ 0x0d2f,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x0d3f,	11,	{0xab, 0x74, 0x04, 0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d4a,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x12, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x14, 0x7e, 0x00, 0x12} },
+{ 0x0d5a,	10,	{0x0d, 0x94, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x0d64,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01} },
+{ 0x0d74,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d7c,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xd2, 0x03, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x0d8c,	8,	{0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0d94,	16,	{0x8e, 0x38, 0x8f, 0x39, 0xe5, 0x39, 0x15, 0x39, 0xae, 0x38, 0x70, 0x02, 0x15, 0x38, 0x4e, 0x60} },
+{ 0x0da4,	7,	{0x05, 0x12, 0x0e, 0x00, 0x80, 0xee, 0x22} },
+{ 0x0dab,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x02, 0xf0, 0xd0} },
+{ 0x0dbb,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dc1,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x10, 0xf0, 0xd0} },
+{ 0x0dd1,	6,	{0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x0dd7,	16,	{0xae, 0x07, 0x7f, 0x21, 0x7d, 0x01, 0x74, 0x00, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0x0f, 0xab, 0x82} },
+{ 0x0de7,	5,	{0xfa, 0x12, 0x0d, 0x10, 0x22} },
+{ 0x0dec,	16,	{0x50, 0x0f, 0x00, 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x98, 0x88, 0x83, 0xc6} },
+{ 0x0dfc,	3,	{0xa1, 0x86, 0x8e} },
+{ 0x0dff,	1,	{0x00} },
+{ 0x0e00,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x0e10,	1,	{0x22} },
+{ 0x0e11,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x10, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x0e1f,	14,	{0x90, 0x7f, 0x00, 0xe5, 0x0e, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0xd3, 0x22} },
+{ 0x0e2d,	8,	{0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0e, 0xd3, 0x22} },
+{ 0x0e35,	8,	{0xe4, 0xf5, 0x0d, 0xd2, 0xe9, 0xd2, 0xaf, 0x22} },
+{ 0x0e3d,	3,	{0xd2, 0x00, 0x22} },
+{ 0x0e40,	2,	{0xd3, 0x22} },
+{ 0x0e42,	2,	{0xd3, 0x22} },
+{ 0x0e44,	2,	{0xd3, 0x22} },
+{ 0x0e46,	2,	{0xd3, 0x22} },
+{ 0x0e48,	2,	{0xd3, 0x22} },
+{ 0x0e4a,	2,	{0xd3, 0x22} },
+{ 0x0e4c,	1,	{0x32} },
+{ 0x0e4d,	1,	{0x32} },
+{ 0x0e4e,	1,	{0x32} },
+{ 0x0e4f,	1,	{0x32} },
+{ 0x0e50,	1,	{0x32} },
+{ 0x0e51,	1,	{0x32} },
+{ 0x0e52,	1,	{0x32} },
+{ 0x0e53,	1,	{0x32} },
+{ 0x0e54,	1,	{0x32} },
+{ 0x0e55,	1,	{0x32} },
+{ 0x0e56,	1,	{0x32} },
+{ 0x0e57,	1,	{0x32} },
+{ 0x0e58,	1,	{0x32} },
+{ 0x0e59,	1,	{0x32} },
+{ 0x0e5a,	1,	{0x32} },
+{ 0x0e5b,	1,	{0x32} },
+{ 0x1100,	16,	{0x12, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x47, 0x05, 0x10, 0x27, 0x01, 0x00, 0x01, 0x02} },
+{ 0x1110,	16,	{0x00, 0x01, 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x03, 0xa0, 0x00, 0x09, 0x04, 0x00, 0x00, 0x02} },
+{ 0x1120,	16,	{0xff, 0x00, 0x00, 0x04, 0x07, 0x05, 0x82, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1130,	16,	{0x00, 0x00, 0x04, 0x03, 0x09, 0x04, 0x26, 0x03, 0x41, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x68, 0x00} },
+{ 0x1140,	16,	{0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x43, 0x00, 0x68, 0x00, 0x69, 0x00, 0x70, 0x00, 0x73, 0x00} },
+{ 0x1150,	16,	{0x2c, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x28, 0x03, 0x46, 0x00} },
+{ 0x1160,	16,	{0x69, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x77, 0x00, 0x61, 0x00, 0x72, 0x00, 0x65, 0x00, 0x20, 0x00} },
+{ 0x1170,	16,	{0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x57, 0x00, 0x6f, 0x00, 0x72, 0x00} },
+{ 0x1180,	16,	{0x6b, 0x00, 0x73, 0x00, 0x2a, 0x03, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x66, 0x00, 0x69, 0x00} },
+{ 0x1190,	16,	{0x67, 0x00, 0x75, 0x00, 0x72, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00} },
+{ 0x11a0,	16,	{0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x22, 0x03} },
+{ 0x11b0,	16,	{0x49, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00} },
+{ 0x11c0,	16,	{0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00} },
+{ 0x11d0,	2,	{0x00, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/stopusb linux.18p8/drivers/usb/stopusb
--- linux.vanilla/drivers/usb/stopusb	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/stopusb	Thu Jan  1 01:00:00 1970
@@ -1,7 +0,0 @@
-#!/bin/sh
-
-killall ohci-control
-
-sleep 2
-
-rmmod usb-ohci
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/uhci-debug.c linux.18p8/drivers/usb/uhci-debug.c
--- linux.vanilla/drivers/usb/uhci-debug.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/uhci-debug.c	Thu Jan  1 01:00:00 1970
@@ -1,168 +0,0 @@
-/*
- * UHCI-specific debugging code. Invaluable when something
- * goes wrong, but don't get in my face.
- *
- * (C) Copyright 1999 Linus Torvalds
- */
-
-#include <linux/kernel.h>
-#include <asm/io.h>
-
-#include "uhci.h"
-
-void show_td(struct uhci_td * td)
-{
-	printk("%08x ", td->link);
-	printk("%se%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
-		((td->status >> 29) & 1) ? "SPD " : "",
-		((td->status >> 27) & 3),
-		((td->status >> 26) & 1) ? "LS " : "",
-		((td->status >> 25) & 1) ? "IOS " : "",
-		((td->status >> 24) & 1) ? "IOC " : "",
-		((td->status >> 23) & 1) ? "Active " : "",
-		((td->status >> 22) & 1) ? "Stalled " : "",
-		((td->status >> 21) & 1) ? "DataBufErr " : "",
-		((td->status >> 20) & 1) ? "Babble " : "",
-		((td->status >> 19) & 1) ? "NAK " : "",
-		((td->status >> 18) & 1) ? "CRC/Timeo " : "",
-		((td->status >> 17) & 1) ? "BitStuff " : "",
-		td->status & 0x7ff);
-	printk("MaxLen=%x %sEndPt=%x Dev=%x, PID=%x ",
-		td->info >> 21,
-		 ((td->info >> 19) & 1) ? "DT " : "",
-		 (td->info >> 15) & 15,
-		 (td->info >> 8) & 127,
-		 td->info & 0xff);
-	printk("(buf=%08x)\n", td->buffer);
-}
-
-static void show_sc(int port, unsigned short status)
-{
-	printk("  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
-		port,
-		status,
-		(status & (1 << 12)) ? " PortSuspend" : "",
-		(status & (1 << 9)) ? " PortReset" : "",
-		(status & (1 << 8)) ? " LowSpeed" : "",
-		(status & 0x40) ? " ResumeDetect" : "",
-		(status & 0x08) ? " EnableChange" : "",
-		(status & 0x04) ? " PortEnabled" : "",
-		(status & 0x02) ? " ConnectChange" : "",
-		(status & 0x01) ? " PortConnected" : "");
-}
-
-void show_status(struct uhci *uhci)
-{
-	unsigned int io_addr = uhci->io_addr;
-	unsigned short usbcmd, usbstat, usbint, usbfrnum;
-	unsigned int flbaseadd;
-	unsigned char sof;
-	unsigned short portsc1, portsc2;
-
-	usbcmd    = inw(io_addr + 0);
-	usbstat   = inw(io_addr + 2);
-	usbint    = inw(io_addr + 4);
-	usbfrnum  = inw(io_addr + 6);
-	flbaseadd = inl(io_addr + 8);
-	sof       = inb(io_addr + 12);
-	portsc1   = inw(io_addr + 16);
-	portsc2   = inw(io_addr + 18);
-
-	printk("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
-		usbcmd,
-		(usbcmd & 0x80) ? " Maxp64" : " Maxp32",
-		(usbcmd & 0x40) ? " CF" : "",
-		(usbcmd & 0x20) ? " SWDBG" : "",
-		(usbcmd & 0x10) ? " FGR" : "",
-		(usbcmd & 0x08) ? " EGSM" : "",
-		(usbcmd & 0x04) ? " GRESET" : "",
-		(usbcmd & 0x02) ? " HCRESET" : "",
-		(usbcmd & 0x01) ? " RS" : "");
-
-	printk("  usbstat   =     %04x   %s%s%s%s%s%s\n",
-		usbstat,
-		(usbstat & 0x20) ? " HCHalted" : "",
-		(usbstat & 0x10) ? " HostControllerProcessError" : "",
-		(usbstat & 0x08) ? " HostSystemError" : "",
-		(usbstat & 0x04) ? " ResumeDetect" : "",
-		(usbstat & 0x02) ? " USBError" : "",
-		(usbstat & 0x01) ? " USBINT" : "");
-
-	printk("  usbint    =     %04x\n", usbint);
-	printk("  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1, 0xfff & (4*(unsigned int)usbfrnum));
-	printk("  flbaseadd = %08x\n", flbaseadd);
-	printk("  sof       =       %02x\n", sof);
-	show_sc(1, portsc1);
-	show_sc(2, portsc2);
-}
-
-#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x))
-
-struct uhci_td * uhci_link_to_td(unsigned int link)
-{
-	if (link & 1)
-		return NULL;
-
-	return bus_to_virt(link & ~15);
-}
-
-void show_queue(struct uhci_qh *qh)
-{
-	struct uhci_td *td;
-	int i = 0;
-
-#if 0
-	printk("    link = %p, element = %p\n", qh->link, qh->element);
-#endif
-	if(!qh->element) {
-		printk("    td 0 = NULL\n");
-		return;
-	}
-
-	for(td = uhci_link_to_td(qh->element); td; 
-	    td = uhci_link_to_td(td->link)) {
-		printk("    td %d = %p\n", i++, td);
-		printk("    ");
-		show_td(td);
-	}
-}
-
-int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
-{
-	int j;
-
-	for (j = 0; j < UHCI_MAXQH; j++)
-		if (qh == uhci->root_hub->qh + j)
-			return 1;
-
-	return 0;
-}
-
-static const char *qh_names[] = {"isochronous", "interrupt2", "interrupt4",
-				 "interrupt8", "interrupt16", "interrupt32",
-				 "interrupt64", "interrupt128", "interrupt256",
-				 "control", "bulk0", "bulk1", "bulk2", "bulk3",
-				 "unused", "unused"};
-
-void show_queues(struct uhci *uhci)
-{
-	int i;
-	struct uhci_qh *qh;
-
-	for (i = 0; i < UHCI_MAXQH; ++i) {
-		printk("  %s:\n", qh_names[i]);
-#if 0
-		printk("  qh #%d, %p\n", i, virt_to_bus(uhci->root_hub->qh + i));
-		show_queue(uhci->root_hub->qh + i);
-#endif
-
-		qh = uhci_link_to_qh(uhci->root_hub->qh[i].link);
-		for (; qh; qh = uhci_link_to_qh(qh->link)) {
-			if (is_skeleton_qh(uhci, qh))
-				break;
-
-			show_queue(qh);
-		}
-	}
-}
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/uhci-debug.h linux.18p8/drivers/usb/uhci-debug.h
--- linux.vanilla/drivers/usb/uhci-debug.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/uhci-debug.h	Fri Sep 15 15:13:11 2000
@@ -0,0 +1,316 @@
+/*
+ * UHCI-specific debugging code. Invaluable when something
+ * goes wrong, but don't get in my face.
+ *
+ * Kernel visible pointers are surrounded in []'s and bus
+ * visible pointers are surrounded in ()'s
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+#include "uhci.h"
+
+void uhci_show_td(struct uhci_td *td)
+{
+	char *spid;
+
+	printk("%08x ", td->link);
+	printk("e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+		((td->status >> 27) & 3),
+		(td->status & TD_CTRL_SPD) ?      "SPD " : "",
+		(td->status & TD_CTRL_LS) ?       "LS " : "",
+		(td->status & TD_CTRL_IOC) ?      "IOC " : "",
+		(td->status & TD_CTRL_ACTIVE) ?   "Active " : "",
+		(td->status & TD_CTRL_STALLED) ?  "Stalled " : "",
+		(td->status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
+		(td->status & TD_CTRL_BABBLE) ?   "Babble " : "",
+		(td->status & TD_CTRL_NAK) ?      "NAK " : "",
+		(td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+		(td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
+		td->status & 0x7ff);
+
+	switch (td->info & 0xff) {
+		case USB_PID_SETUP:
+			spid = "SETUP";
+			break;
+		case USB_PID_OUT:
+			spid = "OUT";
+			break;
+		case USB_PID_IN:
+			spid = "IN";
+			break;
+		default:
+			spid = "?";
+			break;
+	}
+
+	printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
+		td->info >> 21,
+		((td->info >> 19) & 1),
+		(td->info >> 15) & 15,
+		(td->info >> 8) & 127,
+		(td->info & 0xff),
+		spid);
+	printk("(buf=%08x)\n", td->buffer);
+}
+
+static void uhci_show_sc(int port, unsigned short status)
+{
+	printk("  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
+		port,
+		status,
+		(status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+		(status & USBPORTSC_PR) ?   "PortReset " : "",
+		(status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+		(status & USBPORTSC_RD) ?   "ResumeDetect " : "",
+		(status & USBPORTSC_PEC) ?  "EnableChange " : "",
+		(status & USBPORTSC_PE) ?   "PortEnabled " : "",
+		(status & USBPORTSC_CSC) ?  "ConnectChange " : "",
+		(status & USBPORTSC_CCS) ?  "PortConnected " : "");
+}
+
+void uhci_show_status(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	unsigned short usbcmd, usbstat, usbint, usbfrnum;
+	unsigned int flbaseadd;
+	unsigned char sof;
+	unsigned short portsc1, portsc2;
+
+	usbcmd    = inw(io_addr + 0);
+	usbstat   = inw(io_addr + 2);
+	usbint    = inw(io_addr + 4);
+	usbfrnum  = inw(io_addr + 6);
+	flbaseadd = inl(io_addr + 8);
+	sof       = inb(io_addr + 12);
+	portsc1   = inw(io_addr + 16);
+	portsc2   = inw(io_addr + 18);
+
+	printk("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
+		usbcmd,
+		(usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
+		(usbcmd & USBCMD_CF) ?      "CF " : "",
+		(usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
+		(usbcmd & USBCMD_FGR) ?     "FGR " : "",
+		(usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
+		(usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
+		(usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+		(usbcmd & USBCMD_RS) ?      "RS " : "");
+
+	printk("  usbstat   =     %04x   %s%s%s%s%s%s\n",
+		usbstat,
+		(usbstat & USBSTS_HCH) ?    "HCHalted " : "",
+		(usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
+		(usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
+		(usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
+		(usbstat & USBSTS_ERROR) ?  "USBError " : "",
+		(usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+	printk("  usbint    =     %04x\n", usbint);
+	printk("  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1,
+		0xfff & (4*(unsigned int)usbfrnum));
+	printk("  flbaseadd = %08x\n", flbaseadd);
+	printk("  sof       =       %02x\n", sof);
+	uhci_show_sc(1, portsc1);
+	uhci_show_sc(2, portsc2);
+}
+
+#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x))
+
+struct uhci_td *uhci_link_to_td(unsigned int link)
+{
+	if (link & UHCI_PTR_TERM)
+		return NULL;
+
+	return bus_to_virt(link & ~UHCI_PTR_BITS);
+}
+
+void uhci_show_urb_queue(struct urb *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct list_head *head, *tmp;
+	int i, checked = 0, prevactive = 0;
+
+	printk("  URB [%p] urbp [%p]\n", urb, urbp);
+
+	if (urbp->qh)
+		printk("    QH [%p]\n", urbp->qh);
+	else
+		printk("    QH [%p] element (%08x) link (%08x)\n", urbp->qh,
+			urbp->qh->element, urbp->qh->link);
+
+	i = 0;
+
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		printk("      td %d: [%p]\n", i++, td);
+		printk("      ");
+		uhci_show_td(td);
+
+		if (i > 10 && !checked && prevactive && tmp != head) {
+			struct list_head *ntmp = tmp;
+			struct uhci_td *ntd = td;
+			int active = 1, ni = i;
+
+			checked = 1;
+
+			while (ntmp != head && ntmp->next != head && active) {
+				ntd = list_entry(ntmp, struct uhci_td, list);
+
+				ntmp = ntmp->next;
+
+				active = ntd->status & TD_CTRL_ACTIVE;
+
+				ni++;
+			}
+
+			if (active && ni > i) {
+				printk("      [skipped %d active TD's]\n", ni - i);
+				tmp = ntmp;
+				td = ntd;
+				i = ni;
+			}
+		}
+
+		prevactive = td->status & TD_CTRL_ACTIVE;
+	}
+}
+
+void uhci_show_queue(struct uhci_qh *qh)
+{
+	struct uhci_td *td, *first;
+	int i = 0, count = 1000;
+
+	if (qh->element & UHCI_PTR_QH)
+		printk("      Element points to QH (bug?)\n");
+
+	if (qh->element & UHCI_PTR_DEPTH)
+		printk("      Depth traverse\n");
+
+	if (qh->element & UHCI_PTR_TERM)
+		printk("      Terminate\n");
+
+	if (!(qh->element & ~UHCI_PTR_BITS)) {
+		printk("      td 0: [NULL]\n");
+		return;
+	}
+
+	first = uhci_link_to_td(qh->element);
+
+	/* Make sure it doesn't runaway */
+	for (td = first; td && count > 0; 
+	     td = uhci_link_to_td(td->link), --count) {
+		printk("      td %d: [%p]\n", i++, td);
+		printk("      ");
+		uhci_show_td(td);
+
+		if (td == uhci_link_to_td(td->link)) {
+			printk(KERN_ERR "td links to itself!\n");
+			break;
+		}
+	}
+}
+
+static int uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
+{
+	int j;
+
+	for (j = 0; j < UHCI_NUM_SKELTD; j++)
+		if (td == uhci->skeltd + j)
+			return 1;
+
+	return 0;
+}
+
+static int uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	int j;
+
+	for (j = 0; j < UHCI_NUM_SKELQH; j++)
+		if (qh == uhci->skelqh + j)
+			return 1;
+
+	return 0;
+}
+
+static const char *td_names[] = {"interrupt1", "interrupt2", "interrupt4",
+				 "interrupt8", "interrupt16", "interrupt32",
+				 "interrupt64", "interrupt128", "interrupt256" };
+static const char *qh_names[] = { "control", "bulk" };
+
+void uhci_show_queues(struct uhci *uhci)
+{
+	int i, isqh = 0;
+	struct uhci_qh *qh;
+	struct uhci_td *td;
+
+	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+		int shown = 0;
+
+		td = uhci_link_to_td(uhci->fl->frame[i]);
+		if (td)
+			isqh = uhci->fl->frame[i] & UHCI_PTR_QH;
+		while (td && !isqh) {
+			if (uhci_is_skeleton_td(uhci, td))
+				break;
+
+			if (!shown) {
+				printk("   Frame %d\n", i);
+				shown = 1;
+			}
+
+			printk("[%p] ", td);
+
+			uhci_show_td(td);
+			td = uhci_link_to_td(td->link);
+			if (td)
+				isqh = td->link & UHCI_PTR_QH;
+		}
+	}
+	for (i = 0; i < UHCI_NUM_SKELTD; ++i) {
+		printk("  %s: [%p] (%08x)\n", td_names[i],
+			&uhci->skeltd[i],
+			uhci->skeltd[i].link);
+
+		td = uhci_link_to_td(uhci->skeltd[i].link);
+		if (td)
+			isqh = uhci->skeltd[i].link & UHCI_PTR_QH;
+		while (td && !isqh) {
+			if (uhci_is_skeleton_td(uhci, td))
+				break;
+
+			printk("[%p] ", td);
+
+			uhci_show_td(td);
+			td = uhci_link_to_td(td->link);
+			if (td)
+				isqh = td->link & UHCI_PTR_QH;
+		}
+	}
+	for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
+		printk("  %s: [%p] (%08x) (%08x)\n", qh_names[i],
+			&uhci->skelqh[i],
+			uhci->skelqh[i].link, uhci->skelqh[i].element);
+
+		qh = uhci_link_to_qh(uhci->skelqh[i].link);
+		for (; qh; qh = uhci_link_to_qh(qh->link)) {
+			if (uhci_is_skeleton_qh(uhci, qh))
+				break;
+
+			printk("    [%p] (%08x) (%08x)\n",
+				qh, qh->link, qh->element);
+
+			uhci_show_queue(qh);
+		}
+	}
+}
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/uhci.c linux.18p8/drivers/usb/uhci.c
--- linux.vanilla/drivers/usb/uhci.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/uhci.c	Fri Sep  1 13:51:30 2000
@@ -2,15 +2,18 @@
  * Universal Host Controller Interface driver for USB.
  *
  * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@sventech.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
  *
  * Intel documents this fairly well, and as far as I know there
  * are no royalties or anything like that, but even so there are
  * people who decided that they want to do the same thing in a
  * completely different way.
  *
- * Oh, well. The intel version is the more common by far. As such,
- * that's the one I care about right now.
- *
  * WARNING! The USB documentation is downright evil. Most of it
  * is just crap, written by a committee. You're better off ignoring
  * most of it, the important stuff is:
@@ -18,9 +21,6 @@
  *  - working around the horridness of the rest
  */
 
-/* 4/4/1999 added data toggle for interrupt pipes -keryan */
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
@@ -30,726 +30,1934 @@
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+//#define DEBUG
+#include <linux/usb.h>
 
-#include <asm/spinlock.h>
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 
 #include "uhci.h"
-#include "inits.h"
+#include "uhci-debug.h"
 
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-static int handle_apm_event(apm_event_t event);
-static int apm_resume = 0;
-#endif
+#include <linux/pm.h>
+static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);
+
+static int debug = 1;
+MODULE_PARM(debug, "i");
 
-#define compile_assert(x) do { switch (0) { case 1: case !(x): } } while (0)
+static kmem_cache_t *uhci_td_cachep;
+static kmem_cache_t *uhci_qh_cachep;
+static kmem_cache_t *uhci_up_cachep;	/* urb_priv */
 
-static struct wait_queue *uhci_configure = NULL;
+static LIST_HEAD(uhci_list);
+
+static int rh_submit_urb(struct urb *urb);
+static int rh_unlink_urb(struct urb *urb);
+static int uhci_get_current_frame_number(struct usb_device *dev);
+static int uhci_unlink_generic(struct urb *urb);
+static int uhci_unlink_urb(struct urb *urb);
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+/* If a transfer is still active after this much time, turn off FSBR */
+#define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
 
 /*
- * Return the result of a TD..
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
  */
-static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td)
+static int uhci_alloc_dev(struct usb_device *dev)
 {
-	unsigned int status;
+	return 0;
+}
 
-	status = (td->status >> 16) & 0xff;
+static int uhci_free_dev(struct usb_device *dev)
+{
+	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
+	struct list_head *tmp, *head = &uhci->urb_list;
+	unsigned long flags;
 
-	/* Some debugging code */
-	if (status) {
-		int i = 10;
-		struct uhci_td *tmp = dev->control_td;
-		printk("uhci_td_result() failed with status %d\n", status);
-		show_status(dev->uhci);
-		do {
-			show_td(tmp);
-			tmp++;
-			if (!--i)
-				break;
-		} while (tmp <= td);
+	/* Walk through the entire URB list and forcefully remove any */
+	/*  URBs that are still active for that device */
+	nested_lock(&uhci->urblist_lock, flags);
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		if (u->dev == dev)
+			uhci_unlink_urb(u);
 	}
-	return status;		
+	nested_unlock(&uhci->urblist_lock, flags);
+
+	return 0;
 }
 
-/*
- * Inserts a td into qh list at the top.
- *
- * Careful about atomicity: even on UP this
- * requires a locked access due to the concurrent
- * DMA engine.
- *
- * NOTE! This assumes that first->last is a valid
- * list of TD's with the proper backpointers set
- * up and all..
- */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *first, struct uhci_td *last)
+static void uhci_add_urb_list(struct uhci *uhci, struct urb *urb)
 {
-	unsigned int link = qh->element;
-	unsigned int new = 4 | virt_to_bus(first);
+	unsigned long flags;
 
-	for (;;) {
-		unsigned char success;
+	nested_lock(&uhci->urblist_lock, flags);
+	list_add(&urb->urb_list, &uhci->urb_list);
+	nested_unlock(&uhci->urblist_lock, flags);
+}
 
-		last->link = link;
-		first->backptr = &qh->element;
-		asm volatile("lock ; cmpxchg %4,%2 ; sete %0"
-			:"=q" (success), "=a" (link)
-			:"m" (qh->element), "1" (link), "r" (new)
-			:"memory");
-		if (success) {
-			/* Was there a successor entry? Fix it's backpointer.. */
-			if ((link & 1) == 0) {
-				struct uhci_td *next = bus_to_virt(link & ~15);
-				next->backptr = &last->link;
-			}
-			break;
-		}
+static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb)
+{
+	unsigned long flags;
+
+	nested_lock(&uhci->urblist_lock, flags);
+	if (!list_empty(&urb->urb_list)) {
+		list_del(&urb->urb_list);
+		INIT_LIST_HEAD(&urb->urb_list);
 	}
+	nested_unlock(&uhci->urblist_lock, flags);
 }
 
-static inline void uhci_insert_td_in_qh(struct uhci_qh *qh, struct uhci_td *td)
+void uhci_set_next_interrupt(struct uhci *uhci)
 {
-	uhci_insert_tds_in_qh(qh, td, td);
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	uhci->skel_term_td.status |= TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 }
 
-static void uhci_insert_qh(struct uhci_qh *qh, struct uhci_qh *newqh)
+void uhci_clear_next_interrupt(struct uhci *uhci)
 {
-	newqh->link = qh->link;
-	qh->link = virt_to_bus(newqh) | 2;
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	uhci->skel_term_td.status &= ~TD_CTRL_IOC;
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 }
 
-static void uhci_remove_qh(struct uhci_qh *qh, struct uhci_qh *remqh)
+static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
 {
-	unsigned int remphys = virt_to_bus(remqh);
-	struct uhci_qh *lqh = qh;
+	struct uhci_td *td;
 
-	while ((lqh->link & ~0xF) != remphys) {
-		if (lqh->link & 1)
-			break;
+	td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+	if (!td)
+		return NULL;
+
+	td->link = UHCI_PTR_TERM;
+	td->buffer = 0;
+
+	td->frameptr = NULL;
+	td->nexttd = td->prevtd = NULL;
+	td->dev = dev;
+	INIT_LIST_HEAD(&td->list);
+
+	usb_inc_dev_use(dev);
+
+	return td;
+}
+
+static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
+		__u32 info, __u32 buffer)
+{
+	td->status = status;
+	td->info = info;
+	td->buffer = buffer;
+}
+
+static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+
+	/* Fix the linked list pointers */
+	td->nexttd = skeltd->nexttd;
+	td->prevtd = skeltd;
+	if (skeltd->nexttd)
+		skeltd->nexttd->prevtd = td;
+	skeltd->nexttd = td;
+
+	td->link = skeltd->link;
+	skeltd->link = virt_to_bus(td);
+
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+/*
+ * We insert Isochronous transfers directly into the frame list at the
+ * beginning
+ * The layout looks as follows:
+ * frame list pointer -> iso td's (if any) ->
+ * periodic interrupt td (if frame 0) -> irq td's -> control qh -> bulk qh
+ */
+
+static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
+{
+	unsigned long flags;
+	struct uhci_td *nexttd;
 
-		lqh = bus_to_virt(lqh->link & ~0xF);
+	framenum %= UHCI_NUMFRAMES;
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+
+	td->frameptr = &uhci->fl->frame[framenum];
+	td->link = uhci->fl->frame[framenum];
+	if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+		nexttd = (struct uhci_td *)uhci_ptr_to_virt(td->link);
+		td->nexttd = nexttd;
+		nexttd->prevtd = td;
+		nexttd->frameptr = NULL;
 	}
+	uhci->fl->frame[framenum] = virt_to_bus(td);
+
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
 
-	if (lqh->link & 1) {
-		printk("couldn't find qh in chain!\n");
+static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
+{
+	unsigned long flags;
+
+	/* If it's not inserted, don't remove it */
+	if (!td->frameptr && !td->prevtd && !td->nexttd)
 		return;
-	}
 
-	lqh->link = remqh->link;
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	if (td->frameptr) {
+		*(td->frameptr) = td->link;
+		if (td->nexttd) {
+			td->nexttd->frameptr = td->frameptr;
+			td->nexttd->prevtd = NULL;
+			td->nexttd = NULL;
+		}
+		td->frameptr = NULL;
+	} else {
+		if (td->prevtd) {
+			td->prevtd->nexttd = td->nexttd;
+			td->prevtd->link = td->link;
+		}
+		if (td->nexttd)
+			td->nexttd->prevtd = td->prevtd;
+		td->prevtd = td->nexttd = NULL;
+	}
+	td->link = UHCI_PTR_TERM;
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 }
 
 /*
- * Removes td from qh if present.
- *
- * NOTE! We keep track of both forward and back-pointers,
- * so this should be trivial, right?
- *
- * Wrong. While all TD insert/remove operations are synchronous
- * on the CPU, the UHCI controller can (and does) play with the
- * very first forward pointer. So we need to validate the backptr
- * before we change it, so that we don't by mistake reset the QH
- * head to something old.
+ * Inserts a td into qh list at the top.
  */
-static void uhci_remove_td(struct uhci_td *td)
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
 {
-	unsigned int *backptr = td->backptr;
-	unsigned int link = td->link;
-	unsigned int me;
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td, *prevtd;
+
+	if (!urbp)
+		return;
 
-	if (!backptr)
+	head = &urbp->list;
+	tmp = head->next;
+	if (head == tmp)
 		return;
 
-	td->backptr = NULL;
+	td = list_entry(tmp, struct uhci_td, list);
 
-	/*
-	 * This is the easy case: the UHCI will never change "td->link",
-	 * so we can always just look at that and fix up the backpointer
-	 * of any next element..
-	 */
-	if (!(link & 1)) {
-		struct uhci_td *next = bus_to_virt(link & ~15);
-		next->backptr = backptr;
+	/* Add the first TD to the QH element pointer */
+	qh->element = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
+
+	prevtd = td;
+
+	/* Then link the rest of the TD's */
+	tmp = tmp->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		prevtd->link = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
+
+		prevtd = td;
 	}
 
-	/*
-	 * The nasty case is "backptr->next", which we need to
-	 * update to "link" _only_ if "backptr" still points
-	 * to us (it may not: maybe backptr is a QH->element
-	 * pointer and the UHCI has changed the value).
-	 */
-	me = virt_to_bus(td) | (0xe & *backptr);
-	asm volatile("lock ; cmpxchg %0,%1"
-		:
-		:"r" (link), "m" (*backptr), "a" (me)
-		:"memory");
+	prevtd->link = UHCI_PTR_TERM;
+}
+
+static void uhci_free_td(struct uhci_td *td)
+{
+	if (!list_empty(&td->list))
+		dbg("td is still in URB list!");
+
+	if (td->dev)
+		usb_dec_dev_use(td->dev);
+
+	kmem_cache_free(uhci_td_cachep, td);
 }
 
-static struct uhci_qh *uhci_qh_allocate(struct uhci_device *dev)
+static struct uhci_qh *uhci_alloc_qh(struct usb_device *dev)
 {
 	struct uhci_qh *qh;
-	int inuse;
 
-	qh = dev->qh;
-	for (; (inuse = test_and_set_bit(0, &qh->inuse)) != 0 && qh < &dev->qh[UHCI_MAXQH]; qh++)
-		;
+	qh = kmem_cache_alloc(uhci_qh_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+	if (!qh)
+		return NULL;
+
+	qh->element = UHCI_PTR_TERM;
+	qh->link = UHCI_PTR_TERM;
+
+	qh->dev = dev;
+	qh->prevqh = qh->nextqh = NULL;
+
+	INIT_LIST_HEAD(&qh->remove_list);
 
-	if (!inuse)
-		return(qh);
+	usb_inc_dev_use(dev);
 
-	printk("ran out of qh's for dev %p\n", dev);
-	return(NULL);
+	return qh;
 }
 
-static void uhci_qh_deallocate(struct uhci_qh *qh)
+static void uhci_free_qh(struct uhci_qh *qh)
 {
-	if (qh->element != 1)
-		printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element);
+	if (qh->dev)
+		usb_dec_dev_use(qh->dev);
 
-	qh->element = 1;
-	qh->link = 1;
-
-	clear_bit(0, &qh->inuse);
+	kmem_cache_free(uhci_qh_cachep, qh);
 }
 
-static struct uhci_td *uhci_td_allocate(struct uhci_device *dev)
+static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh)
 {
-	struct uhci_td *td;
-	int inuse;
+	unsigned long flags;
 
-	td = dev->td;
-	for (; (inuse = test_and_set_bit(0, &td->inuse)) != 0 && td < &dev->td[UHCI_MAXTD]; td++)
-		;
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
 
-	if (!inuse)
-		return(td);
+	/* Fix the linked list pointers */
+	qh->nextqh = skelqh->nextqh;
+	qh->prevqh = skelqh;
+	if (skelqh->nextqh)
+		skelqh->nextqh->prevqh = qh;
+	skelqh->nextqh = qh;
 
-	printk("ran out of td's for dev %p\n", dev);
-	return(NULL);
+	qh->link = skelqh->link;
+	skelqh->link = virt_to_bus(qh) | UHCI_PTR_QH;
+
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 }
 
-/*
- * This MUST only be called when it has been removed from a QH already (or
- * the QH has been removed from the skeleton
- */
-static void uhci_td_deallocate(struct uhci_td *td)
+static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
 {
-	td->link = 1;
+	unsigned long flags;
+	int delayed;
+
+	/* If the QH isn't queued, then we don't need to delay unlink it */
+	delayed = (qh->prevqh || qh->nextqh);
+
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+	if (qh->prevqh) {
+		qh->prevqh->nextqh = qh->nextqh;
+		qh->prevqh->link = qh->link;
+	}
+	if (qh->nextqh)
+		qh->nextqh->prevqh = qh->prevqh;
+	qh->prevqh = qh->nextqh = NULL;
+	qh->element = qh->link = UHCI_PTR_TERM;
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+
+	if (delayed) {
+		spin_lock_irqsave(&uhci->qh_remove_lock, flags);
 
-	clear_bit(0, &td->inuse);
+		/* Check to see if the remove list is empty */
+		/* Set the IOC bit to force an interrupt so we can remove the QH */
+		if (list_empty(&uhci->qh_remove_list))
+			uhci_set_next_interrupt(uhci);
+
+		/* Add it */
+		list_add(&qh->remove_list, &uhci->qh_remove_list);
+
+		spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+	} else
+		uhci_free_qh(qh);
 }
 
-/*
- * UHCI interrupt list operations..
- */
-static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t uhci_append_urb_lock = SPIN_LOCK_UNLOCKED;
 
-static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td, usb_device_irq completed, void *dev_id)
+/* This function will append one URB's QH to another URB's QH. This is for */
+/*  USB_QUEUE_BULK support */
+static void uhci_append_queued_urb(struct uhci *uhci, struct urb *eurb, struct urb *urb)
 {
+	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
+	struct list_head *tmp;
+	struct uhci_td *td, *ltd;
 	unsigned long flags;
 
-	td->completed = completed;
-	td->dev_id = dev_id;
+	eurbp = eurb->hcpriv;
+	urbp = urb->hcpriv;
+
+	spin_lock_irqsave(&uhci_append_urb_lock, flags);
+
+	/* Find the beginning URB in the queue */
+	if (eurbp->queued) {
+		struct list_head *head = &eurbp->urb_queue_list;
 
-	spin_lock_irqsave(&irqlist_lock, flags);
-	list_add(&td->irq_list, &uhci->interrupt_list);
-	spin_unlock_irqrestore(&irqlist_lock, flags);
+		tmp = head->next;
+		while (tmp != head) {
+			struct urb_priv *turbp =
+				list_entry(tmp, struct urb_priv, urb_queue_list);
+
+			tmp = tmp->next;
+
+			if (!turbp->queued)
+				break;
+		}
+	} else
+		tmp = &eurbp->urb_queue_list;
+
+	furbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+
+	tmp = furbp->urb_queue_list.prev;
+	lurbp = list_entry(tmp, struct urb_priv, urb_queue_list);
+
+	/* Add this one to the end */
+	list_add_tail(&urbp->urb_queue_list, &furbp->urb_queue_list);
+
+	/* Grab the last TD from the last URB */
+	ltd = list_entry(lurbp->list.prev, struct uhci_td, list);
+
+	/* Grab the first TD from the first URB */
+	td = list_entry(urbp->list.next, struct uhci_td, list);
+
+	/* No breadth since this will only be called for bulk transfers */
+	ltd->link = virt_to_bus(td);
+
+	spin_unlock_irqrestore(&uhci_append_urb_lock, flags);
 }
 
-static void uhci_remove_irq_list(struct uhci_td *td)
+static void uhci_delete_queued_urb(struct uhci *uhci, struct urb *urb)
 {
+	struct urb_priv *urbp, *nurbp;
 	unsigned long flags;
 
-	spin_lock_irqsave(&irqlist_lock, flags);
-	list_del(&td->irq_list);
-	spin_unlock_irqrestore(&irqlist_lock, flags);
+	urbp = urb->hcpriv;
+
+	spin_lock_irqsave(&uhci_append_urb_lock, flags);
+
+	nurbp = list_entry(urbp->urb_queue_list.next, struct urb_priv,
+			urb_queue_list);
+
+	if (!urbp->queued) {
+		/* We're the head, so just insert the QH for the next URB */
+		uhci_insert_qh(uhci, &uhci->skel_bulk_qh, nurbp->qh);
+		nurbp->queued = 0;
+	} else {
+		struct urb_priv *purbp;
+		struct uhci_td *ptd;
+
+		/* We're somewhere in the middle (or end). A bit trickier */
+		/*  than the head scenario */
+		purbp = list_entry(urbp->urb_queue_list.prev, struct urb_priv,
+				urb_queue_list);
+
+		ptd = list_entry(purbp->list.prev, struct uhci_td, list);
+		if (nurbp->queued)
+			/* Close the gap between the two */
+			ptd->link = virt_to_bus(list_entry(nurbp->list.next,
+					struct uhci_td, list));
+		else
+			/* The next URB happens to be the beggining, so */
+			/*  we're the last, end the chain */
+			ptd->link = UHCI_PTR_TERM;
+		
+	}
+
+	list_del(&urbp->urb_queue_list);
+
+	spin_unlock_irqrestore(&uhci_append_urb_lock, flags);
 }
 
-/*
- * Request a interrupt handler..
- */
-static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
 {
-	struct uhci_device *dev = usb_to_uhci(usb_dev);
-	struct uhci_td *td = uhci_td_allocate(dev);
-	struct uhci_qh *interrupt_qh = uhci_qh_allocate(dev);
+	struct urb_priv *urbp;
 
-	unsigned int destination, status;
+	urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+	if (!urbp)
+		return NULL;
 
-	/* Destination: pipe destination with INPUT */
-	destination = (pipe & 0x0007ff00)  |  0x69;
+	memset((void *)urbp, 0, sizeof(*urbp));
 
-	/* Status:    slow/fast,      Interrupt,   Active,    Short Packet Detect     Infinite Errors */
-	status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23)   |   (1 << 29)       |    (0 << 27);
+	urbp->inserttime = jiffies;
+	urbp->urb = urb;
+	
+	INIT_LIST_HEAD(&urbp->list);
+	INIT_LIST_HEAD(&urbp->urb_queue_list);
 
-	if(interrupt_qh->element != 1)
-		printk("interrupt_qh->element = 0x%x\n", 
-		       interrupt_qh->element);
+	urb->hcpriv = urbp;
 
-	td->link = 1;
-	td->status = status;			/* In */
-	td->info = destination | (7 << 21);	/* 8 bytes of data */
-	td->buffer = virt_to_bus(dev->data);
-	td->qh = interrupt_qh;
-	interrupt_qh->skel = &dev->uhci->root_hub->skel_int8_qh;
+	usb_inc_dev_use(urb->dev);
 
-	uhci_add_irq_list(dev->uhci, td, handler, dev_id);
+	return urbp;
+}
 
-	uhci_insert_td_in_qh(interrupt_qh, td);
+static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
-	/* Add it into the skeleton */
-	uhci_insert_qh(&dev->uhci->root_hub->skel_int8_qh, interrupt_qh);
-	return 0;
-}
+	td->urb = urb;
 
-/*
- * Control thread operations: we just mark the last TD
- * in a control thread as an interrupt TD, and wake up
- * the front-end on completion.
- *
- * We need to remove the TD from the lists (both interrupt
- * list and TD lists) by hand if something bad happens!
- */
-static struct wait_queue *control_wakeup;
+	list_add_tail(&td->list, &urbp->list);
+}
 
-static int uhci_control_completed(int status, void *buffer, void *dev_id)
+static void uhci_remove_td_from_urb(struct urb *urb, struct uhci_td *td)
 {
-	wake_up(&control_wakeup);
-	return 0;			/* Don't re-instate */
+	urb = NULL;	/* No warnings */
+
+	if (list_empty(&td->list))
+		return;
+
+	list_del(&td->list);
+	INIT_LIST_HEAD(&td->list);
+
+	td->urb = NULL;
 }
 
-/* td points to the last td in the list, which interrupts on completion */
-static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
+static void uhci_destroy_urb_priv(struct urb *urb)
 {
-	struct wait_queue wait = { current, NULL };
-	struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev);
-	struct uhci_td *curtd;
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp;
+	struct uhci *uhci;
+	struct uhci_td *td;
+	unsigned long flags;
 
-	current->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue(&control_wakeup, &wait);
+	spin_lock_irqsave(&urb->lock, flags);
 
-	uhci_add_irq_list(dev->uhci, last, uhci_control_completed, NULL);
-	
-	/* FIXME: This is kinda kludged */
-	/* Walk the TD list and update the QH pointer */
-	{
-	int maxcount = 100;
-
-	curtd = first;
-	do {
-		curtd->qh = ctrl_qh;
-		if (curtd->link & 1)
-			break;
+	urbp = (struct urb_priv *)urb->hcpriv;
+	if (!urbp)
+		goto unlock;
 
-		curtd = bus_to_virt(curtd->link & ~0xF);
-		if (!--maxcount) {
-			printk("runaway tds!\n");
-			break;
-		}
-	} while (1);
+	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
+		goto unlock;
+
+	uhci = urb->dev->bus->hcpriv;
+
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		uhci_remove_td_from_urb(urb, td);
+
+		uhci_remove_td(uhci, td);
+
+		uhci_free_td(td);
 	}
 
-	uhci_insert_tds_in_qh(ctrl_qh, first, last);
+	urb->hcpriv = NULL;
+	kmem_cache_free(uhci_up_cachep, urbp);
 
-	/* Add it into the skeleton */
-	uhci_insert_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh);
+	usb_dec_dev_use(urb->dev);
 
-	schedule_timeout(HZ/10);
+unlock:
+	spin_unlock_irqrestore(&urb->lock, flags);
+}
 
-	remove_wait_queue(&control_wakeup, &wait);
+static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
+{
+	unsigned long flags;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
-	/* Clean up in case it failed.. */
-	uhci_remove_irq_list(last);
+	if (!urbp)
+		return;
 
-#if 0
-	printk("Looking for tds [%p, %p]\n", dev->control_td, td);
-#endif
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
+
+	if (!urbp->fsbr) {
+		urbp->fsbr = 1;
+		if (!uhci->fsbr++)
+			uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+	}
+
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
+static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
+{
+	unsigned long flags;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	if (!urbp)
+		return;
 
-	/* Remove it from the skeleton */
-	uhci_remove_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh);
+	spin_lock_irqsave(&uhci->framelist_lock, flags);
 
-	uhci_qh_deallocate(ctrl_qh);
+	if (urbp->fsbr) {
+		urbp->fsbr = 0;
+		if (!--uhci->fsbr)
+			uhci->skel_term_qh.link = UHCI_PTR_TERM;
+	}
 
-	return uhci_td_result(dev, last);
+	spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 }
 
 /*
- * Send or receive a control message on a pipe.
- *
- * Note that the "pipe" structure is set up to map
- * easily to the uhci destination fields.
- *
- * A control message is built up from three parts:
- *  - The command itself
- *  - [ optional ] data phase
- *  - Status complete phase
- *
- * The data phase can be an arbitrary number of TD's
- * although we currently had better not have more than
- * 29 TD's here (we have 31 TD's allocated for control
- * operations, and two of them are used for command and
- * status).
+ * Map status to standard result codes
  *
- * 29 TD's is a minimum of 232 bytes worth of control
- * information, that's just ridiculously high. Most
- * control messages have just a few bytes of data.
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
+ * <dir_out> is True for output TDs and False for input TDs.
  */
-static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
+static int uhci_map_status(int status, int dir_out)
 {
-	struct uhci_device *dev = usb_to_uhci(usb_dev);
-	struct uhci_td *first, *td, *prevtd;
-	unsigned long destination, status;
-	int ret;
+	if (!status)
+		return 0;
+	if (status & TD_CTRL_BITSTUFF)			/* Bitstuff error */
+		return -EPROTO;
+	if (status & TD_CTRL_CRCTIMEO) {		/* CRC/Timeout */
+		if (dir_out)
+			return -ETIMEDOUT;
+		else
+			return -EILSEQ;
+	}
+	if (status & TD_CTRL_NAK)			/* NAK */
+		return -ETIMEDOUT;
+	if (status & TD_CTRL_BABBLE)			/* Babble */
+		return -EPIPE;
+	if (status & TD_CTRL_DBUFERR)			/* Buffer error */
+		return -ENOSR;
+	if (status & TD_CTRL_STALLED)			/* Stalled */
+		return -EPIPE;
+	if (status & TD_CTRL_ACTIVE)			/* Active */
+		return 0;
 
-	if (len > usb_maxpacket(usb_dev->maxpacketsize) * 29)
-		printk("Warning, too much data for a control packet, crashing\n");
+	return -EINVAL;
+}
 
-	first = td = uhci_td_allocate(dev);
+/*
+ * Control transfers
+ */
+static int uhci_submit_control(struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct uhci_td *td;
+	struct uhci_qh *qh;
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	unsigned char *data = urb->transfer_buffer;
 
-	/* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */
-	destination = (pipe & 0x0007ff00) | 0x2D;
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
 
-	/* Status:    slow/fast,       Active,    Short Packet Detect     Three Errors */
-	status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 29)       |    (3 << 27);
+	/* 3 errors */
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
 
 	/*
 	 * Build the TD for the control request
 	 */
-	td->status = status;				/* Try forever */
-	td->info = destination | (7 << 21);		/* 8 bytes of data */
-	td->buffer = virt_to_bus(cmd);
+	td = uhci_alloc_td(urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination | (7 << 21),
+		virt_to_bus(urb->setup_packet));
 
 	/*
 	 * If direction is "send", change the frame from SETUP (0x2D)
-	 * to OUT (0xE1). Else change it from SETUP to IN (0x69)
+	 * to OUT (0xE1). Else change it from SETUP to IN (0x69).
 	 */
-	destination ^= (0x2D ^ 0x69);			/* SETUP -> IN */
-	if (usb_pipeout(pipe))
-		destination ^= (0xE1 ^ 0x69);		/* IN -> OUT */
+	destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
 
-	prevtd = td;
-	td = uhci_td_allocate(dev);
-	prevtd->link = 4 | virt_to_bus(td);
+	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+		status |= TD_CTRL_SPD;
 
 	/*
 	 * Build the DATA TD's
 	 */
 	while (len > 0) {
-		/* Build the TD for control status */
 		int pktsze = len;
-		int maxsze = usb_maxpacket(pipe);
 
 		if (pktsze > maxsze)
 			pktsze = maxsze;
 
+		td = uhci_alloc_td(urb->dev);
+		if (!td)
+			return -ENOMEM;
+
 		/* Alternate Data0/1 (start with Data1) */
-		destination ^= 1 << 19;
+		destination ^= 1 << TD_TOKEN_TOGGLE;
 	
-		td->status = status;					/* Status */
-		td->info = destination | ((pktsze-1) << 21);		/* pktsze bytes of data */
-		td->buffer = virt_to_bus(data);
-		td->backptr = &prevtd->link;
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21),
+			virt_to_bus(data));
 
-		prevtd = td;
-		td = uhci_td_allocate(dev);
-		prevtd->link = 4 | virt_to_bus(td);			/* Update previous TD */
+		data += pktsze;
+		len -= pktsze;
+	}
 
-		data += maxsze;
-		len -= maxsze;
+	/*
+	 * Build the final TD for control status 
+	 */
+	td = uhci_alloc_td(urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	/*
+	 * It's IN if the pipe is an output pipe or we're not expecting
+	 * data back.
+	 */
+	destination &= ~TD_PID;
+	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
+		destination |= USB_PID_IN;
+	else
+		destination |= USB_PID_OUT;
+
+	destination |= 1 << TD_TOKEN_TOGGLE;		/* End in Data1 */
+
+	status &= ~TD_CTRL_SPD;
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status | TD_CTRL_IOC,
+		destination | (UHCI_NULL_DATA_SIZE << 21), 0);
+
+	qh = uhci_alloc_qh(urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	/* Low speed or small transfers gets a different queue and treatment */
+	if (urb->pipe & TD_CTRL_LS) {
+		uhci_insert_tds_in_qh(qh, urb, 0);
+		uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, qh);
+	} else {
+		uhci_insert_tds_in_qh(qh, urb, 1);
+		uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
+		uhci_inc_fsbr(uhci, urb);
+	}
+
+	urbp->qh = qh;
+
+	uhci_add_urb_list(uhci, urb);
+
+	usb_inc_dev_use(urb->dev);
+
+	return -EINPROGRESS;
+}
+
+static int usb_control_retrigger_status(struct urb *urb);
+
+static int uhci_result_control(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status;
+	int ret = 0;
+
+	if (!urbp)
+		return -EINVAL;
+
+	head = &urbp->list;
+	if (head->next == head)
+		return -EINVAL;
+
+	if (urbp->short_control_packet) {
+		tmp = head->prev;
+		goto status_phase;
 	}
 
+	tmp = head->next;
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* The first TD is the SETUP phase, check the status, but skip */
+	/*  the count */
+	status = uhci_status_bits(td->status);
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	urb->actual_length = 0;
+
+	/* The rest of the TD's (but the last) are data */
+	tmp = tmp->next;
+	while (tmp != head && tmp->next != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
+		    !(td->status & TD_CTRL_ACTIVE)) {
+			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
+			urbp->fsbr_timeout = 0;
+			td->status &= ~TD_CTRL_IOC;
+		}
+
+		status = uhci_status_bits(td->status);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(td->status);
+
+		if (status)
+			goto td_error;
+
+		/* Check to see if we received a short packet */
+		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				ret = -EREMOTEIO;
+				goto err;
+			}
+
+			if (uhci_packetid(td->info) == USB_PID_IN)
+				return usb_control_retrigger_status(urb);
+			else
+				return 0;
+		}
+	}
+
+status_phase:
+	td = list_entry(tmp, struct uhci_td, list);
+
+	/* Control status phase */
+	status = uhci_status_bits(td->status);
+
+#ifdef I_HAVE_BUGGY_APC_BACKUPS
+	/* APC BackUPS Pro kludge */
+	/* It tries to send all of the descriptor instead of the amount */
+	/*  we requested */
+	if (td->status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */
+	    status & TD_CTRL_ACTIVE &&
+	    status & TD_CTRL_NAK)
+		return 0;
+#endif
+
+	if (status & TD_CTRL_ACTIVE)
+		return -EINPROGRESS;
+
+	if (status)
+		goto td_error;
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td->info));
+	if (ret == -EPIPE)
+		/* endpoint has stalled - mark it halted */
+		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+	    			uhci_packetout(td->info));
+
+err:
+	if (debug && ret != -EPIPE) {
+		/* Some debugging code */
+		dbg("uhci_result_control() failed with status %x", status);
+
+		/* Print the chain for debugging purposes */
+		uhci_show_urb_queue(urb);
+	}
+
+	return ret;
+}
+
+static int usb_control_retrigger_status(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci *uhci = urb->dev->bus->hcpriv;
+
+	urbp->short_control_packet = 1;
+
+	/* Create a new QH to avoid pointer overwriting problems */
+	uhci_remove_qh(uhci, urbp->qh);
+
+	/* Delete all of the TD's except for the status TD at the end */
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head && tmp->next != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		uhci_remove_td_from_urb(urb, td);
+
+		uhci_remove_td(uhci, td);
+
+		uhci_free_td(td);
+	}
+
+	urbp->qh = uhci_alloc_qh(urb->dev);
+	if (!urbp->qh) {
+		err("unable to allocate new QH for control retrigger");
+		return -ENOMEM;
+	}
+
+	/* One TD, who cares about Breadth first? */
+	uhci_insert_tds_in_qh(urbp->qh, urb, 0);
+
+	/* Low speed or small transfers gets a different queue and treatment */
+	if (urb->pipe & TD_CTRL_LS)
+		uhci_insert_qh(uhci, &uhci->skel_ls_control_qh, urbp->qh);
+	else
+		uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, urbp->qh);
+
+	return -EINPROGRESS;
+}
+
+/*
+ * Interrupt transfers
+ */
+static int uhci_submit_interrupt(struct urb *urb)
+{
+	struct uhci_td *td;
+	unsigned long destination, status;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+
+	td = uhci_alloc_td(urb->dev);
+	if (!td)
+		return -ENOMEM;
+
+	destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+	destination |= ((urb->transfer_buffer_length - 1) << 21);
+
+	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+
+	uhci_add_td_to_urb(urb, td);
+	uhci_fill_td(td, status, destination,
+		virt_to_bus(urb->transfer_buffer));
+
+	uhci_insert_td(uhci, &uhci->skeltd[__interval_to_skel(urb->interval)], td);
+
+	uhci_add_urb_list(uhci, urb);
+
+	return -EINPROGRESS;
+}
+
+static int uhci_result_interrupt(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci_td *td;
+	unsigned int status;
+	int ret = 0;
+
+	if (!urbp)
+		return -EINVAL;
+
+	urb->actual_length = 0;
+
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		if (urbp->fsbr_timeout && (td->status & TD_CTRL_IOC) &&
+		    !(td->status & TD_CTRL_ACTIVE)) {
+			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
+			urbp->fsbr_timeout = 0;
+			td->status &= ~TD_CTRL_IOC;
+		}
+
+		status = uhci_status_bits(td->status);
+		if (status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		urb->actual_length += uhci_actual_length(td->status);
+
+		if (status)
+			goto td_error;
+
+		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
+			usb_settoggle(urb->dev, uhci_endpoint(td->info),
+				uhci_packetout(td->info),
+				uhci_toggle(td->info) ^ 1);
+
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				ret = -EREMOTEIO;
+				goto err;
+			} else
+				return 0;
+		}
+	}
+
+	return 0;
+
+td_error:
+	ret = uhci_map_status(status, uhci_packetout(td->info));
+	if (ret == -EPIPE)
+		/* endpoint has stalled - mark it halted */
+		usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+	    			uhci_packetout(td->info));
+
+err:
+	if (debug && ret != -EPIPE) {
+		/* Some debugging code */
+		dbg("uhci_result_interrupt/bulk() failed with status %x",
+			status);
+
+		/* Print the chain for debugging purposes */
+		if (urbp->qh)
+			uhci_show_urb_queue(urb);
+		else
+			uhci_show_td(td);
+	}
+
+	return ret;
+}
+
+static void uhci_reset_interrupt(struct urb *urb)
+{
+	struct list_head *tmp;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct uhci_td *td;
+
+	if (!urbp)
+		return;
+
+	tmp = urbp->list.next;
+	td = list_entry(tmp, struct uhci_td, list);
+	if (!td)
+		return;
+
+	td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
+	td->info &= ~(1 << TD_TOKEN_TOGGLE);
+	td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+	usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+
+	urb->status = -EINPROGRESS;
+}
+
+/*
+ * Bulk transfers
+ */
+static int uhci_submit_bulk(struct urb *urb, struct urb *eurb)
+{
+	struct uhci_td *td;
+	struct uhci_qh *qh;
+	unsigned long destination, status;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	int len = urb->transfer_buffer_length;
+	unsigned char *data = urb->transfer_buffer;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+	if (len < 0)
+		return -EINVAL;
+
+	/* Can't have low speed bulk transfers */
+	if (urb->pipe & TD_CTRL_LS)
+		return -EINVAL;
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	/* 3 errors */
+	status = TD_CTRL_ACTIVE | (3 << TD_CTRL_C_ERR_SHIFT);
+
+	if (!(urb->transfer_flags & USB_DISABLE_SPD))
+		status |= TD_CTRL_SPD;
+
 	/*
-	 * Build the final TD for control status
+	 * Build the DATA TD's
 	 */
-	destination ^= (0xE1 ^ 0x69);			/* OUT -> IN */
-	destination |= 1 << 19;				/* End in Data1 */
+	do {	/* Allow zero length packets */
+		int pktsze = len;
 
-	td->link = 1;					/* Terminate */
-	td->status = status | (1 << 24);		/* IOC */
-	td->info = destination | (0x7ff << 21);		/* 0 bytes of data */
-	td->buffer = 0;
-	td->backptr = &prevtd->link;
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		td = uhci_alloc_td(urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) |
+			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
+			virt_to_bus(data));
+
+		data += pktsze;
+		len -= maxsze;
+
+		if (len <= 0)
+			td->status |= TD_CTRL_IOC;
+
+		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+			usb_pipeout(urb->pipe));
+	} while (len > 0);
+
+	qh = uhci_alloc_qh(urb->dev);
+	if (!qh)
+		return -ENOMEM;
+
+	urbp->qh = qh;
+
+	/* Always assume depth first */
+	uhci_insert_tds_in_qh(qh, urb, 1);
+
+	if (urb->transfer_flags & USB_QUEUE_BULK && eurb) {
+		urbp->queued = 1;
+		uhci_append_queued_urb(uhci, eurb, urb);
+	} else
+		uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
 
-	/* Start it up.. */
-	ret = uhci_run_control(dev, first, td);
+	uhci_add_urb_list(uhci, urb);
 
-	{
-		int maxcount = 100;
-		struct uhci_td *curtd = first;
-		unsigned int nextlink;
+	uhci_inc_fsbr(uhci, urb);
+
+	return -EINPROGRESS;
+}
+
+/* We can use the result interrupt since they're identical */
+#define uhci_result_bulk uhci_result_interrupt
+
+/*
+ * Isochronous transfers
+ */
+static int isochronous_find_limits(struct urb *urb, unsigned int *start, unsigned int *end)
+{
+	struct urb *last_urb = NULL;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct list_head *tmp, *head = &uhci->urb_list;
+	int ret = 0;
+	unsigned long flags;
+
+	nested_lock(&uhci->urblist_lock, flags);
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		/* look for pending URB's with identical pipe handle */
+		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
+		    (u->status == -EINPROGRESS) && (u != urb)) {
+			if (!last_urb)
+				*start = u->start_frame;
+			last_urb = u;
+		}
+	}
 
+	if (last_urb) {
+		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
+		ret = 0;
+	} else
+		ret = -1;	/* no previous urb found */
+
+	nested_unlock(&uhci->urblist_lock, flags);
+
+	return ret;
+}
+
+static int isochronous_find_start(struct urb *urb)
+{
+	int limits;
+	unsigned int start = 0, end = 0;
+
+	if (urb->number_of_packets > 900)	/* 900? Why? */
+		return -EFBIG;
+
+	limits = isochronous_find_limits(urb, &start, &end);
+
+	if (urb->transfer_flags & USB_ISO_ASAP) {
+		if (limits) {
+			int curframe;
+
+			curframe = uhci_get_current_frame_number(urb->dev) % UHCI_NUMFRAMES;
+			urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES;
+		} else
+			urb->start_frame = end;
+	} else {
+		urb->start_frame %= UHCI_NUMFRAMES;
+		/* FIXME: Sanity check */
+	}
+
+	return 0;
+}
+
+static int uhci_submit_isochronous(struct urb *urb)
+{
+	struct uhci_td *td;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	int i, ret, framenum;
+	int status, destination;
+
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
+
+	ret = isochronous_find_start(urb);
+	if (ret)
+		return ret;
+
+	framenum = urb->start_frame;
+	for (i = 0; i < urb->number_of_packets; i++, framenum++) {
+		if (!urb->iso_frame_desc[i].length)
+			continue;
+
+		td = uhci_alloc_td(urb->dev);
+		if (!td)
+			return -ENOMEM;
+
+		uhci_add_td_to_urb(urb, td);
+		uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21),
+			virt_to_bus(urb->transfer_buffer + urb->iso_frame_desc[i].offset));
+
+		if (i + 1 >= urb->number_of_packets)
+			td->status |= TD_CTRL_IOC;
+
+		uhci_insert_td_frame_list(uhci, td, framenum);
+	}
+
+	uhci_add_urb_list(uhci, urb);
+
+	return -EINPROGRESS;
+}
+
+static int uhci_result_isochronous(struct urb *urb)
+{
+	struct list_head *tmp, *head;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	int status;
+	int i, ret = 0;
+
+	if (!urbp)
+		return -EINVAL;
+
+	urb->actual_length = 0;
+
+	i = 0;
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+		int actlength;
+
+		tmp = tmp->next;
+
+		if (td->status & TD_CTRL_ACTIVE)
+			return -EINPROGRESS;
+
+		actlength = uhci_actual_length(td->status);
+		urb->iso_frame_desc[i].actual_length = actlength;
+		urb->actual_length += actlength;
+
+		status = uhci_map_status(uhci_status_bits(td->status), usb_pipeout(urb->pipe));
+		urb->iso_frame_desc[i].status = status;
+		if (status != 0) {
+			urb->error_count++;
+			ret = status;
+		}
+
+		i++;
+	}
+
+	return ret;
+}
+
+static struct urb *uhci_find_urb_ep(struct uhci *uhci, struct urb *urb)
+{
+	struct list_head *tmp, *head = &uhci->urb_list;
+	unsigned long flags;
+	struct urb *u = NULL;
+
+	if (usb_pipeisoc(urb->pipe))
+		return NULL;
+
+	nested_lock(&uhci->urblist_lock, flags);
+	tmp = head->next;
+	while (tmp != head) {
+		u = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		if (u->dev == urb->dev &&
+		    u->pipe == urb->pipe)
+			goto found;
+	}
+	u = NULL;
+
+found:
+	nested_unlock(&uhci->urblist_lock, flags);
+
+	return u;
+}
+
+static int uhci_submit_urb(struct urb *urb)
+{
+	int ret = -EINVAL;
+	struct uhci *uhci;
+	unsigned long flags;
+	struct urb *u;
+
+	if (!urb)
+		return -EINVAL;
+
+	if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
+		return -ENODEV;
+
+	uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	/* Short circuit the virtual root hub */
+	if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
+		return rh_submit_urb(urb);
+
+	u = uhci_find_urb_ep(uhci, urb);
+	if (u && !(urb->transfer_flags & USB_QUEUE_BULK))
+		return -ENXIO;
+
+	spin_lock_irqsave(&urb->lock, flags);
+
+	if (!uhci_alloc_urb_priv(urb)) {
+		spin_unlock_irqrestore(&urb->lock, flags);
+		return -ENOMEM;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_submit_control(urb);
+		break;
+	case PIPE_INTERRUPT:
+		ret = uhci_submit_interrupt(urb);
+		break;
+	case PIPE_BULK:
+		ret = uhci_submit_bulk(urb, u);
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = uhci_submit_isochronous(urb);
+		break;
+	}
+
+	urb->status = ret;
+
+	spin_unlock_irqrestore(&urb->lock, flags);
+
+	if (ret == -EINPROGRESS)
+		ret = 0;
+	else
+		uhci_unlink_generic(urb);
+
+	return ret;
+}
+
+/*
+ * Return the result of a transfer
+ *
+ * Must be called with urblist_lock acquired
+ */
+static void uhci_transfer_result(struct urb *urb)
+{
+	struct urb *turb;
+	int proceed = 0, is_ring = 0;
+	int ret = -EINVAL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&urb->lock, flags);
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = uhci_result_control(urb);
+		break;
+	case PIPE_INTERRUPT:
+		ret = uhci_result_interrupt(urb);
+		break;
+	case PIPE_BULK:
+		ret = uhci_result_bulk(urb);
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = uhci_result_isochronous(urb);
+		break;
+	}
+
+	urb->status = ret;
+
+	spin_unlock_irqrestore(&urb->lock, flags);
+
+	if (ret == -EINPROGRESS)
+		return;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+	case PIPE_ISOCHRONOUS:
+		uhci_unlink_generic(urb);
+		break;
+	case PIPE_INTERRUPT:
+		/* Interrupts are an exception */
+		urb->complete(urb);
+		if (urb->interval)
+			uhci_reset_interrupt(urb);
+		else
+			uhci_unlink_generic(urb);
+		return;		/* <-- Note the return */
+	}
+
+	if (urb->next) {
+		turb = urb->next;
 		do {
-			nextlink = curtd->link;
-			uhci_remove_td(curtd);
-			uhci_td_deallocate(curtd);
-			if (nextlink & 1)	/* Tail? */
+			if (turb->status != -EINPROGRESS) {
+				proceed = 1;
 				break;
+			}
+
+			turb = turb->next;
+		} while (turb && turb != urb && turb != urb->next);
+
+		if (turb == urb || turb == urb->next)
+			is_ring = 1;
+	}
+
+	if (urb->complete && (!proceed || (urb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
+		urb->complete(urb);
+		if (!proceed && is_ring)
+			uhci_submit_urb(urb);
+	}
+
+	if (proceed && urb->next) {
+		turb = urb->next;
+		do {
+			if (turb->status != -EINPROGRESS &&
+			    uhci_submit_urb(turb) != 0)
+
+			turb = turb->next;
+		} while (turb && turb != urb->next);
+
+		if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE))
+			urb->complete(urb);
+	}
+}
+
+static int uhci_unlink_generic(struct urb *urb)
+{
+	struct urb_priv *urbp = urb->hcpriv;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	if (!urbp)
+		return -EINVAL;
+
+	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
+
+	uhci_remove_urb_list(uhci, urb);
+
+	if (urbp->qh)
+		/* The interrupt loop will reclaim the QH's */
+		uhci_remove_qh(uhci, urbp->qh);
+
+	if (!list_empty(&urbp->urb_queue_list))
+		uhci_delete_queued_urb(uhci, urb);
 
-			curtd = bus_to_virt(nextlink & ~0xF);
-			if (!--maxcount) {
-				printk("runaway td's!?\n");
-				break;
-			}
-		} while (1);
-	}
+	uhci_destroy_urb_priv(urb);
 
-	return ret;
+	return 0;
 }
 
-static struct usb_device *uhci_usb_allocate(struct usb_device *parent)
+static int uhci_unlink_urb(struct urb *urb)
 {
-	struct usb_device *usb_dev;
-	struct uhci_device *dev;
-	int i;
+	struct uhci *uhci;
+	int ret = 0;
+	unsigned long flags;
 
-	usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
-	if (!usb_dev)
-		return NULL;
+	if (!urb)
+		return -EINVAL;
 
-	memset(usb_dev, 0, sizeof(*usb_dev));
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
 
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		usb_destroy_configuration(usb_dev);
-		kfree(usb_dev);
-		return NULL;
-	}
+	uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
-	/* Initialize "dev" */
-	memset(dev, 0, sizeof(*dev));
+	/* Short circuit the virtual root hub */
+	if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
+		return rh_unlink_urb(urb);
 
-	usb_dev->hcpriv = dev;
-	dev->usb = usb_dev;
+	if (urb->status == -EINPROGRESS) {
+		uhci_unlink_generic(urb);
 
-	usb_dev->parent = parent;
+		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+			urb->status = -ECONNABORTED;
 
-	if (parent) {
-		usb_dev->bus = parent->bus;
-		dev->uhci = usb_to_uhci(parent)->uhci;
-	}
+			spin_lock_irqsave(&uhci->urb_remove_lock, flags);
 
-	/* Reset the QH's and TD's */
-	for (i = 0; i < UHCI_MAXQH; i++) {
-		dev->qh[i].link = 1;
-		dev->qh[i].element = 1;
-		dev->qh[i].inuse = 0;
-	}
+			/* Check to see if the remove list is empty */
+			if (list_empty(&uhci->urb_remove_list))
+				uhci_set_next_interrupt(uhci);
+			
+			list_add(&urb->urb_list, &uhci->urb_remove_list);
+
+			spin_unlock_irqrestore(&uhci->urb_remove_lock, flags);
+		} else {
+			urb->status = -ENOENT;
+
+			if (in_interrupt()) {	/* wait at least 1 frame */
+				static int errorcount = 10;
+
+				if (errorcount--)
+					dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
+				udelay(1000);
+			} else
+				schedule_timeout(1+1*HZ/1000); 
 
-	for (i = 0; i < UHCI_MAXTD; i++) {
-		dev->td[i].link = 1;
-		dev->td[i].inuse = 0;
+			if (urb->complete)
+				urb->complete(urb);
+		}
 	}
 
-	return usb_dev;
+	return ret;
 }
 
-static int uhci_usb_deallocate(struct usb_device *usb_dev)
+static int uhci_fsbr_timeout(struct uhci *uhci, struct urb *urb)
 {
-	struct uhci_device *dev = usb_to_uhci(usb_dev);
-	int i;
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
 
-	/* There are UHCI_MAXTD preallocated tds */
-	for (i = 0; i < UHCI_MAXTD; ++i) {
-		struct uhci_td *td = dev->td + i;
+	uhci_dec_fsbr(uhci, urb);
 
-		/* And remove it from the irq list, if it's active */
-		if (td->status & (1 << 23))
-			uhci_remove_irq_list(td);
+	/* There is a race with updating IOC in here, but it's not worth */
+	/*  trying to fix since this is merely an optimization. The only */
+	/*  time we'd lose is if the status of the packet got updated */
+	/*  and we'd be turning on FSBR next frame anyway, so it's a wash */
+	urbp->fsbr_timeout = 1;
 
-		if (td->inuse)
-			uhci_remove_td(td);
-	}
+	head = &urbp->list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 
-	/* Remove the td from any queues */
-	for (i = 0; i < UHCI_MAXQH; ++i) {
-		struct uhci_qh *qh = dev->qh + i;
+		tmp = tmp->next;
 
-		if (qh->inuse)
-			uhci_remove_qh(qh->skel, qh);
+		if (td->status & TD_CTRL_ACTIVE) {
+			td->status |= TD_CTRL_IOC;
+			break;
+		}
 	}
 
-	kfree(dev);
-	usb_destroy_configuration(usb_dev);
-	kfree(usb_dev);
-
 	return 0;
 }
 
-struct usb_operations uhci_device_operations = {
-	uhci_usb_allocate,
-	uhci_usb_deallocate,
-	uhci_control_msg,
-	uhci_request_irq,
-};
-
 /*
- * This is just incredibly fragile. The timings must be just
- * right, and they aren't really documented very well.
+ * uhci_get_current_frame_number()
  *
- * Note the short delay between disabling reset and enabling
- * the port..
+ * returns the current frame number for a USB bus/controller.
  */
-static void uhci_reset_port(unsigned int port)
+static int uhci_get_current_frame_number(struct usb_device *dev)
 {
-	unsigned short status;
+	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
 
-	status = inw(port);
-	outw(status | USBPORTSC_PR, port);		/* reset port */
-	wait_ms(10);
-	outw(status & ~USBPORTSC_PR, port);
-	udelay(5);
+	return inw(uhci->io_addr + USBFRNUM);
+}
 
-	status = inw(port);
-	outw(status | USBPORTSC_PE, port);		/* enable port */
-	wait_ms(10);
+struct usb_operations uhci_device_operations = {
+	uhci_alloc_dev,
+	uhci_free_dev,
+	uhci_get_current_frame_number,
+	uhci_submit_urb,
+	uhci_unlink_urb
+};
 
-	status = inw(port);
-	if(!(status & USBPORTSC_PE)) {
-		outw(status | USBPORTSC_PE, port);	/* one more try at enabling port */
-		wait_ms(50);
-	}
+/* -------------------------------------------------------------------
+   Virtual Root Hub
+   ------------------------------------------------------------------- */
+
+static __u8 root_hub_dev_des[] =
+{
+ 	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x00,			/*  __u16 bcdUSB; v1.0 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
 
-}
 
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes;
+					Bit 7: Bus-powered, 6: Self-powered,
+					Bit 5 Remote-wakeup, 4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+	/* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */
+	0x00,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
 
-/*
- * This gets called if the connect status on the root
- * hub (and the root hub only) changes.
- */
-static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned int nr)
+static __u8 root_hub_hub_des[] =
 {
-	struct usb_device *usb_dev;
-	struct uhci_device *dev;
-	unsigned short status;
+	0x09,			/*  __u8  bLength; */
+	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
+	0x02,			/*  __u8  bNbrPorts; */
+	0x00,			/* __u16  wHubCharacteristics; */
+	0x00,
+	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
+	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
 
-	printk("uhci_connect_change: called for %d\n", nr);
+/*-------------------------------------------------------------------------*/
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+static int rh_send_irq(struct urb *urb)
+{
+	int i, len = 1;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 data = 0;
 
-	/*
-	 * Even if the status says we're connected,
-	 * the fact that the status bits changed may
-	 * that we got disconnected and then reconnected.
-	 *
-	 * So start off by getting rid of any old devices..
-	 */
-	usb_disconnect(&uhci->root_hub->usb->children[nr]);
+	for (i = 0; i < uhci->rh.numports; i++) {
+		data |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
+		len = (i + 1) / 8 + 1;
+	}
 
-	status = inw(port);
+	*(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
+	urb->actual_length = len;
+	urb->status = USB_ST_NOERROR;
 
-	/* If we have nothing connected, then clear change status and disable the port */
-	status = (status & ~USBPORTSC_PE) | USBPORTSC_PEC;
-	if (!(status & USBPORTSC_CCS)) {
-		outw(status, port);
-		return;
+	if ((data > 0) && (uhci->rh.send != 0)) {
+		dbg("root-hub INT complete: port1: %x port2: %x data: %x",
+			inw(io_addr + USBPORTSC1), inw(io_addr + USBPORTSC2), data);
+		urb->complete(urb);
 	}
 
-	/*
-	 * Ok, we got a new connection. Allocate a device to it,
-	 * and find out what it wants to do..
-	 */
-	usb_dev = uhci_usb_allocate(uhci->root_hub->usb);
-	dev = usb_dev->hcpriv;
+	return USB_ST_NOERROR;
+}
 
-	dev->uhci = uhci;
+/*-------------------------------------------------------------------------*/
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+static int rh_init_int_timer(struct urb *urb);
 
-	usb_connect(usb_dev);
+static void rh_int_timer_do(unsigned long ptr)
+{
+	struct urb *urb = (struct urb *)ptr;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	struct list_head *tmp, *head = &uhci->urb_list;
+	struct urb_priv *urbp;
+	int len;
+	unsigned long flags;
 
-	uhci->root_hub->usb->children[nr] = usb_dev;
+	if (uhci->rh.send) {
+		len = rh_send_irq(urb);
+		if (len > 0) {
+			urb->actual_length = len;
+			if (urb->complete)
+				urb->complete(urb);
+		}
+	}
 
-	wait_ms(200); /* wait for powerup */
-	uhci_reset_port(port);
+	nested_lock(&uhci->urblist_lock, flags);
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *u = list_entry(tmp, urb_t, urb_list);
 
-	/* Get speed information */
-	usb_dev->slow = (inw(port) & USBPORTSC_LSDA) ? 1 : 0;
+		tmp = tmp->next;
 
-	/*
-	 * Ok, all the stuff specific to the root hub has been done.
-	 * The rest is generic for any new USB attach, regardless of
-	 * hub type.
-	 */
-	usb_new_device(usb_dev);
+		urbp = (struct urb_priv *)u->hcpriv;
+		if (urbp) {
+			/* Check if the FSBR timed out */
+			if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies))
+				uhci_fsbr_timeout(uhci, u);
+
+			/* Check if the URB timed out */
+			if (u->timeout && time_after(u->timeout, jiffies)) {
+				u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+				uhci_unlink_urb(u);
+			}
+		}
+	}
+	nested_unlock(&uhci->urblist_lock, flags);
+
+	rh_init_int_timer(urb);
 }
 
-/*
- * This gets called when the root hub configuration
- * has changed. Just go through each port, seeing if
- * there is something interesting happening.
- */
-static void uhci_check_configuration(struct uhci *uhci)
+/*-------------------------------------------------------------------------*/
+/* Root Hub INTs are polled by this timer */
+static int rh_init_int_timer(struct urb *urb)
 {
-	unsigned int io_addr = uhci->io_addr + USBPORTSC1;
-	int maxchild = uhci->root_hub->usb->maxchild;
-	int nr = 0;
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	uhci->rh.interval = urb->interval;
+	init_timer(&uhci->rh.rh_int_timer);
+	uhci->rh.rh_int_timer.function = rh_int_timer_do;
+	uhci->rh.rh_int_timer.data = (unsigned long)urb;
+	uhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+	add_timer(&uhci->rh.rh_int_timer);
 
-	do {
-		unsigned short status = inw(io_addr);
+	return 0;
+}
 
-		if (status & USBPORTSC_CSC)
-			uhci_connect_change(uhci, io_addr, nr);
+/*-------------------------------------------------------------------------*/
+#define OK(x)			len = (x); break
 
-		nr++; io_addr += 2;
-	} while (nr < maxchild);
+#define CLR_RH_PORTSTAT(x) \
+	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+	status = (status & 0xfff5) & ~(x); \
+	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+#define SET_RH_PORTSTAT(x) \
+	status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
+	status = (status & 0xfff5) | (x); \
+	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
+
+
+/*-------------------------------------------------------------------------*/
+/*************************
+ ** Root Hub Control Pipe
+ *************************/
+
+static int rh_submit_urb(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	devrequest *cmd = (devrequest *)urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = 0;
+	int stat = USB_ST_NOERROR;
+	int i;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 cstatus;
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
+		uhci->rh.urb = urb;
+		uhci->rh.send = 1;
+		uhci->rh.interval = urb->interval;
+		rh_init_int_timer(urb);
+
+		return USB_ST_NOERROR;
+	}
+
+	bmRType_bReq = cmd->requesttype | cmd->request << 8;
+	wValue = le16_to_cpu(cmd->value);
+	wIndex = le16_to_cpu(cmd->index);
+	wLength = le16_to_cpu(cmd->length);
+
+	for (i = 0; i < 8; i++)
+		uhci->rh.c_p_r[i] = 0;
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device,
+		   RH_INTERFACE: interface,
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here,
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
+		*/
+
+	case RH_GET_STATUS:
+		*(__u16 *)data = cpu_to_le16(1);
+		OK(2);
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *)data = cpu_to_le16(0);
+		OK(2);
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *)data = cpu_to_le16(0);
+		OK(2);
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *)data = cpu_to_le32(0);
+		OK(4);		/* hub power */
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
+		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+			((status & USBPORTSC_PEC) >> (3 - 1)) |
+			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
+			status = (status & USBPORTSC_CCS) |
+			((status & USBPORTSC_PE) >> (2 - 1)) |
+			((status & USBPORTSC_SUSP) >> (12 - 2)) |
+			((status & USBPORTSC_PR) >> (9 - 4)) |
+			(1 << 8) |      /* power on */
+			((status & USBPORTSC_LSDA) << (-8 + 9));
+
+		*(__u16 *)data = cpu_to_le16(status);
+		*(__u16 *)(data + 2) = cpu_to_le16(cstatus);
+		OK(4);
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case RH_ENDPOINT_STALL:
+			OK(0);
+		}
+		break;
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case RH_C_HUB_OVER_CURRENT:
+			OK(0);	/* hub power over current */
+		}
+		break;
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case RH_PORT_ENABLE:
+			CLR_RH_PORTSTAT(USBPORTSC_PE);
+			OK(0);
+		case RH_PORT_SUSPEND:
+			CLR_RH_PORTSTAT(USBPORTSC_SUSP);
+			OK(0);
+		case RH_PORT_POWER:
+			OK(0);	/* port power */
+		case RH_C_PORT_CONNECTION:
+			SET_RH_PORTSTAT(USBPORTSC_CSC);
+			OK(0);
+		case RH_C_PORT_ENABLE:
+			SET_RH_PORTSTAT(USBPORTSC_PEC);
+			OK(0);
+		case RH_C_PORT_SUSPEND:
+			/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+			OK(0);
+		case RH_C_PORT_OVER_CURRENT:
+			OK(0);	/* port power over current */
+		case RH_C_PORT_RESET:
+			uhci->rh.c_p_r[wIndex - 1] = 0;
+			OK(0);
+		}
+		break;
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case RH_PORT_SUSPEND:
+			SET_RH_PORTSTAT(USBPORTSC_SUSP);
+			OK(0);
+		case RH_PORT_RESET:
+			SET_RH_PORTSTAT(USBPORTSC_PR);
+			wait_ms(50);	/* USB v1.1 7.1.7.3 */
+			uhci->rh.c_p_r[wIndex - 1] = 1;
+			CLR_RH_PORTSTAT(USBPORTSC_PR);
+			udelay(10);
+			SET_RH_PORTSTAT(USBPORTSC_PE);
+			wait_ms(10);
+			SET_RH_PORTSTAT(0xa);
+			OK(0);
+		case RH_PORT_POWER:
+			OK(0); /* port power ** */
+		case RH_PORT_ENABLE:
+			SET_RH_PORTSTAT(USBPORTSC_PE);
+			OK(0);
+		}
+		break;
+	case RH_SET_ADDRESS:
+		uhci->rh.devnum = wValue;
+		OK(0);
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case 0x01:	/* device descriptor */
+			len = min(leni, min(sizeof(root_hub_dev_des), wLength));
+			memcpy(data, root_hub_dev_des, len);
+			OK(len);
+		case 0x02:	/* configuration descriptor */
+			len = min(leni, min(sizeof(root_hub_config_des), wLength));
+			memcpy (data, root_hub_config_des, len);
+			OK(len);
+		case 0x03:	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff,
+				uhci->io_addr, "UHCI-alt",
+				data, wLength);
+			if (len > 0) {
+				OK (min (leni, len));
+			} else 
+				stat = -EPIPE;
+		}
+		break;
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = uhci->rh.numports;
+		len = min(leni, min(sizeof(root_hub_hub_des), wLength));
+		memcpy(data, root_hub_hub_des, len);
+		OK(len);
+	case RH_GET_CONFIGURATION:
+		*(__u8 *)data = 0x01;
+		OK(1);
+	case RH_SET_CONFIGURATION:
+		OK(0);
+	case RH_GET_INTERFACE | RH_INTERFACE:
+		*(__u8 *)data = 0x00;
+		OK(1);
+	case RH_SET_INTERFACE | RH_INTERFACE:
+		OK(0);
+	default:
+		stat = -EPIPE;
+	}
+
+	urb->actual_length = len;
+	urb->status = stat;
+	if (urb->complete)
+		urb->complete(urb);
+
+	return USB_ST_NOERROR;
+}
+/*-------------------------------------------------------------------------*/
+
+static int rh_unlink_urb(struct urb *urb)
+{
+	struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+	if (uhci->rh.urb == urb) {
+		uhci->rh.send = 0;
+		del_timer(&uhci->rh.rh_int_timer);
+	}
+	return 0;
 }
+/*-------------------------------------------------------------------*/
 
-static void uhci_interrupt_notify(struct uhci *uhci)
+void uhci_free_pending_qhs(struct uhci *uhci)
 {
-	struct list_head *head = &uhci->interrupt_list;
-	struct list_head *tmp;
+	struct list_head *tmp, *head;
+	unsigned long flags;
 
-	spin_lock(&irqlist_lock);
+	/* Free any pending QH's */
+	spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+	head = &uhci->qh_remove_list;
 	tmp = head->next;
 	while (tmp != head) {
-		struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
-		struct list_head *next;
+		struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list);
 
-		next = tmp->next;
+		tmp = tmp->next;
 
-		if (!(td->status & (1 << 23))) {	/* No longer active? */
-			/* remove from IRQ list */
-			__list_del(tmp->prev, next);
-			INIT_LIST_HEAD(tmp);
-			if (td->completed(td->status, bus_to_virt(td->buffer), td->dev_id)) {
-				struct uhci_qh *interrupt_qh = td->qh;
-
-				list_add(&td->irq_list, &uhci->interrupt_list);
-				td->info ^= 1 << 19; /* toggle between data0 and data1 */
-				td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24);	/* active */
-
-				/* Remove then readd? Is that necessary */
-				uhci_remove_td(td);
-				uhci_insert_td_in_qh(interrupt_qh, td);
-			}
-			/* If completed wants to not reactivate, then it's */
-			/* responsible for free'ing the TD's and QH's */
-			/* or another function (such as run_control) */
-		}
-		tmp = next;
-	}
-	spin_unlock(&irqlist_lock);
-}
+		list_del(&qh->remove_list);
 
-/*
- * Check port status - Connect Status Change - for
- * each of the attached ports (defaults to two ports,
- * but at least in theory there can be more of them).
- *
- * Wake up the configurator if something happened, we
- * can't really do much at interrupt time.
- */
-static void uhci_root_hub_events(struct uhci *uhci, unsigned int io_addr)
-{
-	if (waitqueue_active(&uhci_configure)) {
-		int ports = uhci->root_hub->usb->maxchild;
-		io_addr += USBPORTSC1;
-		do {
-			if (inw(io_addr) & USBPORTSC_CSC) {
-				wake_up(&uhci_configure);
-				return;
-			}
-			io_addr += 2;
-		} while (--ports > 0);
+		uhci_free_qh(qh);
 	}
+	spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
 }
 
 static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
@@ -757,39 +1965,63 @@
 	struct uhci *uhci = __uhci;
 	unsigned int io_addr = uhci->io_addr;
 	unsigned short status;
+	unsigned long flags;
+	struct list_head *tmp, *head;
 
 	/*
-	 * Read the interrupt status, and write it back to clear the interrupt cause
+	 * Read the interrupt status, and write it back to clear the
+	 * interrupt cause
 	 */
 	status = inw(io_addr + USBSTS);
+	if (!status)	/* shared interrupt, not mine */
+		return;
 	outw(status, io_addr + USBSTS);
 
-	/* Walk the list of pending TD's to see which ones completed.. */
-	uhci_interrupt_notify(uhci);
+	if (status & ~(USBSTS_USBINT | USBSTS_ERROR)) {
+		if (status & USBSTS_RD)
+			printk(KERN_INFO "uhci: resume detected, not implemented\n");
+		if (status & USBSTS_HSE)
+			printk(KERN_ERR "uhci: host system error, PCI problems?\n");
+		if (status & USBSTS_HCPE)
+			printk(KERN_ERR "uhci: host controller process error. something bad happened\n");
+		if (status & USBSTS_HCH) {
+			printk(KERN_ERR "uhci: host controller halted. very bad\n");
+			/* FIXME: Reset the controller, fix the offending TD */
+		}
+	}
 
-	/* Check if there are any events on the root hub.. */
-	uhci_root_hub_events(uhci, io_addr);
-}
+	uhci_free_pending_qhs(uhci);
 
-/*
- * We init one packet, and mark it just IOC and _not_
- * active. Which will result in no actual USB traffic,
- * but _will_ result in an interrupt every second.
- *
- * Which is exactly what we want.
- */
-static void uhci_init_ticktd(struct uhci *uhci)
-{
-	struct uhci_device *dev = uhci->root_hub;
-	struct uhci_td *td = uhci_td_allocate(dev);
+	spin_lock(&uhci->urb_remove_lock);
+	head = &uhci->urb_remove_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *urb = list_entry(tmp, struct urb, urb_list);
 
-	td->link = 1;
-	td->status = (1 << 24);					/* interrupt on completion */
-	td->info = (15 << 21) | 0x7f69;				/* (ignored) input packet, 16 bytes, device 127 */
-	td->buffer = 0;
-	td->qh = NULL;
+		tmp = tmp->next;
+
+		list_del(&urb->urb_list);
+
+		if (urb->complete)
+			urb->complete(urb);
+	}
+	spin_unlock(&uhci->urb_remove_lock);
+
+	uhci_clear_next_interrupt(uhci);
 
-	uhci->fl->frame[0] = virt_to_bus(td);
+	/* Walk the list of pending TD's to see which ones completed */
+	nested_lock(&uhci->urblist_lock, flags);
+	head = &uhci->urb_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct urb *urb = list_entry(tmp, struct urb, urb_list);
+
+		tmp = tmp->next;
+
+		/* Checks the status and does all of the magic necessary */
+		uhci_transfer_result(urb);
+	}
+	nested_unlock(&uhci->urblist_lock, flags);
 }
 
 static void reset_hc(struct uhci *uhci)
@@ -797,9 +2029,9 @@
 	unsigned int io_addr = uhci->io_addr;
 
 	/* Global reset for 50ms */
-	outw(USBCMD_GRESET, io_addr+USBCMD);
+	outw(USBCMD_GRESET, io_addr + USBCMD);
 	wait_ms(50);
-	outw(0, io_addr+USBCMD);
+	outw(0, io_addr + USBCMD);
 	wait_ms(10);
 }
 
@@ -808,8 +2040,6 @@
 	unsigned int io_addr = uhci->io_addr;
 	int timeout = 1000;
 
-	uhci_init_ticktd(uhci);
-
 	/*
 	 * Reset the HC - this will force us to get a
 	 * new notification of any already connected
@@ -819,21 +2049,25 @@
 	outw(USBCMD_HCRESET, io_addr + USBCMD);
 	while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
 		if (!--timeout) {
-			printk("USBCMD_HCRESET timed out!\n");
+			printk(KERN_ERR "uhci: USBCMD_HCRESET timed out!\n");
 			break;
 		}
 	}
 
-	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+	/* Turn on all interrupts */
+	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
+		io_addr + USBINTR);
+
+	/* Start at frame 0 */
 	outw(0, io_addr + USBFRNUM);
 	outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD);
 
 	/* Run and mark it configured with a 64-byte max packet */
-	outw(USBCMD_RS | USBCMD_CF, io_addr + USBCMD);
+	outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
 }
 
 /*
- * Allocate a frame list, and four regular queues.
+ * Allocate a frame list, and then setup the skeleton
  *
  * The hardware doesn't really know any difference
  * in the queues, but the order does matter for the
@@ -843,20 +2077,14 @@
  *    of the queues. We don't do that here, because
  *    we'll create the actual TD entries on demand.
  *  - The first queue is the "interrupt queue".
- *  - The second queue is the "control queue".
+ *  - The second queue is the "control queue", split into low and high speed
  *  - The third queue is "bulk data".
- *
- * We could certainly have multiple queues of the same
- * type, and maybe we should. We could have per-device
- * queues, for example. We begin small.
  */
-static struct uhci *alloc_uhci(unsigned int io_addr)
+static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
 {
-	int i;
+	int i, port;
 	struct uhci *uhci;
 	struct usb_bus *bus;
-	struct uhci_device *dev;
-	struct usb_device *usb;
 
 	uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
 	if (!uhci)
@@ -866,69 +2094,87 @@
 
 	uhci->irq = -1;
 	uhci->io_addr = io_addr;
-	INIT_LIST_HEAD(&uhci->interrupt_list);
+	uhci->io_size = io_size;
+
+	spin_lock_init(&uhci->qh_remove_lock);
+	INIT_LIST_HEAD(&uhci->qh_remove_list);
+
+	spin_lock_init(&uhci->urb_remove_lock);
+	INIT_LIST_HEAD(&uhci->urb_remove_list);
+
+	nested_init(&uhci->urblist_lock);
+	INIT_LIST_HEAD(&uhci->urb_list);
+
+	spin_lock_init(&uhci->framelist_lock);
 
 	/* We need exactly one page (per UHCI specs), how convenient */
+	/* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
 	uhci->fl = (void *)__get_free_page(GFP_KERNEL);
+	if (!uhci->fl)
+		goto au_free_uhci;
 
-	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+	bus = usb_alloc_bus(&uhci_device_operations);
 	if (!bus)
-		return NULL;
-
-	memset(bus, 0, sizeof(*bus));
+		goto au_free_fl;
 
 	uhci->bus = bus;
 	bus->hcpriv = uhci;
-	bus->op = &uhci_device_operations;
 
-	/*
-	 * We allocate a 8kB area for the UHCI hub. The area
-	 * is described by the uhci_device structure, and basically
-	 * contains everything needed for normal operation.
-	 *
-	 * The first page is the actual device descriptor for the
-	 * hub.
-	 *
-	 * The second page is used for the frame list.
-	 */
-	usb = uhci_usb_allocate(NULL);
-	if (!usb)
-		return NULL;
+	/* Initialize the root hub */
+
+	/* UHCI specs says devices must have 2 ports, but goes on to say */
+	/*  they may have more but give no way to determine how many they */
+	/*  have. However, according to the UHCI spec, Bit 7 is always set */
+	/*  to 1. So we try to use this to our advantage */
+	for (port = 0; port < (io_size - 0x10) / 2; port++) {
+		unsigned int portstatus;
 
-	dev = uhci->root_hub = usb_to_uhci(usb);
+		portstatus = inw(io_addr + 0x10 + (port * 2));
+		if (!(portstatus & 0x0080))
+			break;
+	}
+	if (debug)
+		info("detected %d ports", port);
 
-	usb->bus = bus;
+	/* This is experimental so anything less than 2 or greater than 8 is */
+	/*  something weird and we'll ignore it */
+	if (port < 2 || port > 8) {
+		info("port count misdetected? forcing to 2 ports");
+		port = 2;
+	}
 
-	/* Initialize the root hub */
-	/* UHCI specs says devices must have 2 ports, but goes on to say */
-	/* they may have more but give no way to determine how many they */
-	/* have, so default to 2 */
-	usb->maxchild = 2;
-	usb_init_root_hub(usb);
+	uhci->rh.numports = port;
 
 	/*
-	 * Initialize the queues. They all start out empty,
-	 * linked to each other in the proper order.
+	 * 9 Interrupt queues; link int2 to int1, int4 to int2, etc
+	 * then link int1 to control and control to bulk
 	 */
-	for (i = 1 ; i < 9; i++) {
-		dev->qh[i].link = 2 | virt_to_bus(&dev->skel_control_qh);
-		dev->qh[i].element = 1;
+	for (i = 1; i < 9; i++) {
+		struct uhci_td *td = &uhci->skeltd[i];
+
+		uhci_fill_td(td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+		td->link = virt_to_bus(&uhci->skeltd[i - 1]);
 	}
-	
-	dev->skel_control_qh.link = 2 | virt_to_bus(&dev->skel_bulk0_qh);
-	dev->skel_control_qh.element = 1;
 
-	dev->skel_bulk0_qh.link = 2 | virt_to_bus(&dev->skel_bulk1_qh);
-	dev->skel_bulk0_qh.element = 1;
 
-	dev->skel_bulk1_qh.link = 2 | virt_to_bus(&dev->skel_bulk2_qh);
-	dev->skel_bulk1_qh.element = 1;
+	uhci_fill_td(&uhci->skel_int1_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+	uhci->skel_int1_td.link = virt_to_bus(&uhci->skel_ls_control_qh) | UHCI_PTR_QH;
+
+	uhci->skel_ls_control_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+	uhci->skel_ls_control_qh.element = UHCI_PTR_TERM;
+
+	uhci->skel_hs_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) | UHCI_PTR_QH;
+	uhci->skel_hs_control_qh.element = UHCI_PTR_TERM;
 
-	dev->skel_bulk2_qh.link = 2 | virt_to_bus(&dev->skel_bulk3_qh);
-	dev->skel_bulk2_qh.element = 1;
+	uhci->skel_bulk_qh.link = virt_to_bus(&uhci->skel_term_qh) | UHCI_PTR_QH;
+	uhci->skel_bulk_qh.element = UHCI_PTR_TERM;
 
-	dev->skel_bulk3_qh.link = 1;
-	dev->skel_bulk3_qh.element = 1;
+	/* This dummy TD is to work around a bug in Intel PIIX controllers */
+	uhci_fill_td(&uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+	uhci->skel_term_td.link = UHCI_PTR_TERM;
+
+	uhci->skel_term_qh.link = UHCI_PTR_TERM;
+	uhci->skel_term_qh.element = virt_to_bus(&uhci->skel_term_td);
 
 	/*
 	 * Fill the frame list: make all entries point to
@@ -939,7 +2185,8 @@
 	 * us a reasonable dynamic range for irq latencies.
 	 */
 	for (i = 0; i < 1024; i++) {
-		struct uhci_qh * irq = &dev->skel_int2_qh;
+		struct uhci_td *irq = &uhci->skel_int1_td;
+
 		if (i & 1) {
 			irq++;
 			if (i & 2) {
@@ -952,21 +2199,31 @@
 							irq++;
 							if (i & 32) {
 								irq++;
-								if (i & 64) {
+								if (i & 64)
 									irq++;
-								}
 							}
 						}
 					}
 				}
 			}
 		}
-		uhci->fl->frame[i] =  2 | virt_to_bus(irq);
+
+		/* Only place we don't use the frame list routines */
+		uhci->fl->frame[i] =  virt_to_bus(irq);
 	}
 
 	return uhci;
-}
 
+/*
+ * error exits:
+ */
+au_free_fl:
+	free_page((unsigned long)uhci->fl);
+au_free_uhci:
+	kfree(uhci);
+
+	return NULL;
+}
 
 /*
  * De-allocate all resources..
@@ -978,236 +2235,259 @@
 		uhci->irq = -1;
 	}
 
-#if 0
-	if (uhci->root_hub) {
-		uhci_usb_deallocate(uhci_to_usb(uhci->root_hub));
-		uhci->root_hub = NULL;
-	}
-#endif
-
 	if (uhci->fl) {
 		free_page((unsigned long)uhci->fl);
 		uhci->fl = NULL;
 	}
 
-	kfree(uhci->bus);
+	usb_free_bus(uhci->bus);
 	kfree(uhci);
 }
 
-void cleanup_drivers(void);
-
-static int uhci_control_thread(void * __uhci)
+int uhci_start_root_hub(struct uhci *uhci)
 {
-	struct uhci *uhci = (struct uhci *)__uhci;
-
-	lock_kernel();
-	request_region(uhci->io_addr, 32, "usb-uhci");
+	struct usb_device *dev;
 
-	/*
-	 * This thread doesn't need any user-level access,
-	 * so get rid of all our resources..
-	 */
-	printk("uhci_control_thread at %p\n", &uhci_control_thread);
-	exit_mm(current);
-	exit_files(current);
-	exit_fs(current);
+	dev = usb_alloc_dev(NULL, uhci->bus);
+	if (!dev)
+		return -1;
 
-	strcpy(current->comm, "uhci-control");
+	uhci->bus->root_hub = dev;
+	usb_connect(dev);
 
-	/*
-	 * Ok, all systems are go..
-	 */
-	start_hc(uhci);
-	for(;;) {
-		siginfo_t info;
-		int unsigned long signr;
-
-		interruptible_sleep_on(&uhci_configure);
-#ifdef CONFIG_APM
-		if (apm_resume) {
-			apm_resume = 0;
-			start_hc(uhci);
-			continue;
-		}
-#endif
-		uhci_check_configuration(uhci);
+	if (usb_new_device(dev) != 0) {
+		usb_free_dev(dev);
 
-		if(signal_pending(current)) {
-			/* sending SIGUSR1 makes us print out some info */
-			spin_lock_irq(&current->sigmask_lock);
-			signr = dequeue_signal(&current->blocked, &info);
-			spin_unlock_irq(&current->sigmask_lock);
-
-			if(signr == SIGUSR1) {
-				printk("UHCI queue dump:\n");
-				show_queues(uhci);
-			} else {
-				break;
-			}
-		}
+		return -1;
 	}
 
-#if 0
-	if(uhci->root_hub)
-		for(i = 0; i < uhci->root_hub->usb->maxchild; i++)
-			usb_disconnect(uhci->root_hub->usb->children + i);
-#endif
-
-	cleanup_drivers();
-
-	reset_hc(uhci);
-	release_region(uhci->io_addr, 32);
-
-	release_uhci(uhci);
-	MOD_DEC_USE_COUNT;
-
-	printk("uhci_control_thread exiting\n");
-
 	return 0;
-}	
+}
 
 /*
  * If we've successfully found a UHCI, now is the time to increment the
- * module usage count, start the control thread, and return success..
+ * module usage count, and return success..
  */
-static int found_uhci(int irq, unsigned int io_addr)
+static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
 {
 	int retval;
 	struct uhci *uhci;
+	char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+	sprintf(buf, "%d", irq);
+#else
+	bufp = __irq_itoa(irq);
+#endif
+	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+		io_addr, bufp);
 
-	uhci = alloc_uhci(io_addr);
+	uhci = alloc_uhci(io_addr, io_size);
 	if (!uhci)
 		return -ENOMEM;
 
+	INIT_LIST_HEAD(&uhci->uhci_list);
+	list_add(&uhci->uhci_list, &uhci_list);
+
+	request_region(uhci->io_addr, io_size, "usb-uhci");
+
 	reset_hc(uhci);
 
-	retval = -EBUSY;
-	if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb", uhci) == 0) {
-		int pid;
+	usb_register_bus(uhci->bus);
+	start_hc(uhci);
 
-		MOD_INC_USE_COUNT;
+	retval = -EBUSY;
+	if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) {
 		uhci->irq = irq;
-		pid = kernel_thread(uhci_control_thread, uhci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-		if (pid >= 0)
-			return 0;
 
-		MOD_DEC_USE_COUNT;
-		retval = pid;
+		if (!uhci_start_root_hub(uhci)) {
+			struct pm_dev *pmdev;
+
+			pmdev = pm_register(PM_PCI_DEV,
+					    PM_PCI_ID(dev),
+					    handle_pm_event);
+			if (pmdev)
+				pmdev->data = uhci;
+			return 0;
+		}
 	}
+
+	/* Couldn't allocate IRQ if we got here */
+	list_del(&uhci->uhci_list);
+	INIT_LIST_HEAD(&uhci->uhci_list);
+
+	reset_hc(uhci);
+	release_region(uhci->io_addr, uhci->io_size);
 	release_uhci(uhci);
+
 	return retval;
 }
 
-static int start_uhci(struct pci_dev *dev)
+static int found_uhci(struct pci_dev *dev)
 {
 	int i;
 
+	/* disable legacy emulation */
+	pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+	if (pci_enable_device(dev) < 0)
+		return -1;
+
+	if (!dev->irq) {
+		err("found UHCI device with no IRQ assigned. check BIOS settings!");
+		return -1;
+	}
+
 	/* Search for the IO base address.. */
 	for (i = 0; i < 6; i++) {
-		unsigned int io_addr = dev->base_address[i];
+		unsigned int io_addr = pci_resource_start(dev, i);
+		unsigned int io_size = pci_resource_len(dev, i);
 
 		/* IO address? */
-		if (!(io_addr & 1))
+		if (!(pci_resource_flags(dev, i) & IORESOURCE_IO))
 			continue;
 
-		io_addr &= PCI_BASE_ADDRESS_IO_MASK;
-
 		/* Is it already in use? */
-		if (check_region(io_addr, 32))
+		if (check_region(io_addr, io_size))
 			break;
 
-		return found_uhci(dev->irq, io_addr);
+		return setup_uhci(dev, dev->irq, io_addr, io_size);
 	}
+
 	return -1;
 }
 
-#ifdef CONFIG_APM
-static int handle_apm_event(apm_event_t event)
+static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
 {
-	static int down = 0;
-
-	switch (event) {
-	case APM_SYS_SUSPEND:
-	case APM_USER_SUSPEND:
-		if (down) {
-			printk(KERN_DEBUG "uhci: received extra suspend event\n");
-			break;
-		}
-		down = 1;
+	struct uhci *uhci = dev->data;
+	switch (rqst) {
+	case PM_SUSPEND:
+		reset_hc(uhci);
 		break;
-	case APM_NORMAL_RESUME:
-	case APM_CRITICAL_RESUME:
-		if (!down) {
-			printk(KERN_DEBUG "uhci: received bogus resume event\n");
-			break;
-		}
-		down = 0;
-		if (waitqueue_active(&uhci_configure)) {
-			apm_resume = 1;
-			wake_up(&uhci_configure);
-		}
+	case PM_RESUME:
+		reset_hc(uhci);
+		start_hc(uhci);
 		break;
 	}
 	return 0;
 }
-#endif
-
-#ifdef MODULE
-
-void cleanup_module(void)
-{
-#ifdef CONFIG_APM
-	apm_unregister_callback(&handle_apm_event);
-#endif
-}
-
-#define uhci_init init_module
-
-#endif
 
 int uhci_init(void)
 {
 	int retval;
-	struct pci_dev *dev = NULL;
+	struct pci_dev *dev;
 	u8 type;
 
+	retval = -ENOMEM;
+
+	/* We throw all of the TD's and QH's into a kmem cache */
+	/* TD's and QH's need to be 16 byte aligned and SLAB_HWCACHE_ALIGN */
+	/*  does this for us */
+	uhci_td_cachep = kmem_cache_create("uhci_td",
+		sizeof(struct uhci_td), 0,
+		SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+	if (!uhci_td_cachep)
+		goto td_failed;
+
+	uhci_qh_cachep = kmem_cache_create("uhci_qh",
+		sizeof(struct uhci_qh), 0,
+		SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+	if (!uhci_qh_cachep)
+		goto qh_failed;
+
+	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
+		sizeof(struct urb_priv), 0, 0, NULL, NULL);
+
+	if (!uhci_up_cachep)
+		goto up_failed;
+
 	retval = -ENODEV;
+	dev = NULL;
 	for (;;) {
-		dev = pci_find_class(PCI_CLASS_SERIAL_USB<<8, dev);
+		dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev);
 		if (!dev)
 			break;
-		/* Is it UHCI */
+
+		/* Is it the UHCI programming interface? */
 		pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
-		if(type != 0)
+		if (type != 0)
 			continue;
+
 		/* Ok set it up */
-		retval = start_uhci(dev);
-		if (retval < 0)
-			continue;
+		retval = found_uhci(dev);
+	}
 
-#ifdef CONFIG_USB_MOUSE
-		usb_mouse_init();
-#endif
-#ifdef CONFIG_USB_KBD		
-		usb_kbd_init();
-#endif		
-		hub_init();
-#ifdef CONFIG_USB_AUDIO		
-		usb_audio_init();
-#endif		
-#ifdef CONFIG_APM
-		apm_register_callback(&handle_apm_event);
-#endif
+	/* We only want to return an error code if ther was an error */
+	/*  and we didn't find a UHCI controller */
+	if (retval && list_empty(&uhci_list))
+		goto init_failed;
 
-		return 0;
-	}
+	return 0;
+
+init_failed:
+	if (kmem_cache_destroy(uhci_up_cachep))
+		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
+up_failed:
+	if (kmem_cache_destroy(uhci_qh_cachep))
+		printk(KERN_INFO "uhci: not all QH's were freed\n");
+
+qh_failed:
+	if (kmem_cache_destroy(uhci_td_cachep))
+		printk(KERN_INFO "uhci: not all TD's were freed\n");
+
+td_failed:
 	return retval;
 }
 
-void cleanup_drivers(void)
+void uhci_cleanup(void)
 {
-	hub_cleanup();
-#ifdef CONFIG_USB_MOUSE
-	usb_mouse_cleanup();
-#endif
+	struct list_head *tmp, *head = &uhci_list;
+
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list);
+
+		tmp = tmp->next;
+
+		list_del(&uhci->uhci_list);
+		INIT_LIST_HEAD(&uhci->uhci_list);
+
+		if (uhci->bus->root_hub)
+			usb_disconnect(&uhci->bus->root_hub);
+
+		usb_deregister_bus(uhci->bus);
+
+		reset_hc(uhci);
+		release_region(uhci->io_addr, uhci->io_size);
+
+		uhci_free_pending_qhs(uhci);
+
+		release_uhci(uhci);
+	}
+
+	if (kmem_cache_destroy(uhci_up_cachep))
+		printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
+	if (kmem_cache_destroy(uhci_qh_cachep))
+		printk(KERN_INFO "uhci: not all QH's were freed\n");
+
+	if (kmem_cache_destroy(uhci_td_cachep))
+		printk(KERN_INFO "uhci: not all TD's were freed\n");
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return uhci_init();
+}
+
+void cleanup_module(void)
+{
+	pm_unregister_all(handle_pm_event);
+	uhci_cleanup();
 }
+#endif //MODULE
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/uhci.h linux.18p8/drivers/usb/uhci.h
--- linux.vanilla/drivers/usb/uhci.h	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/uhci.h	Fri Sep 15 15:13:11 2000
@@ -2,8 +2,37 @@
 #define __LINUX_UHCI_H
 
 #include <linux/list.h>
+#include <linux/usb.h>
 
-#include "usb.h"
+/*
+ * This nested spinlock code is courtesy of Davide Libenzi <dlibenzi@maticad.it>
+ */
+struct s_nested_lock {
+	spinlock_t lock;
+	void *uniq;
+	short int count;
+};
+
+#define nested_init(snl) \
+	spin_lock_init(&(snl)->lock); \
+	(snl)->uniq = NULL; \
+	(snl)->count = 0;
+
+#define nested_lock(snl, flags) \
+	if ((snl)->uniq == current) { \
+		(snl)->count++; \
+		flags = 0; /* No warnings */ \
+	} else { \
+		spin_lock_irqsave(&(snl)->lock, flags); \
+		(snl)->count++; \
+		(snl)->uniq = current; \
+	}
+
+#define nested_unlock(snl, flags) \
+	if (!--(snl)->count) { \
+		(snl)->uniq = NULL; \
+		spin_unlock_irqrestore(&(snl)->lock, flags); \
+	}
 
 /*
  * Universal Host Controller Interface data structures and defines
@@ -53,17 +82,83 @@
 #define   USBPORTSC_PR		0x0200	/* Port Reset */
 #define   USBPORTSC_SUSP	0x1000	/* Suspend */
 
-struct uhci_qh {
-	unsigned int link;	/* Next queue */
-	unsigned int element;	/* Queue element pointer */
-	int inuse;		/* Inuse? */
-	struct uhci_qh *skel;	/* Skeleton head */
-} __attribute__((aligned(16)));
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_DEFAULT	0x2000	/* only PIRQ enable set */
+
+#define UHCI_NULL_DATA_SIZE	0x7FF	/* for UHCI controller TD */
+
+#define UHCI_PTR_BITS		0x000F
+#define UHCI_PTR_TERM		0x0001
+#define UHCI_PTR_QH		0x0002
+#define UHCI_PTR_DEPTH		0x0004
+
+#define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
+#define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
 
 struct uhci_framelist {
-	unsigned int frame[1024];
+	__u32 frame[UHCI_NUMFRAMES];
 } __attribute__((aligned(4096)));
 
+struct uhci_td;
+
+struct uhci_qh {
+	/* Hardware fields */
+	__u32 link;				/* Next queue */
+	__u32 element;				/* Queue element pointer */
+
+	/* Software fields */
+	/* Can't use list_head since we want a specific order */
+	struct usb_device *dev;			/* The owning device */
+
+	struct uhci_qh *prevqh, *nextqh;
+
+	struct list_head remove_list;
+} __attribute__((aligned(16)));
+
+/*
+ * for TD <status>:
+ */
+#define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK	(3 << 27)	/* Error Counter bits */
+#define TD_CTRL_C_ERR_SHIFT	27
+#define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
+#define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
+#define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
+#define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
+#define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
+#define TD_CTRL_DBUFERR		(1 << 21)	/* Data Buffer Error */
+#define TD_CTRL_BABBLE		(1 << 20)	/* Babble Detected */
+#define TD_CTRL_NAK		(1 << 19)	/* NAK Received */
+#define TD_CTRL_CRCTIMEO	(1 << 18)	/* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF	(1 << 17)	/* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK	0x7FF		/* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define uhci_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
+#define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+
+#define uhci_ptr_to_virt(x)	bus_to_virt(x & ~UHCI_PTR_BITS)
+
+/*
+ * for TD <info>: (a.k.a. Token)
+ */
+#define TD_TOKEN_TOGGLE		19
+#define TD_PID			0xFF
+
+#define uhci_maxlen(token)	((token) >> 21)
+#define uhci_expected_length(info) (((info >> 21) + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
+#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
+#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
+#define uhci_devep(token)	(((token) >> 8) & 0x7ff)
+#define uhci_packetid(token)	((token) & 0xff)
+#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
+#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
+
 /*
  * The documentation says "4 words for hardware, 4 words for software".
  *
@@ -75,7 +170,7 @@
  * On 64-bit machines we probably want to take advantage of the fact that
  * hw doesn't really care about the size of the sw-only area.
  *
- * Alas, not anymore, we have more than 4 words of software, woops
+ * Alas, not anymore, we have more than 4 words for software, woops
  */
 struct uhci_td {
 	/* Hardware fields */
@@ -85,48 +180,14 @@
 	__u32 buffer;
 
 	/* Software fields */
-	struct list_head irq_list;	/* Active interrupt list.. */
-	usb_device_irq completed;	/* Completion handler routine */
-	unsigned int *backptr;		/* Where to remove this from.. */
-	void *dev_id;
-	int inuse;			/* Inuse? */
-	struct uhci_qh *qh;
-} __attribute__((aligned(32)));
-
-/*
- * Note the alignment requirements of the entries
- *
- * Each UHCI device has pre-allocated QH and TD entries.
- * You can use more than the pre-allocated ones, but I
- * don't see you usually needing to.
- */
-struct uhci;
+	unsigned int *frameptr;		/* Frame list pointer */
+	struct uhci_td *prevtd, *nexttd; /* Previous and next TD in queue */
 
-#define UHCI_MAXTD 64
+	struct usb_device *dev;
+	struct urb *urb;		/* URB this TD belongs to */
 
-#define UHCI_MAXQH	16
-
-/* The usb device part must be first! */
-struct uhci_device {
-	struct usb_device	*usb;
-
-	struct uhci		*uhci;
-	struct uhci_qh		qh[UHCI_MAXQH];		/* These are the "common" qh's for each device */
-	struct uhci_td		td[UHCI_MAXTD];
-
-	unsigned long		data[16];
-};
-
-#define uhci_to_usb(uhci)	((uhci)->usb)
-#define usb_to_uhci(usb)	((struct uhci_device *)(usb)->hcpriv)
-
-/*
- * The root hub pre-allocated QH's and TD's have
- * some special global uses..
- */
-#define control_td	td		/* Td's 0-30 */
-/* This is only for the root hub's TD list */
-#define tick_td		td[31]
+	struct list_head list;
+} __attribute__((aligned(16)));
 
 /*
  * There are various standard queues. We set up several different
@@ -151,49 +212,92 @@
  * be scared, it kinda makes sense. Look at this wonderful picture care of
  * Linus:
  *
- *  generic-iso-QH  ->  dev1-iso-QH  ->  generic-irq-QH  ->  dev1-irq-QH  -> ...
- *       |                       |                  |                   |
- *      End          dev1-iso-TD1          End            dev1-irq-TD1
- *                       |
- *                   dev1-iso-TD2
- *                       |
- *                      ....
+ *  generic-  ->  dev1-  ->  generic-  ->  dev1-  ->  control-  ->  bulk- -> ...
+ *   iso-QH      iso-QH       irq-QH      irq-QH        QH           QH
+ *      |           |            |           |           |            |
+ *     End     dev1-iso-TD1     End     dev1-irq-TD1    ...          ... 
+ *                  |
+ *             dev1-iso-TD2
+ *                  |
+ *                ....
  *
  * This may vary a bit (the UHCI docs don't explicitly say you can put iso
  * transfers in QH's and all of their pictures don't have that either) but
  * other than that, that is what we're doing now
  *
- * To keep with Linus' nomenclature, this is called the qh skeleton. These
- * labels (below) are only signficant to the root hub's qh's
+ * And now we don't put Iso transfers in QH's, so we don't waste one on it
+ * --jerdfelt
+ *
+ * To keep with Linus' nomenclature, this is called the QH skeleton. These
+ * labels (below) are only signficant to the root hub's QH's
  */
-#define skel_iso_qh		qh[0]
 
-#define skel_int2_qh		qh[1]
-#define skel_int4_qh		qh[2]
-#define skel_int8_qh		qh[3]
-#define skel_int16_qh		qh[4]
-#define skel_int32_qh		qh[5]
-#define skel_int64_qh		qh[6]
-#define skel_int128_qh		qh[7]
-#define skel_int256_qh		qh[8]
-
-#define skel_control_qh		qh[9]
-
-#define skel_bulk0_qh		qh[10]
-#define skel_bulk1_qh		qh[11]
-#define skel_bulk2_qh		qh[12]
-#define skel_bulk3_qh		qh[13]
-
-/*
- * These are significant to the devices allocation of QH's
- */
-#if 0
-#define iso_qh			qh[0]
-#define int_qh			qh[1]	/* We have 2 "common" interrupt QH's */
-#define control_qh		qh[3]
-#define bulk_qh			qh[4]	/* We have 4 "common" bulk QH's */
-#define extra_qh		qh[8]	/* The rest, anything goes */
-#endif
+#define UHCI_NUM_SKELTD		10
+#define skel_int1_td		skeltd[0]
+#define skel_int2_td		skeltd[1]
+#define skel_int4_td		skeltd[2]
+#define skel_int8_td		skeltd[3]
+#define skel_int16_td		skeltd[4]
+#define skel_int32_td		skeltd[5]
+#define skel_int64_td		skeltd[6]
+#define skel_int128_td		skeltd[7]
+#define skel_int256_td		skeltd[8]
+#define skel_term_td		skeltd[9]	/* To work around PIIX UHCI bug */
+
+#define UHCI_NUM_SKELQH		4
+#define skel_ls_control_qh	skelqh[0]
+#define skel_hs_control_qh	skelqh[1]
+#define skel_bulk_qh		skelqh[2]
+#define skel_term_qh		skelqh[3]
+
+/*
+ * Search tree for determining where <interval> fits in the
+ * skelqh[] skeleton.
+ *
+ * An interrupt request should be placed into the slowest skelqh[]
+ * which meets the interval/period/frequency requirement.
+ * An interrupt request is allowed to be faster than <interval> but not slower.
+ *
+ * For a given <interval>, this function returns the appropriate/matching
+ * skelqh[] index value.
+ *
+ * NOTE: For UHCI, we don't really need int256_qh since the maximum interval
+ * is 255 ms.  However, we do need an int1_qh since 1 is a valid interval
+ * and we should meet that frequency when requested to do so.
+ * This will require some change(s) to the UHCI skeleton.
+ */
+static inline int __interval_to_skel(int interval)
+{
+	if (interval < 16) {
+		if (interval < 4) {
+			if (interval < 2)
+				return 0;	/* int1 for 0-1 ms */
+			return 1;		/* int2 for 2-3 ms */
+		}
+		if (interval < 8)
+			return 2;		/* int4 for 4-7 ms */
+		return 3;			/* int8 for 8-15 ms */
+	}
+	if (interval < 64) {
+		if (interval < 32)
+			return 4;		/* int16 for 16-31 ms */
+		return 5;			/* int32 for 32-63 ms */
+	}
+	if (interval < 128)
+		return 6;			/* int64 for 64-127 ms */
+	return 7;				/* int128 for 128-255 ms (Max.) */
+}
+
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	int c_p_r[8];
+	struct timer_list rh_int_timer;
+};
 
 /*
  * This describes the full uhci information.
@@ -202,28 +306,117 @@
  * a subset of what the full implementation needs.
  */
 struct uhci {
+	/* Grabbed from PCI */
 	int irq;
 	unsigned int io_addr;
+	unsigned int io_size;
+
+	struct list_head uhci_list;
 
 	struct usb_bus *bus;
 
-#if 0
-	/* These are "standard" QH's for the entire bus */
-	struct uhci_qh qh[UHCI_MAXQH];
-#endif
-	struct uhci_device *root_hub;		/* Root hub device descriptor.. */
+	struct uhci_td skeltd[UHCI_NUM_SKELTD];	/* Skeleton TD's */
+	struct uhci_qh skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
 
+	spinlock_t framelist_lock;
 	struct uhci_framelist *fl;		/* Frame list */
-	struct list_head interrupt_list;	/* List of interrupt-active TD's for this uhci */
+	int fsbr;				/* Full speed bandwidth reclamation */
+
+	spinlock_t qh_remove_lock;
+	struct list_head qh_remove_list;
+
+	spinlock_t urb_remove_lock;
+	struct list_head urb_remove_list;
+
+	struct s_nested_lock urblist_lock;
+	struct list_head urb_list;
+
+	struct virt_root_hub rh;	/* private data of the virtual root hub */
+};
+
+struct urb_priv {
+	struct urb *urb;
+
+	struct uhci_qh *qh;		/* QH for this URB */
+
+	int fsbr : 1;			/* URB turned on FSBR */
+	int fsbr_timeout : 1;		/* URB timed out on FSBR */
+	int queued : 1;			/* QH was queued (not linked in) */
+	int short_control_packet : 1;	/* If we get a short packet during */
+					/*  a control transfer, retrigger */
+					/*  the status phase */
+
+	unsigned long inserttime;	/* In jiffies */
+
+	struct list_head list;
+
+	struct list_head urb_queue_list;	/* URB's linked together */
 };
 
+/* -------------------------------------------------------------------------
+   Virtual Root HUB
+   ------------------------------------------------------------------------- */
+/* destination of request */
+#define RH_DEVICE		0x00
+#define RH_INTERFACE		0x01
+#define RH_ENDPOINT		0x02
+#define RH_OTHER		0x03
+
+#define RH_CLASS		0x20
+#define RH_VENDOR		0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	0x00
+#define RH_PORT_ENABLE		0x01
+#define RH_PORT_SUSPEND		0x02
+#define RH_PORT_OVER_CURRENT	0x03
+#define RH_PORT_RESET		0x04
+#define RH_PORT_POWER		0x08
+#define RH_PORT_LOW_SPEED	0x09
+#define RH_C_PORT_CONNECTION	0x10
+#define RH_C_PORT_ENABLE	0x11
+#define RH_C_PORT_SUSPEND	0x12
+#define RH_C_PORT_OVER_CURRENT	0x13
+#define RH_C_PORT_RESET		0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	0x00
+#define RH_C_HUB_OVER_CURRENT	0x01
+#define RH_DEVICE_REMOTE_WAKEUP	0x00
+#define RH_ENDPOINT_STALL	0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP		0x00
+
+#define RH_ACK			0x01
+#define RH_REQ_ERR		-1
+#define RH_NACK			0x00
+
 /* needed for the debugging code */
 struct uhci_td *uhci_link_to_td(unsigned int element);
 
 /* Debugging code */
-void show_td(struct uhci_td * td);
-void show_status(struct uhci *uhci);
-void show_queues(struct uhci *uhci);
+void uhci_show_td(struct uhci_td *td);
+void uhci_show_status(struct uhci *uhci);
+void uhci_show_urb_queue(struct urb *urb);
+void uhci_show_queue(struct uhci_qh *qh);
+void uhci_show_queues(struct uhci *uhci);
 
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-core.c linux.18p8/drivers/usb/usb-core.c
--- linux.vanilla/drivers/usb/usb-core.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usb-core.c	Tue Sep  5 22:20:48 2000
@@ -0,0 +1,117 @@
+/*
+ * driver/usb/usb-core.c
+ *
+ * (C) Copyright David Waite 1999
+ * based on code from usb.c, by Linus Torvalds
+ *
+ * The purpose of this file is to pull any and all generic modular code from
+ * usb.c and put it in a separate file. This way usb.c is kept as a generic
+ * library, while this file handles starting drivers, etc.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/usb.h>
+
+/*
+ * USB core
+ */
+
+int usb_hub_init(void);
+void usb_hub_cleanup(void);
+int usb_major_init(void);
+void usb_major_cleanup(void);
+
+/*
+ * USB device drivers
+ */
+
+int input_init_module(void);
+int acm_init_module(void);
+int usb_dc2xx_init_module(void);
+int evdev_init_module(void);
+int hid_init_module(void);
+int joydev_init_module(void);
+int keybdev_init_module(void);
+int mousedev_init_module(void);
+int microtek_drv_init_module(void);
+int usblp_init_module(void);
+int usb_ov511_init_module(void);
+int usb_rio_init_module(void);
+int usb_scanner_init_module(void);
+int usb_serial_init_module(void);
+int usb_stor_init_module(void);
+int usb_kbd_init_module(void);
+int usb_mouse_init_module(void);
+int wacom_init_module(void);
+int wmforce_init_module(void);
+
+int usb_audio_init(void);
+int usb_ibmcam_init(void);
+int dabusb_init(void);
+int plusb_init(void);
+int dsbr100_init(void);
+
+/*
+ * HCI drivers
+ */
+
+int uhci_init(void);
+int ohci_hcd_init(void);
+
+#ifdef MODULE
+
+/*
+ * Cleanup
+ */
+
+void cleanup_module(void)
+{
+	usb_major_cleanup();
+	usbdevfs_cleanup();
+	usb_hub_cleanup();
+}
+
+/*
+ * Init
+ */
+
+int init_module(void)
+#else
+int usb_init(void)
+#endif
+{
+	usb_major_init();
+	usbdevfs_init();
+	usb_hub_init();
+
+#ifndef CONFIG_USB_MODULE
+#ifdef CONFIG_USB_AUDIO
+	usb_audio_init();
+#endif
+#ifdef CONFIG_USB_IBMCAM
+	usb_ibmcam_init();
+#endif
+#ifdef CONFIG_USB_DABUSB
+	dabusb_init();
+#endif
+#ifdef CONFIG_USB_DSBR
+	dsbr100_init();
+#endif
+#ifdef CONFIG_USB_PLUSB
+	plusb_init();
+#endif
+#ifdef CONFIG_USB_UHCI
+	uhci_init();
+#endif
+#ifdef CONFIG_USB_UHCI_ALT
+	uhci_init();
+#endif
+#ifdef CONFIG_USB_OHCI
+	ohci_hcd_init(); 
+#endif
+#endif
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-debug.c linux.18p8/drivers/usb/usb-debug.c
--- linux.vanilla/drivers/usb/usb-debug.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/usb-debug.c	Fri Sep  1 13:51:30 2000
@@ -4,31 +4,49 @@
  * I just want these out of the way where they aren't in your
  * face, but so that you can still use them..
  */
+#include <linux/config.h>
+#include <linux/version.h>
 #include <linux/kernel.h>
-
-#include "usb.h"
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
 
 static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint)
 {
 	usb_show_endpoint_descriptor(endpoint);
 }
 
-static void usb_show_interface(struct usb_interface_descriptor *interface)
+static void usb_show_interface(struct usb_interface_descriptor *altsetting)
 {
 	int i;
 
-	usb_show_interface_descriptor(interface);
-	for (i = 0 ; i < interface->bNumEndpoints; i++)
-		usb_show_endpoint(interface->endpoint + i);
+	usb_show_interface_descriptor(altsetting);
+
+	for (i = 0; i < altsetting->bNumEndpoints; i++)
+		usb_show_endpoint(altsetting->endpoint + i);
 }
 
 static void usb_show_config(struct usb_config_descriptor *config)
 {
-	int i;
+	int i, j;
+	struct usb_interface *ifp;
 
 	usb_show_config_descriptor(config);
-	for (i = 0 ; i < config->bNumInterfaces; i++)
-		usb_show_interface(config->interface + i);
+	for (i = 0; i < config->bNumInterfaces; i++) {
+		ifp = config->interface + i;
+
+		if (!ifp)
+			break;
+
+		printk("\n  Interface: %d\n", i);
+		for (j = 0; j < ifp->num_altsetting; j++)
+			usb_show_interface(ifp->altsetting + j);
+	}
 }
 
 void usb_show_device(struct usb_device *dev)
@@ -40,26 +58,54 @@
 		usb_show_config(dev->config + i);
 }
 
-
 /*
  * Parse and show the different USB descriptors.
  */
 void usb_show_device_descriptor(struct usb_device_descriptor *desc)
 {
-	printk("  USB version %x.%02x\n", desc->bcdUSB >> 8, desc->bcdUSB & 0xff);
-	printk("  Vendor:  %04x\n", desc->idVendor);
-	printk("  Product: %04x\n", desc->idProduct);
-	printk("  Configurations: %d\n", desc->bNumConfigurations);
+	if (!desc)
+	{
+		printk("Invalid USB device descriptor (NULL POINTER)\n");
+		return;
+	}
+	printk("  Length              = %2d%s\n", desc->bLength,
+		desc->bLength == USB_DT_DEVICE_SIZE ? "" : " (!!!)");
+	printk("  DescriptorType      = %02x\n", desc->bDescriptorType);
+
+	printk("  USB version         = %x.%02x\n",
+		desc->bcdUSB >> 8, desc->bcdUSB & 0xff);
+	printk("  Vendor:Product      = %04x:%04x\n",
+		desc->idVendor, desc->idProduct);
+	printk("  MaxPacketSize0      = %d\n", desc->bMaxPacketSize0);
+	printk("  NumConfigurations   = %d\n", desc->bNumConfigurations);
+	printk("  Device version      = %x.%02x\n",
+		desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
 
-	printk("  Device Class: %d\n", desc->bDeviceClass);
+	printk("  Device Class:SubClass:Protocol = %02x:%02x:%02x\n",
+		desc->bDeviceClass, desc->bDeviceSubClass, desc->bDeviceProtocol);
 	switch (desc->bDeviceClass) {
 	case 0:
 		printk("    Per-interface classes\n");
 		break;
-	case 9:
+	case USB_CLASS_AUDIO:
+		printk("    Audio device class\n");
+		break;
+	case USB_CLASS_COMM:
+		printk("    Communications class\n");
+		break;
+	case USB_CLASS_HID:
+		printk("    Human Interface Devices class\n");
+		break;
+	case USB_CLASS_PRINTER:
+		printk("    Printer device class\n");
+		break;
+	case USB_CLASS_MASS_STORAGE:
+		printk("    Mass Storage device class\n");
+		break;
+	case USB_CLASS_HUB:
 		printk("    Hub device class\n");
 		break;
-	case 0xff:
+	case USB_CLASS_VENDOR_SPEC:
 		printk("    Vendor class\n");
 		break;
 	default:
@@ -67,11 +113,11 @@
 	}
 }
 
-void usb_show_config_descriptor(struct usb_config_descriptor * desc)
+void usb_show_config_descriptor(struct usb_config_descriptor *desc)
 {
 	printk("Configuration:\n");
 	printk("  bLength             = %4d%s\n", desc->bLength,
-		desc->bLength == 9 ? "" : " (!!!)");
+		desc->bLength == USB_DT_CONFIG_SIZE ? "" : " (!!!)");
 	printk("  bDescriptorType     =   %02x\n", desc->bDescriptorType);
 	printk("  wTotalLength        = %04x\n", desc->wTotalLength);
 	printk("  bNumInterfaces      =   %02x\n", desc->bNumInterfaces);
@@ -81,47 +127,77 @@
 	printk("  MaxPower            = %4dmA\n", desc->MaxPower * 2);
 }
 
-void usb_show_interface_descriptor(struct usb_interface_descriptor * desc)
+void usb_show_interface_descriptor(struct usb_interface_descriptor *desc)
 {
-	printk("  Interface:\n");
+	printk("  Alternate Setting: %2d\n", desc->bAlternateSetting);
 	printk("    bLength             = %4d%s\n", desc->bLength,
-		desc->bLength == 9 ? "" : " (!!!)");
+		desc->bLength == USB_DT_INTERFACE_SIZE ? "" : " (!!!)");
 	printk("    bDescriptorType     =   %02x\n", desc->bDescriptorType);
 	printk("    bInterfaceNumber    =   %02x\n", desc->bInterfaceNumber);
 	printk("    bAlternateSetting   =   %02x\n", desc->bAlternateSetting);
 	printk("    bNumEndpoints       =   %02x\n", desc->bNumEndpoints);
-	printk("    bInterfaceClass     =   %02x\n", desc->bInterfaceClass);
-	printk("    bInterfaceSubClass  =   %02x\n", desc->bInterfaceSubClass);
-	printk("    bInterfaceProtocol  =   %02x\n", desc->bInterfaceProtocol);
+	printk("    bInterface Class:SubClass:Protocol =   %02x:%02x:%02x\n",
+		desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol);
 	printk("    iInterface          =   %02x\n", desc->iInterface);
 }
 
-void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc)
+void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc)
 {
+	char *LengthCommentString = (desc->bLength ==
+		USB_DT_ENDPOINT_AUDIO_SIZE) ? " (Audio)" : (desc->bLength ==
+		USB_DT_ENDPOINT_SIZE) ? "" : " (!!!)";
 	char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };
+
 	printk("    Endpoint:\n");
-	printk("      bLength             = %4d%s\n", desc->bLength,
-		desc->bLength == 7 ? "" : " (!!!)");
+	printk("      bLength             = %4d%s\n",
+		desc->bLength, LengthCommentString);
 	printk("      bDescriptorType     =   %02x\n", desc->bDescriptorType);
 	printk("      bEndpointAddress    =   %02x (%s)\n", desc->bEndpointAddress,
-		(desc->bEndpointAddress & 0x80) ? "in" : "out");
+		(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+			USB_ENDPOINT_XFER_CONTROL ? "i/o" :
+		(desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? "in" : "out");
 	printk("      bmAttributes        =   %02x (%s)\n", desc->bmAttributes,
-		EndpointType[3 & desc->bmAttributes]);
+		EndpointType[USB_ENDPOINT_XFERTYPE_MASK & desc->bmAttributes]);
 	printk("      wMaxPacketSize      = %04x\n", desc->wMaxPacketSize);
 	printk("      bInterval           =   %02x\n", desc->bInterval);
+
+	/* Audio extensions to the endpoint descriptor */
+	if (desc->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) {
+		printk("      bRefresh            =   %02x\n", desc->bRefresh);
+		printk("      bSynchAddress       =   %02x\n", desc->bSynchAddress);
+	}
 }
 
-void usb_show_hub_descriptor(struct usb_hub_descriptor * desc)
+void usb_show_string(struct usb_device *dev, char *id, int index)
 {
-	int len = 7;
-	unsigned char *ptr = (unsigned char *) desc;
+	char *buf;
 
-	printk("Interface:");
-	while (len) {
-		printk(" %02x", *ptr);
-		ptr++; len--;
-	}
-	printk("\n");
+	if (!index)
+		return;
+	if (!(buf = kmalloc(256, GFP_KERNEL)))
+		return;
+	if (usb_string(dev, index, buf, 256) > 0)
+		printk(KERN_INFO "%s: %s\n", id, buf);
+	kfree(buf);
+}
+
+void usb_dump_urb (purb_t purb)
+{
+	printk ("urb                   :%p\n", purb);
+	printk ("next                  :%p\n", purb->next);
+	printk ("dev                   :%p\n", purb->dev);
+	printk ("pipe                  :%08X\n", purb->pipe);
+	printk ("status                :%d\n", purb->status);
+	printk ("transfer_flags        :%08X\n", purb->transfer_flags);
+	printk ("transfer_buffer       :%p\n", purb->transfer_buffer);
+	printk ("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
+	printk ("actual_length         :%d\n", purb->actual_length);
+	printk ("setup_packet          :%p\n", purb->setup_packet);
+	printk ("start_frame           :%d\n", purb->start_frame);
+	printk ("number_of_packets     :%d\n", purb->number_of_packets);
+	printk ("interval              :%d\n", purb->interval);
+	printk ("error_count           :%d\n", purb->error_count);
+	printk ("context               :%p\n", purb->context);
+	printk ("complete              :%p\n", purb->complete);
 }
-
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-ohci.c linux.18p8/drivers/usb/usb-ohci.c
--- linux.vanilla/drivers/usb/usb-ohci.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usb-ohci.c	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,2137 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * 
+ * History:
+ * 
+ * v5.2 1999/12/07 URB 3rd preview, 
+ * v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
+ * v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume 
+ * 	i386: HUB, Keyboard, Mouse, Printer 
+ *
+ * v4.3 1999/10/27 multiple HCs, bulk_request
+ * v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
+ * v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
+ * v4.0 1999/08/18 
+ * v3.0 1999/06/25 
+ * v2.1 1999/05/09  code clean up
+ * v2.0 1999/05/04 
+ * v1.0 1999/04/27 initial release
+ * 
+ 
+ */
+ 
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>  /* for in_interrupt() */
+#undef DEBUG
+#include <linux/usb.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#define OHCI_USE_NPS		// force NoPowerSwitching mode
+
+#include "usb-ohci.h"
+
+#include <linux/pm.h>
+static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data);
+
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#endif
+
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define	OHCI_CONTROL_INIT \
+	(OHCI_CTRL_CBSR & 0x3) \
+	| OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+static DECLARE_WAIT_QUEUE_HEAD (op_wakeup); 
+static LIST_HEAD (ohci_hcd_list);
+static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
+
+/*-------------------------------------------------------------------------*
+ * URB support functions 
+ *-------------------------------------------------------------------------*/ 
+ 
+/* free the private part of an URB */
+ 
+static void urb_rm_priv (urb_t * urb) 
+{
+	urb_priv_t * urb_priv = urb->hcpriv;
+	int i;
+	
+	if (!urb_priv) return;
+	
+	for (i = 0; i < urb_priv->length; i++) {
+		if (urb_priv->td [i]) {
+			OHCI_FREE (urb_priv->td [i]);
+		}
+	}
+	kfree (urb->hcpriv);
+	urb->hcpriv = NULL;
+
+}
+
+/*-------------------------------------------------------------------------*/
+ 
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB     
+ * small: 0) header + data packets 1) just header */
+ 
+static void urb_print (urb_t * urb, char * str, int small)
+{
+	unsigned int pipe= urb->pipe;
+	int i, len;
+	
+	if (!urb->dev || !urb->dev->bus) {
+		dbg("%s URB: no dev", str);
+		return;
+	}
+	
+	dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)", 
+			str,
+		 	sohci_get_current_frame_number (urb->dev), 
+		 	usb_pipedevice (pipe),
+		 	usb_pipeendpoint (pipe), 
+		 	usb_pipeout (pipe)? 'O': 'I',
+		 	usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+		 		(usb_pipecontrol (pipe)? "CTRL": "BULK"),
+		 	urb->transfer_flags, 
+		 	urb->actual_length, 
+		 	urb->transfer_buffer_length,
+		 	urb->status, urb->status);
+	if (!small) {
+		if (usb_pipecontrol (pipe)) {
+			printk (KERN_DEBUG __FILE__ ": cmd(8):");
+			for (i = 0; i < 8 ; i++) 
+				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
+			printk ("\n");
+		}
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printk (KERN_DEBUG __FILE__ ": data(%d/%d):", 
+				urb->actual_length, 
+				urb->transfer_buffer_length);
+			len = usb_pipeout (pipe)? 
+						urb->transfer_buffer_length: urb->actual_length;
+			for (i = 0; i < 16 && i < len; i++) 
+				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
+			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+		}
+	} 
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t * ohci, char * str) {
+	int i, j;
+	 __u32 * ed_p;
+	for (i= 0; i < 32; i++) {
+		j = 5;
+		ed_p = &(ohci->hcca.int_table [i]);
+		if (*ed_p == 0)
+		    continue;
+		printk (KERN_DEBUG __FILE__ ": %s branch int %2d(%2x):", str, i, i);
+		while (*ed_p != 0 && j--) {
+			ed_t *ed = (ed_t *) bus_to_virt(le32_to_cpup(ed_p));
+			printk (" ed: %4x;", ed->hwINFO);
+			ed_p = &ed->hwNextED;
+		}
+		printk ("\n");
+	}
+}
+
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+		label,
+		mask,
+		(mask & OHCI_INTR_MIE) ? " MIE" : "",
+		(mask & OHCI_INTR_OC) ? " OC" : "",
+		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+		(mask & OHCI_INTR_FNO) ? " FNO" : "",
+		(mask & OHCI_INTR_UE) ? " UE" : "",
+		(mask & OHCI_INTR_RD) ? " RD" : "",
+		(mask & OHCI_INTR_SF) ? " SF" : "",
+		(mask & OHCI_INTR_WDH) ? " WDH" : "",
+		(mask & OHCI_INTR_SO) ? " SO" : ""
+		);
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+	if (value)
+		dbg ("%s %08x", label, value);
+}
+
+static char *hcfs2string (int state)
+{
+	switch (state) {
+		case OHCI_USB_RESET:	return "reset";
+		case OHCI_USB_RESUME:	return "resume";
+		case OHCI_USB_OPER:	return "operational";
+		case OHCI_USB_SUSPEND:	return "suspend";
+	}
+	return "?";
+}
+
+// dump control and status registers
+static void ohci_dump_status (ohci_t *controller)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp;
+
+	temp = readl (&regs->revision) & 0xff;
+	if (temp != 0x10)
+		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+	temp = readl (&regs->control);
+	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
+		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
+		(temp & OHCI_CTRL_IR) ? " IR" : "",
+		hcfs2string (temp & OHCI_CTRL_HCFS),
+		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
+		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
+		(temp & OHCI_CTRL_IE) ? " IE" : "",
+		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
+		temp & OHCI_CTRL_CBSR
+		);
+
+	temp = readl (&regs->cmdstatus);
+	dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+		(temp & OHCI_SOC) >> 16,
+		(temp & OHCI_OCR) ? " OCR" : "",
+		(temp & OHCI_BLF) ? " BLF" : "",
+		(temp & OHCI_CLF) ? " CLF" : "",
+		(temp & OHCI_HCR) ? " HCR" : ""
+		);
+
+	ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+	ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+	// intrdisable always same as intrenable
+	// ohci_dump_intr_mask ("intrdisable", readl (&regs->intrdisable));
+
+	maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+	maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+	maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+	maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+	maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+	maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp, ndp, i;
+
+	temp = readl (&regs->roothub.a);
+	ndp = (temp & RH_A_NDP);
+
+	if (verbose) {
+		dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+			((temp & RH_A_POTPGT) >> 24) & 0xff,
+			(temp & RH_A_NOCP) ? " NOCP" : "",
+			(temp & RH_A_OCPM) ? " OCPM" : "",
+			(temp & RH_A_DT) ? " DT" : "",
+			(temp & RH_A_NPS) ? " NPS" : "",
+			(temp & RH_A_PSM) ? " PSM" : "",
+			ndp
+			);
+		temp = readl (&regs->roothub.b);
+		dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = readl (&regs->roothub.status);
+		dbg ("roothub.status: %08x%s%s%s%s%s%s",
+			temp,
+			(temp & RH_HS_CRWE) ? " CRWE" : "",
+			(temp & RH_HS_OCIC) ? " OCIC" : "",
+			(temp & RH_HS_LPSC) ? " LPSC" : "",
+			(temp & RH_HS_DRWE) ? " DRWE" : "",
+			(temp & RH_HS_OCI) ? " OCI" : "",
+			(temp & RH_HS_LPS) ? " LPS" : ""
+			);
+	}
+	
+	for (i = 0; i < ndp; i++) {
+		temp = readl (&regs->roothub.portstatus [i]);
+		dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+			i,
+			temp,
+			(temp & RH_PS_PRSC) ? " PRSC" : "",
+			(temp & RH_PS_OCIC) ? " OCIC" : "",
+			(temp & RH_PS_PSSC) ? " PSSC" : "",
+			(temp & RH_PS_PESC) ? " PESC" : "",
+			(temp & RH_PS_CSC) ? " CSC" : "",
+
+			(temp & RH_PS_LSDA) ? " LSDA" : "",
+			(temp & RH_PS_PPS) ? " PPS" : "",
+			(temp & RH_PS_PRS) ? " PRS" : "",
+			(temp & RH_PS_POCI) ? " POCI" : "",
+			(temp & RH_PS_PSS) ? " PSS" : "",
+
+			(temp & RH_PS_PES) ? " PES" : "",
+			(temp & RH_PS_CCS) ? " CCS" : ""
+			);
+	}
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+	dbg ("OHCI controller %p state", controller->regs);
+
+	// dumps some of the state we know about
+	ohci_dump_status (controller);
+	if (verbose)
+		ep_print_int_eds (controller, "hcca");
+	dbg ("hcca frame #%04x", controller->hcca.frame_no);
+	ohci_dump_roothub (controller, 1);
+}
+
+
+#endif
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* return a request to the completion handler */
+ 
+static int sohci_return_urb (urb_t * urb)
+{
+	urb_priv_t * urb_priv = urb->hcpriv;
+	urb_t * urbt;
+	unsigned long flags;
+	int i;
+	
+	/* just to be sure */
+	if (!urb->complete) {
+		urb_rm_priv (urb);
+		usb_dec_dev_use (urb->dev);
+		return -1;
+	}
+	
+	if (!urb_priv) return -1; /* urb already unlinked */
+	
+#ifdef DEBUG
+	urb_print (urb, "RET", usb_pipeout (urb->pipe));
+#endif
+
+	switch (usb_pipetype (urb->pipe)) {
+  		case PIPE_INTERRUPT:
+			urb->complete (urb); /* call complete and requeue URB */	
+  			urb->actual_length = 0;
+  			urb->status = USB_ST_URB_PENDING;
+  			if (urb_priv->state != URB_DEL)
+  				td_submit_urb (urb);
+  			break;
+  			
+		case PIPE_ISOCHRONOUS:
+			for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);
+			if (urbt) { /* send the reply and requeue URB */	
+				urb->complete (urb);
+				
+				spin_lock_irqsave (&usb_ed_lock, flags);
+				urb->actual_length = 0;
+  				urb->status = USB_ST_URB_PENDING;
+  				urb->start_frame = urb_priv->ed->last_iso + 1;
+  				if (urb_priv->state != URB_DEL) {
+  					for (i = 0; i < urb->number_of_packets; i++) {
+  						urb->iso_frame_desc[i].actual_length = 0;
+  						urb->iso_frame_desc[i].status = -EXDEV;
+  					}
+  					td_submit_urb (urb);
+  				}
+  				spin_unlock_irqrestore (&usb_ed_lock, flags);
+  				
+  			} else { /* unlink URB, call complete */
+				urb_rm_priv (urb);
+				usb_dec_dev_use (urb->dev);
+				urb->complete (urb); 	
+			}		
+			break;
+  				
+		case PIPE_BULK:
+		case PIPE_CONTROL: /* unlink URB, call complete */
+			urb_rm_priv (urb);
+			usb_dec_dev_use (urb->dev);
+			urb->complete (urb);	
+			break;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+ 
+static int sohci_submit_urb (urb_t * urb)
+{
+	ohci_t * ohci;
+	ed_t * ed;
+	urb_priv_t * urb_priv;
+	unsigned int pipe = urb->pipe;
+	int i, size = 0;
+	unsigned long flags;
+	
+	if (!urb->dev || !urb->dev->bus) return -EINVAL;
+	
+	if (urb->hcpriv) return -EINVAL; /* urb already in use */
+
+//	if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe))) 
+//		return -EPIPE;
+	
+	usb_inc_dev_use (urb->dev);
+	ohci = (ohci_t *) urb->dev->bus->hcpriv;
+	
+#ifdef DEBUG
+	urb_print (urb, "SUB", usb_pipein (pipe));
+#endif
+	
+	/* a request to the virtual root hub */
+	if (usb_pipedevice (pipe) == ohci->rh.devnum) 
+		return rh_submit_urb (urb);
+	
+	/* when controller's hung, permit only hub cleanup attempts
+	 * such as powering down ports */
+	if (ohci->disabled)
+		return -ESHUTDOWN;
+
+	/* every endpoint has a ed, locate and fill it */
+	if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {
+		usb_dec_dev_use (urb->dev);	
+		return -ENOMEM;
+	}
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch (usb_pipetype (pipe)) {
+		case PIPE_BULK:	/* one TD for every 4096 Byte */
+			size = (urb->transfer_buffer_length - 1) / 4096 + 1;
+			break;
+		case PIPE_ISOCHRONOUS: /* number of packets from URB */
+			size = urb->number_of_packets;
+			for (i = 0; i < urb->number_of_packets; i++) {
+  				urb->iso_frame_desc[i].actual_length = 0;
+  				urb->iso_frame_desc[i].status = -EXDEV;
+  			}
+			break;
+		case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+			size = (urb->transfer_buffer_length == 0)? 2: 
+						(urb->transfer_buffer_length - 1) / 4096 + 3;
+			break;
+		case PIPE_INTERRUPT: /* one TD */
+			size = 1;
+			
+			break;
+	}
+
+	/* allocate the private part or the URB */
+	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), 
+							in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	if (!urb_priv) {
+		usb_dec_dev_use (urb->dev);	
+		return -ENOMEM;
+	}
+	memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *));
+	
+	/* fill the private part of the URB */
+	urb->hcpriv = urb_priv;
+	urb_priv->length = size;
+	urb_priv->td_cnt = 0;
+	urb_priv->state = 0;
+	urb_priv->ed = ed;	
+	
+	/* allocate the TDs */
+	for (i = 0; i < size; i++) { 
+		OHCI_ALLOC (urb_priv->td[i], sizeof (td_t));
+		if (!urb_priv->td[i]) {
+			usb_dec_dev_use (urb->dev);	
+			urb_rm_priv (urb);
+			return -ENOMEM;
+		}
+	}	
+	spin_lock_irqsave (&usb_ed_lock, flags);	
+	if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+		urb_rm_priv(urb);
+		usb_dec_dev_use (urb->dev);	
+		spin_unlock_irqrestore(&usb_ed_lock, flags);
+		return -EINVAL;
+	}
+	
+	/* for ISOC transfers calculate start frame index */
+	if (urb->transfer_flags & USB_ISO_ASAP) { 
+		urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1): 
+								(le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
+	}	
+	urb->status = USB_ST_URB_PENDING;
+	urb->actual_length = 0;
+	
+	if (ed->state != ED_OPER)  /* link the ed into a chain if is not already */
+		ep_link (ohci, ed);
+	
+	urb->status = USB_ST_URB_PENDING; 
+	td_submit_urb (urb); /* fill the TDs and link it to the ed */
+
+	spin_unlock_irqrestore (&usb_ed_lock, flags);
+
+	return 0;	
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* deactivate all TDs and remove the private part of the URB */
+ 
+static int sohci_unlink_urb (urb_t * urb)
+{
+	unsigned long flags;
+	ohci_t * ohci;
+	DECLARE_WAITQUEUE (wait, current);
+	
+	if (!urb) /* just to be sure */ 
+		return -EINVAL;
+		
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	ohci = (ohci_t *) urb->dev->bus->hcpriv; 
+
+#ifdef DEBUG
+	urb_print (urb, "UNLINK", 1);
+#endif		  
+	
+	if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) {
+		usb_dec_dev_use(urb->dev);
+		return rh_unlink_urb (urb); /* a request to the virtual root hub */
+	}
+
+	if (urb->hcpriv) { 
+		/* URB active? */
+		if (urb->status == USB_ST_URB_PENDING && !ohci->disabled) {
+			urb_priv_t  * urb_priv = urb->hcpriv;
+			urb_priv->state = URB_DEL; 
+
+			/* we want to delete the TDs of an URB from an ed 
+			 * request the deletion, it will be handled at the
+			 * next USB-frame */
+			
+			spin_lock_irqsave (&usb_ed_lock, flags);
+			ep_rm_ed (urb->dev, urb_priv->ed);
+			urb_priv->ed->state |= ED_URB_DEL;
+			spin_unlock_irqrestore (&usb_ed_lock, flags);
+			if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+				usb_dec_dev_use (urb->dev);	
+				add_wait_queue (&op_wakeup, &wait);
+				current->state = TASK_UNINTERRUPTIBLE;
+				if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
+					err("unlink URB timeout!");
+				remove_wait_queue (&op_wakeup, &wait); 
+				urb->status = -ENOENT;
+			} else {
+				/* usb_dec_dev_use done in dl_del_list() */
+				urb->status = -EINPROGRESS;
+			}
+		} else {
+			usb_dec_dev_use (urb->dev);	
+			urb_rm_priv (urb);
+			if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) {
+				urb->complete (urb); 
+				urb->status = 0;	
+			} else 
+				urb->status = -ENOENT;
+		}	
+	}	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* allocate private data space for a usb device */
+
+static int sohci_alloc_dev (struct usb_device *usb_dev)
+{
+	struct ohci_device * dev;
+
+	dev = kmalloc (sizeof (*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+		
+	memset (dev, 0, sizeof (*dev));
+
+	usb_dev->hcpriv = dev;
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* free private data space of usb device */
+  
+static int sohci_free_dev (struct usb_device * usb_dev)
+{
+	unsigned long flags;
+	int i, cnt = 0;
+	ed_t * ed;
+	DECLARE_WAITQUEUE (wait, current);
+	struct ohci_device * dev = usb_to_ohci (usb_dev);
+	ohci_t * ohci = usb_dev->bus->hcpriv;
+	
+	if (!dev) return 0;
+	
+	if (usb_dev->devnum >= 0) {
+	
+		/* delete all TDs of all EDs */
+		spin_lock_irqsave (&usb_ed_lock, flags);	
+		for(i = 0; i < NUM_EDS; i++) {
+  			ed = &(dev->ed[i]);
+  			if (ed->state != ED_NEW) {
+  				if (ed->state == ED_OPER) ep_unlink (ohci, ed);
+  				ep_rm_ed (usb_dev, ed);
+  				ed->state = ED_DEL;
+  				cnt++;
+  			}
+  		}
+  		spin_unlock_irqrestore (&usb_ed_lock, flags);
+  		
+		if (cnt > 0) {
+			add_wait_queue (&op_wakeup, &wait);
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout (HZ / 10);
+			remove_wait_queue (&op_wakeup, &wait);
+		}
+	}
+	kfree (dev);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev) 
+{
+	ohci_t * ohci = usb_dev->bus->hcpriv;
+	
+	return le16_to_cpu (ohci->hcca.frame_no);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_operations sohci_device_operations = {
+	sohci_alloc_dev,
+	sohci_free_dev,
+	sohci_get_current_frame_number,
+	sohci_submit_urb,
+	sohci_unlink_urb
+};
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/  
+		
+/* search for the right branch to insert an interrupt ed into the int tree 
+ * do some load ballancing;
+ * returns the branch and 
+ * sets the interval to interval = 2^integer (ld (interval)) */
+
+static int ep_int_ballance (ohci_t * ohci, int interval, int load)
+{
+	int i, branch = 0;
+   
+	/* search for the least loaded interrupt endpoint branch of all 32 branches */
+	for (i = 0; i < 32; i++) 
+		if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i]) branch = i; 
+  
+	branch = branch % interval;
+	for (i = branch; i < 32; i += interval) ohci->ohci_int_load [i] += load;
+
+	return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*  2^int( ld (inter)) */
+
+static int ep_2_n_interval (int inter)
+{	
+	int i;
+	for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++); 
+	return 1 << i;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree 
+ * in order to process it sequentially the indexes of the branches have to be mapped 
+ * the mapping reverses the bits of a word of num_bits length */
+ 
+static int ep_rev (int num_bits, int word)
+{
+	int i, wout = 0;
+
+	for (i = 0; i < num_bits; i++) wout |= (((word >> i) & 1) << (num_bits - i - 1));
+	return wout;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t * ohci, ed_t * edi)
+{	 
+	int int_branch;
+	int i;
+	int inter;
+	int interval;
+	int load;
+	__u32 * ed_p;
+	volatile ed_t * ed = edi;
+	
+	ed->state = ED_OPER;
+	
+	switch (ed->type) {
+	case CTRL:
+		ed->hwNextED = 0;
+		if (ohci->ed_controltail == NULL) {
+			writel (virt_to_bus (ed), &ohci->regs->ed_controlhead);
+		} else {
+			ohci->ed_controltail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+		}
+		ed->ed_prev = ohci->ed_controltail;
+		ohci->ed_controltail = edi;	  
+		break;
+		
+	case BULK:  
+		ed->hwNextED = 0;
+		if (ohci->ed_bulktail == NULL) {
+			writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead);
+		} else {
+			ohci->ed_bulktail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+		}
+		ed->ed_prev = ohci->ed_bulktail;
+		ohci->ed_bulktail = edi;	  
+		break;
+		
+	case INT:
+		load = ed->int_load;
+		interval = ep_2_n_interval (ed->int_period);
+		ed->int_interval = interval;
+		int_branch = ep_int_ballance (ohci, interval, load);
+		ed->int_branch = int_branch;
+		
+		for (i = 0; i < ep_rev (6, interval); i += inter) {
+			inter = 1;
+			for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]); 
+				(*ed_p != 0) && (((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval >= interval); 
+				ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
+					inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+			ed->hwNextED = *ed_p; 
+			*ed_p = cpu_to_le32 (virt_to_bus (ed));
+		}
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "LINK_INT");
+#endif
+		break;
+		
+	case ISO:
+		ed->hwNextED = 0;
+		ed->int_interval = 1;
+		if (ohci->ed_isotail != NULL) {
+			ohci->ed_isotail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
+			ed->ed_prev = ohci->ed_isotail;
+		} else {
+			for ( i = 0; i < 32; i += inter) {
+				inter = 1;
+				for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
+					*ed_p != 0; 
+					ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) 
+						inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+				*ed_p = cpu_to_le32 (virt_to_bus (ed));	
+			}	
+			ed->ed_prev = NULL;
+		}	
+		ohci->ed_isotail = edi;  
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "LINK_ISO");
+#endif
+		break;
+	}	 	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains. 
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t * ohci, ed_t * ed) 
+{
+	int int_branch;
+	int i;
+	int inter;
+	int interval;
+	__u32 * ed_p;
+	 
+    
+	switch (ed->type) {
+	case CTRL: 
+		if (ed->ed_prev == NULL) {
+			writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if(ohci->ed_controltail == ed) {
+			ohci->ed_controltail = ed->ed_prev;
+		} else {
+			((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+      
+	case BULK: 
+		if (ed->ed_prev == NULL) {
+			writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_bulktail == ed) {
+			ohci->ed_bulktail = ed->ed_prev;
+		} else {
+			((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+      
+    case INT: 
+      	int_branch = ed->int_branch;
+		interval = ed->int_interval;
+
+		for (i = 0; i < ep_rev (6, interval); i += inter) {
+			for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]), inter = 1; 
+				(*ed_p != 0) && (*ed_p != ed->hwNextED); 
+				ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED), 
+				inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval)) {				
+					if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
+			  			*ed_p = ed->hwNextED;		
+			  			break;
+			  		}
+			  }
+		}
+		for (i = int_branch; i < 32; i += interval)
+		    ohci->ohci_int_load[i] -= ed->int_load;
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "UNLINK_INT");
+#endif
+		break;
+		
+    case ISO:
+    	if (ohci->ed_isotail == ed)
+				ohci->ed_isotail = ed->ed_prev;
+		if (ed->hwNextED != 0) 
+				((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+				
+		if (ed->ed_prev != NULL) {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		} else {
+			for (i = 0; i < 32; i += inter) {
+				inter = 1;
+				for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); 
+					*ed_p != 0; 
+					ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) {
+						inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
+						if(((ed_t *) bus_to_virt (le32_to_cpup (ed_p))) == ed) {
+			  				*ed_p = ed->hwNextED;		
+			  				break;
+			  			}
+			  	}
+			}	
+		}	
+#ifdef DEBUG
+		ep_print_int_eds (ohci, "UNLINK_ISO");
+#endif
+		break;
+    }
+    ed->state = ED_UNLINK;
+    return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless  so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+ 
+static ed_t * ep_add_ed (struct usb_device * usb_dev, unsigned int pipe, int interval, int load)
+{
+   	ohci_t * ohci = usb_dev->bus->hcpriv;
+	td_t * td;
+	ed_t * ed_ret;
+	volatile ed_t * ed; 
+ 	
+ 	
+	spin_lock (&usb_ed_lock);
+
+	ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | 
+			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
+
+	if((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) 
+		return NULL; /* pending delete request */
+	
+	if (ed->state == ED_NEW) {
+		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
+  		OHCI_ALLOC (td, sizeof (*td)); /* dummy td; end of td list for ed */
+  		if(!td) return NULL; /* out of memory */
+		ed->hwTailP = cpu_to_le32 (virt_to_bus (td));
+		ed->hwHeadP = ed->hwTailP;	
+		ed->state = ED_UNLINK;
+		ed->type = usb_pipetype (pipe);
+		usb_to_ohci (usb_dev)->ed_cnt++;
+	}
+
+	ohci->dev[usb_pipedevice (pipe)] = usb_dev;
+	
+	ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
+			| usb_pipeendpoint (pipe) << 7
+			| (usb_pipeisoc (pipe)? 0x8000: 0)
+			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
+			| usb_pipeslow (pipe) << 13
+			| usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
+  
+  	if (ed->type == INT && ed->state == ED_UNLINK) {
+  		ed->int_period = interval;
+  		ed->int_load = load;
+  	}
+  	
+	spin_unlock(&usb_ed_lock);
+	return ed_ret; 
+}
+
+/*-------------------------------------------------------------------------*/
+ 
+/* request the removal of an endpoint
+ * put the ep on the rm_list and request a stop of the bulk or ctrl list 
+ * real removal is done at the next start of frame (SOF) hardware interrupt */
+ 
+static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
+{    
+	unsigned int frame;
+	ohci_t * ohci = usb_dev->bus->hcpriv;
+
+	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) return;
+	
+	ed->hwINFO  |=  cpu_to_le32 (OHCI_ED_SKIP);
+	
+	writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+	writel (OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
+
+	frame = le16_to_cpu (ohci->hcca.frame_no) & 0x1;
+	ed->ed_rm_list = ohci->ed_rm_list[frame];
+	ohci->ed_rm_list[frame] = ed;
+
+	switch (ed->type) {
+		case CTRL: /* stop CTRL list */
+			writel (ohci->hc_control &= ~OHCI_CTRL_CLE, &ohci->regs->control); 
+  			break;
+		case BULK: /* stop BULK list */
+			writel (ohci->hc_control &= ~OHCI_CTRL_BLE, &ohci->regs->control); 
+			break;
+	}
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* prepare a TD */
+
+static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int index)
+{
+	volatile td_t  * td, * td_pt;
+	urb_priv_t * urb_priv = urb->hcpriv;
+
+	if (index >= urb_priv->length) {
+		err("internal OHCI error: TD index > length");
+		return;
+	}
+	
+	td_pt = urb_priv->td [index];
+	/* fill the old dummy TD */
+	td = urb_priv->td [index] = (td_t *) bus_to_virt (le32_to_cpup (&urb_priv->ed->hwTailP) & 0xfffffff0);
+	td->ed = urb_priv->ed;
+	td->index = index;
+	td->urb = urb; 
+	td->hwINFO = cpu_to_le32 (info);
+	if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) {
+		td->hwCBP = cpu_to_le32 (((!data || !len)? 
+								0 : virt_to_bus (data)) & 0xFFFFF000);
+		td->ed->last_iso = info & 0xffff;
+	} else {
+		td->hwCBP = cpu_to_le32 (((!data || !len)? 0 : virt_to_bus (data))); 
+	}			
+	td->hwBE = cpu_to_le32 ((!data || !len )? 0: virt_to_bus (data + len - 1));
+	td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt));
+	td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000);
+	td_pt->hwNextTD = 0;
+	td->ed->hwTailP = td->hwNextTD;
+   
+	td->next_dl_td = NULL; //td_pt;
+}
+
+/*-------------------------------------------------------------------------*/
+ 
+/* prepare all TDs of a transfer */
+
+static void td_submit_urb (urb_t * urb)
+{ 
+	urb_priv_t * urb_priv = urb->hcpriv;
+	ohci_t * ohci = (ohci_t *) urb->dev->bus->hcpriv;
+	void * ctrl = urb->setup_packet;
+	void * data = urb->transfer_buffer;
+	int data_len = urb->transfer_buffer_length;
+	int cnt = 0; 
+	__u32 info = 0;
+  	unsigned int toggle = 0;
+
+	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+  	if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) {
+  		toggle = TD_T_TOGGLE;
+	} else {
+  		toggle = TD_T_DATA0;
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1);
+	}
+	
+	urb_priv->td_cnt = 0;
+	
+	switch (usb_pipetype (urb->pipe)) {
+		case PIPE_BULK:
+			info = usb_pipeout (urb->pipe)? 
+				TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+			while(data_len > 4096) {		
+				td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, 4096, urb, cnt);
+				data += 4096; data_len -= 4096; cnt++;
+			}
+			info = usb_pipeout (urb->pipe)?
+				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+			td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
+			cnt++;
+			writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+			break;
+
+		case PIPE_INTERRUPT:
+			info = usb_pipeout (urb->pipe)? 
+				TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
+			td_fill (info, data, data_len, urb, cnt++);
+			break;
+
+		case PIPE_CONTROL:
+			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+			td_fill (info, ctrl, 8, urb, cnt++); 
+			if (data_len > 0) {  
+				info = usb_pipeout (urb->pipe)? 
+					TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+				td_fill (info, data, data_len, urb, cnt++);  
+			} 
+			info = usb_pipeout (urb->pipe)? 
+ 				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+			td_fill (info, NULL, 0, urb, cnt++);
+			writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+			break;
+
+		case PIPE_ISOCHRONOUS:
+			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
+				td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 
+ 					(__u8 *) data + urb->iso_frame_desc[cnt].offset, 
+					urb->iso_frame_desc[cnt].length, urb, cnt); 
+			}
+			break;
+	} 
+	if (urb_priv->length != cnt) 
+		dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+	__u32 tdINFO, tdBE, tdCBP;
+ 	__u16 tdPSW;
+ 	urb_t * urb = td->urb;
+ 	urb_priv_t * urb_priv = urb->hcpriv;
+	int dlen = 0;
+	int cc = 0;
+	
+	tdINFO = le32_to_cpup (&td->hwINFO);
+  	tdBE   = le32_to_cpup (&td->hwBE);
+  	tdCBP  = le32_to_cpup (&td->hwCBP);
+
+
+  	if (tdINFO & TD_ISO) {
+ 		tdPSW = le16_to_cpu (td->hwPSW[0]);
+ 		cc = (tdPSW >> 12) & 0xF;
+		if (cc < 0xE)  {
+			if (usb_pipeout(urb->pipe)) {
+				dlen = urb->iso_frame_desc[td->index].length;
+			} else {
+				dlen = tdPSW & 0x3ff;
+			}
+			urb->actual_length += dlen;
+			urb->iso_frame_desc[td->index].actual_length = dlen;
+			if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
+				cc = TD_CC_NOERROR;
+					 
+			urb->iso_frame_desc[td->index].status = cc_to_error[cc];
+		}
+	} else { /* BULK, INT, CONTROL DATA */
+		if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL && 
+				((td->index == 0) || (td->index == urb_priv->length - 1)))) {
+ 			if (tdBE != 0) {
+ 				if (td->hwCBP == 0)
+					urb->actual_length = bus_to_virt (tdBE) - urb->transfer_buffer + 1;
+  				else
+					urb->actual_length = bus_to_virt (tdCBP) - urb->transfer_buffer;
+			}
+  		}
+  	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+ 
+static td_t * dl_reverse_done_list (ohci_t * ohci)
+{
+	__u32 td_list_hc;
+	td_t * td_rev = NULL;
+	td_t * td_list = NULL;
+  	urb_priv_t * urb_priv = NULL;
+  	unsigned long flags;
+  	
+  	spin_lock_irqsave (&usb_ed_lock, flags);
+  	
+	td_list_hc = le32_to_cpup (&ohci->hcca.done_head) & 0xfffffff0;
+	ohci->hcca.done_head = 0;
+	
+	while (td_list_hc) {		
+		td_list = (td_t *) bus_to_virt (td_list_hc);
+
+		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
+			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
+			dbg(" USB-error/status: %x : %p", 
+					TD_CC_GET (le32_to_cpup (&td_list->hwINFO)), td_list);
+			if (td_list->ed->hwHeadP & cpu_to_le32 (0x1)) {
+				if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
+					td_list->ed->hwHeadP = 
+						(urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
+									(td_list->ed->hwHeadP & cpu_to_le32 (0x2));
+					urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
+				} else 
+					td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
+			}
+		}
+
+		td_list->next_dl_td = td_rev;	
+		td_rev = td_list;
+		td_list_hc = le32_to_cpup (&td_list->hwNextTD) & 0xfffffff0;	
+	}	
+	spin_unlock_irqrestore (&usb_ed_lock, flags);
+	return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* there are some pending requests to remove 
+ * - some of the eds (if ed->state & ED_DEL (set by sohci_free_dev)
+ * - some URBs/TDs if urb_priv->state == URB_DEL */
+ 
+static void dl_del_list (ohci_t  * ohci, unsigned int frame)
+{
+	unsigned long flags;
+	ed_t * ed;
+	__u32 edINFO;
+	__u32 tdINFO;
+	td_t * td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
+	__u32 * td_p;
+	int ctrl = 0, bulk = 0;
+
+	spin_lock_irqsave (&usb_ed_lock, flags);
+	for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
+
+   	 	tdTailP = bus_to_virt (le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
+		tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0);
+		edINFO = le32_to_cpup (&ed->hwINFO);
+		td_p = &ed->hwHeadP;
+
+		for (td = tdHeadP; td != tdTailP; td = td_next) { 
+			urb_t * urb = td->urb;
+			urb_priv_t * urb_priv = td->urb->hcpriv;
+			
+			td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0);
+			if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
+				tdINFO = le32_to_cpup (&td->hwINFO);
+				if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td);
+				*td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3));
+				if(++ (urb_priv->td_cnt) == urb_priv->length) 
+					urb_rm_priv (urb);
+					if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+						usb_dec_dev_use (urb->dev);
+						urb->status = -ECONNRESET;
+						urb->complete (urb); 
+					} else {	
+						wake_up (&op_wakeup);
+					}
+			} else {
+				td_p = &td->hwNextTD;
+			}
+			
+		}
+		if (ed->state & ED_DEL) { /* set by sohci_free_dev */
+			struct ohci_device * dev = usb_to_ohci (ohci->dev[edINFO & 0x7F]);
+   	 		OHCI_FREE (tdTailP); /* free dummy td */
+   	 		ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); 
+   	 		ed->state = ED_NEW; 
+   	 		/* if all eds are removed wake up sohci_free_dev */
+   	 		if (!--dev->ed_cnt)
+				wake_up (&op_wakeup);
+   	 	}
+   	 	else {
+   	 		ed->state &= ~ED_URB_DEL;
+   	 		ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP);
+   	 	}
+   	 	
+   	 	if ((ed->type & 3) == CTRL) ctrl |= 1;
+  		if ((ed->type & 3) == BULK) bulk |= 1;  
+   	}
+   	
+   	if (ctrl) writel (0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
+   	if (bulk) writel (0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
+	if (!ohci->ed_rm_list[!frame]) { 		/* enable CTRL and BULK lists */ 
+  		ohci->hc_control |= OHCI_CTRL_CLE | OHCI_CTRL_BLE;
+  		writel (ohci->hc_control, &ohci->regs->control);   
+	}
+   	ohci->ed_rm_list[frame] = NULL;
+
+   	spin_unlock_irqrestore (&usb_ed_lock, flags);
+}
+
+
+  		
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+
+static void dl_done_list (ohci_t * ohci, td_t * td_list)
+{
+  	td_t * td_list_next = NULL;
+	ed_t * ed;
+	int cc = 0;
+	urb_t * urb;
+	urb_priv_t * urb_priv;
+ 	__u32 tdINFO, edHeadP, edTailP;
+ 	
+ 	unsigned long flags;
+ 	
+  	while (td_list) {
+   		td_list_next = td_list->next_dl_td;
+   		
+  		urb = td_list->urb;
+  		urb_priv = urb->hcpriv;
+  		tdINFO = le32_to_cpup (&td_list->hwINFO);
+  		
+   		ed = td_list->ed;
+   		
+   		dl_transfer_length(td_list);
+ 			
+  		/* error code of transfer */
+  		cc = TD_CC_GET (tdINFO);
+  		if( cc == TD_CC_STALL) usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+  		
+  		if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
+						cc = TD_CC_NOERROR;
+  		if (++(urb_priv->td_cnt) == urb_priv->length) {
+  			if (urb_priv->state != URB_DEL && !(ed->state & ED_DEL) && ed->state != ED_NEW) { 
+  				urb->status = cc_to_error[cc];
+  				sohci_return_urb (urb);
+  			} else {
+  				urb_rm_priv (urb);
+  			}
+  		}
+  		
+  		spin_lock_irqsave (&usb_ed_lock, flags);
+  		if (ed->state != ED_NEW) { 
+  			edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0;
+  			edTailP = le32_to_cpup (&ed->hwTailP);
+
+     		if((edHeadP == edTailP) && (ed->state == ED_OPER)) 
+     			ep_unlink (ohci, ed); /* unlink eds if they are not busy */
+     		
+     	}	
+     	spin_unlock_irqrestore (&usb_ed_lock, flags);
+     	
+    	td_list = td_list_next;
+  	}  
+}
+
+
+
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub 
+ *-------------------------------------------------------------------------*/
+ 
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+	0x12,       /*  __u8  bLength; */
+	0x01,       /*  __u8  bDescriptorType; Device */
+	0x10,	    /*  __u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*  __u8  bDeviceSubClass; */
+	0x00,       /*  __u8  bDeviceProtocol; */
+	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,       /*  __u16 idVendor; */
+	0x00,
+	0x00,       /*  __u16 idProduct; */
+ 	0x00,
+	0x00,       /*  __u16 bcdDevice; */
+ 	0x00,
+	0x00,       /*  __u8  iManufacturer; */
+	0x02,       /*  __u8  iProduct; */
+	0x01,       /*  __u8  iSerialNumber; */
+	0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,       /*  __u8  bLength; */
+	0x02,       /*  __u8  bDescriptorType; Configuration */
+	0x19,       /*  __u16 wTotalLength; */
+	0x00,
+	0x01,       /*  __u8  bNumInterfaces; */
+	0x01,       /*  __u8  bConfigurationValue; */
+	0x00,       /*  __u8  iConfiguration; */
+	0x40,       /*  __u8  bmAttributes; 
+                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,       /*  __u8  MaxPower; */
+      
+	/* interface */	  
+	0x09,       /*  __u8  if_bLength; */
+	0x04,       /*  __u8  if_bDescriptorType; Interface */
+	0x00,       /*  __u8  if_bInterfaceNumber; */
+	0x00,       /*  __u8  if_bAlternateSetting; */
+	0x01,       /*  __u8  if_bNumEndpoints; */
+	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,       /*  __u8  if_bInterfaceSubClass; */
+	0x00,       /*  __u8  if_bInterfaceProtocol; */
+	0x00,       /*  __u8  if_iInterface; */
+     
+	/* endpoint */
+	0x07,       /*  __u8  ep_bLength; */
+	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+ 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+ 	0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 	0x00,
+	0xff        /*  __u8  ep_bInterval; 255 ms */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */ 
+ 
+static int rh_send_irq (ohci_t * ohci, void * rh_data, int rh_len)
+{
+	int num_ports;
+	int i;
+	int ret;
+	int len;
+
+	__u8 data[8];
+
+	num_ports = readl (&ohci->regs->roothub.a) & RH_A_NDP; 
+	*(__u8 *) data = (readl (&ohci->regs->roothub.status) & (RH_HS_LPSC | RH_HS_OCIC))
+		? 1: 0;
+	ret = *(__u8 *) data;
+
+	for ( i = 0; i < num_ports; i++) {
+		*(__u8 *) (data + (i + 1) / 8) |= 
+			((readl (&ohci->regs->roothub.portstatus[i]) &
+				(RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
+			    ? 1: 0) << ((i + 1) % 8);
+		ret += *(__u8 *) (data + (i + 1) / 8);
+	}
+	len = i/8 + 1;
+  
+	if (ret > 0) { 
+		memcpy (rh_data, data, min (len, min (rh_len, sizeof(data))));
+		return len;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+ 
+static void rh_int_timer_do (unsigned long ptr)
+{
+	int len; 
+
+	urb_t * urb = (urb_t *) ptr;
+	ohci_t * ohci = urb->dev->bus->hcpriv;
+
+	if (ohci->disabled)
+	    return;
+	
+	if(ohci->rh.send) { 
+		len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
+		if (len > 0) {
+			urb->actual_length = len;
+#ifdef DEBUG
+			urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
+#endif
+			if (urb->complete) urb->complete (urb);
+		}
+	}	
+	rh_init_int_timer (urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Root Hub INTs are polled by this timer */
+
+static int rh_init_int_timer (urb_t * urb) 
+{
+	ohci_t * ohci = urb->dev->bus->hcpriv;
+
+	ohci->rh.interval = urb->interval;
+	init_timer (&ohci->rh.rh_int_timer);
+	ohci->rh.rh_int_timer.function = rh_int_timer_do;
+	ohci->rh.rh_int_timer.data = (unsigned long) urb;
+	ohci->rh.rh_int_timer.expires = 
+			jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
+	add_timer (&ohci->rh.rh_int_timer);
+	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x) 			len = (x); break
+#define WR_RH_STAT(x) 		writel((x), &ohci->regs->roothub.status)
+#define WR_RH_PORTSTAT(x) 	writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
+#define RD_RH_STAT		readl(&ohci->regs->roothub.status)
+#define RD_RH_PORTSTAT		readl(&ohci->regs->roothub.portstatus[wIndex-1])
+
+/* request to virtual root hub */
+
+static int rh_submit_urb (urb_t * urb)
+{
+	struct usb_device * usb_dev = urb->dev;
+	ohci_t * ohci = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	devrequest * cmd = (devrequest *) urb->setup_packet;
+	void * data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = TD_CC_NOERROR;
+	
+	__u32 datab[4];
+	__u8  * data_buf = (__u8 *) datab;
+	
+ 	__u16 bmRType_bReq;
+	__u16 wValue; 
+	__u16 wIndex;
+	__u16 wLength;
+
+	if (usb_pipeint(pipe)) {
+	
+		ohci->rh.urb =  urb;
+		ohci->rh.send = 1;
+		ohci->rh.interval = urb->interval;
+		rh_init_int_timer(urb);
+		urb->status = cc_to_error [TD_CC_NOERROR];
+		
+		return 0;
+	}
+
+	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+	wValue        = le16_to_cpu (cmd->value);
+	wIndex        = le16_to_cpu (cmd->index);
+	wLength       = le16_to_cpu (cmd->length);
+
+	dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq,
+		bmRType_bReq, wLength);
+
+	switch (bmRType_bReq) {
+	/* Request Destination:
+	   without flags: Device, 
+	   RH_INTERFACE: interface, 
+	   RH_ENDPOINT: endpoint,
+	   RH_CLASS means HUB here, 
+	   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+	*/
+  
+		case RH_GET_STATUS: 				 		
+				*(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
+		case RH_GET_STATUS | RH_INTERFACE: 	 		
+				*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
+		case RH_GET_STATUS | RH_ENDPOINT:	 		
+				*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);   
+		case RH_GET_STATUS | RH_CLASS: 				
+				*(__u32 *) data_buf = cpu_to_le32 (
+					RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+				OK (4);
+		case RH_GET_STATUS | RH_OTHER | RH_CLASS: 	
+				*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
+
+		case RH_CLEAR_FEATURE | RH_ENDPOINT:  
+			switch (wValue) {
+				case (RH_ENDPOINT_STALL): OK (0);
+			}
+			break;
+
+		case RH_CLEAR_FEATURE | RH_CLASS:
+			switch (wValue) {
+				case RH_C_HUB_LOCAL_POWER:
+					OK(0);
+				case (RH_C_HUB_OVER_CURRENT): 
+						WR_RH_STAT(RH_HS_OCIC); OK (0);
+			}
+			break;
+		
+		case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+			switch (wValue) {
+				case (RH_PORT_ENABLE): 			
+						WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+				case (RH_PORT_SUSPEND):			
+						WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+				case (RH_PORT_POWER):			
+						WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+				case (RH_C_PORT_CONNECTION):	
+						WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+				case (RH_C_PORT_ENABLE):		
+						WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+				case (RH_C_PORT_SUSPEND):		
+						WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+				case (RH_C_PORT_OVER_CURRENT):	
+						WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+				case (RH_C_PORT_RESET):			
+						WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); 
+			}
+			break;
+ 
+		case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+			switch (wValue) {
+				case (RH_PORT_SUSPEND):			
+						WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); 
+				case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+						if (RD_RH_PORTSTAT & RH_PS_CCS)
+						    WR_RH_PORTSTAT (RH_PS_PRS);
+						OK (0);
+				case (RH_PORT_POWER):			
+						WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); 
+				case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+						if (RD_RH_PORTSTAT & RH_PS_CCS)
+						    WR_RH_PORTSTAT (RH_PS_PES );
+						OK (0);
+			}
+			break;
+
+		case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0);
+
+		case RH_GET_DESCRIPTOR:
+			switch ((wValue & 0xff00) >> 8) {
+				case (0x01): /* device descriptor */
+					len = min (leni, min (sizeof (root_hub_dev_des), wLength));
+					data_buf = root_hub_dev_des; OK(len);
+				case (0x02): /* configuration descriptor */
+					len = min (leni, min (sizeof (root_hub_config_des), wLength));
+					data_buf = root_hub_config_des; OK(len);
+				case (0x03): /* string descriptors */
+					len = usb_root_hub_string (wValue & 0xff,
+						(int)(long) ohci->regs, "OHCI",
+						data, wLength);
+					if (len > 0) {
+						data_buf = data;
+						OK (min (leni, len));
+					}
+					// else fallthrough
+				default: 
+					status = TD_CC_STALL;
+			}
+			break;
+		
+		case RH_GET_DESCRIPTOR | RH_CLASS:
+		    {
+			    __u32 temp = readl (&ohci->regs->roothub.a);
+
+			    data_buf [0] = 9;		// min length;
+			    data_buf [1] = 0x29;
+			    data_buf [2] = temp & RH_A_NDP;
+			    data_buf [3] = 0;
+			    if (temp & RH_A_PSM) 	/* per-port power switching? */
+				data_buf [3] |= 0x1;
+			    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
+				data_buf [3] |= 0x10;
+			    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
+				data_buf [3] |= 0x8;
+
+			    datab [1] = 0;
+			    data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+			    temp = readl (&ohci->regs->roothub.b);
+			    data_buf [7] = temp & RH_B_DR;
+			    if (data_buf [2] < 7) {
+				data_buf [8] = 0xff;
+			    } else {
+				data_buf [0] += 2;
+				data_buf [8] = (temp & RH_B_DR) >> 8;
+				data_buf [10] = data_buf [9] = 0xff;
+			    }
+				
+			    len = min (leni, min (data_buf [0], wLength));
+			    OK (len);
+			}
+ 
+		case RH_GET_CONFIGURATION: 	*(__u8 *) data_buf = 0x01; OK (1);
+
+		case RH_SET_CONFIGURATION: 	WR_RH_STAT (0x10000); OK (0);
+
+		default: 
+			dbg ("unsupported root hub command");
+			status = TD_CC_STALL;
+	}
+	
+#ifdef	DEBUG
+	ohci_dump_roothub (ohci, 0);
+#endif
+
+	len = min(len, leni);
+	if (data != data_buf)
+	    memcpy (data, data_buf, len);
+  	urb->actual_length = len;
+	urb->status = cc_to_error [status];
+	
+#ifdef DEBUG
+	urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
+#endif
+
+	if (urb->complete) urb->complete (urb);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_unlink_urb (urb_t * urb)
+{
+	ohci_t * ohci = urb->dev->bus->hcpriv;
+ 
+	if (ohci->rh.urb == urb) {
+		ohci->rh.send = 0;
+		del_timer (&ohci->rh.rh_int_timer);
+	}
+	return 0;
+}
+ 
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t * ohci)
+{
+	int timeout = 30;
+	int smm_timeout = 50; /* 0,5 sec */
+	 	
+	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+		dbg("USB HC TakeOver from SMM");
+		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+			wait_ms (10);
+			if (--smm_timeout == 0) {
+				err("USB HC TakeOver failed!");
+				return -1;
+			}
+		}
+	}	
+		
+	/* Disable HC interrupts */
+	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+	dbg("USB HC reset_hc: %x ;", readl (&ohci->regs->control));
+
+  	/* Reset USB (needed by some controllers) */
+	writel (0, &ohci->regs->control);
+      	
+	/* HC Reset requires max 10 ms delay */
+	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+		if (--timeout == 0) {
+			err("USB HC reset timed out!");
+			return -1;
+		}	
+		udelay (1);
+	}	 
+	ohci->disabled = 0;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts 
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+  	__u32 mask;
+  	unsigned int fminterval;
+  	struct usb_device  * usb_dev;
+	struct ohci_device * dev;
+	
+	/* Tell the controller where the control and bulk lists are
+	 * The lists are empty now. */
+	 
+	writel (0, &ohci->regs->ed_controlhead);
+	writel (0, &ohci->regs->ed_bulkhead);
+	
+	writel (virt_to_bus (&ohci->hcca), &ohci->regs->hcca); /* a reset clears this */
+   
+  	fminterval = 0x2edf;
+	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+	fminterval |= ((((fminterval - 210) * 6) / 7) << 16); 
+	writel (fminterval, &ohci->regs->fminterval);	
+	writel (0x628, &ohci->regs->lsthresh);
+
+ 	/* start controller operations */
+ 	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ 	writel (ohci->hc_control, &ohci->regs->control);
+ 
+	/* Choose the interrupts we care about now, others later on demand */
+	mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+	writel (mask, &ohci->regs->intrenable);
+	writel (mask, &ohci->regs->intrstatus);
+
+#ifdef	OHCI_USE_NPS
+	writel ((readl(&ohci->regs->roothub.a) | RH_A_NPS) & ~RH_A_PSM,
+		&ohci->regs->roothub.a);
+	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+	// POTPGT delay is bits 24-31, in 2 ms units.
+	mdelay ((readl(&ohci->regs->roothub.a) >> 23) & 0x1fe);
+#endif	/* OHCI_USE_NPS */
+ 
+	/* connect the virtual root hub */
+	ohci->rh.devnum = 0;
+	usb_dev = usb_alloc_dev (NULL, ohci->bus);
+	if (!usb_dev)
+	    return -ENOMEM;
+
+	dev = usb_to_ohci (usb_dev);
+	ohci->bus->root_hub = usb_dev;
+	usb_connect (usb_dev);
+	if (usb_new_device (usb_dev) != 0) {
+		usb_free_dev (usb_dev); 
+		return -ENODEV;
+	}
+	
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* an interrupt happens */
+
+static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r)
+{
+	ohci_t * ohci = __ohci;
+	struct ohci_regs * regs = ohci->regs;
+ 	int ints; 
+
+	if ((ohci->hcca.done_head != 0) && !(le32_to_cpup (&ohci->hcca.done_head) & 0x01)) {
+		ints =  OHCI_INTR_WDH;
+	} else { 
+ 		if ((ints = (readl (&regs->intrstatus) & readl (&regs->intrenable))) == 0)
+			return;
+	} 
+
+	// dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+
+	if (ints & OHCI_INTR_UE) {
+		ohci->disabled++;
+		err ("OHCI Unrecoverable Error, controller disabled");
+		// e.g. due to PCI Master/Target Abort
+	}
+  
+	if (ints & OHCI_INTR_WDH) {
+		writel (OHCI_INTR_WDH, &regs->intrdisable);	
+		dl_done_list (ohci, dl_reverse_done_list (ohci));
+		writel (OHCI_INTR_WDH, &regs->intrenable); 
+	}
+  
+	if (ints & OHCI_INTR_SO) {
+		dbg("USB Schedule overrun");
+		writel (OHCI_INTR_SO, &regs->intrenable); 	 
+	}
+
+	if (ints & OHCI_INTR_SF) { 
+		unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1;
+		writel (OHCI_INTR_SF, &regs->intrdisable);	
+		if (ohci->ed_rm_list[!frame] != NULL) {
+			dl_del_list (ohci, !frame);
+		}
+		if (ohci->ed_rm_list[frame] != NULL) writel (OHCI_INTR_SF, &regs->intrenable);	
+	}
+	writel (ints, &regs->intrstatus);
+	writel (OHCI_INTR_MIE, &regs->intrenable);	
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* reinitialize after controller reset */
+
+static void hc_reinit_ohci (ohci_t *ohci)
+{
+	int i;
+
+	/* for load balancing of the interrupt branches */
+	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
+	for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0;
+	
+	ohci->ed_rm_list [0] = NULL;
+	ohci->ed_rm_list [1] = NULL;
+
+	/* end of control and bulk lists */	 
+	ohci->ed_isotail     = NULL;
+	ohci->ed_controltail = NULL;
+	ohci->ed_bulktail    = NULL;
+} 
+
+/* allocate OHCI */
+
+static ohci_t * hc_alloc_ohci (void * mem_base)
+{
+	ohci_t * ohci;
+	struct usb_bus * bus;
+
+	ohci = (ohci_t *) __get_free_pages (GFP_KERNEL, 1);
+	if (!ohci)
+		return NULL;
+		
+	memset (ohci, 0, sizeof (ohci_t));
+	
+	ohci->irq = -1;
+	ohci->regs = mem_base;   
+
+	bus = usb_alloc_bus (&sohci_device_operations);
+	if (!bus) {
+		free_pages ((unsigned long) ohci, 1);
+		return NULL;
+	}
+
+	ohci->bus = bus;
+	bus->hcpriv = (void *) ohci;
+ 
+	return ohci;
+} 
+
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t * ohci)
+{	
+	dbg("USB HC release ohci");
+
+	/* disconnect all devices */    
+	if (ohci->bus->root_hub)
+		usb_disconnect (&ohci->bus->root_hub);
+
+	hc_reset (ohci);
+	writel (OHCI_USB_RESET, &ohci->regs->control);
+	wait_ms (10);
+	
+	if (ohci->irq >= 0) {
+		free_irq (ohci->irq, ohci);
+		ohci->irq = -1;
+	}
+
+	usb_deregister_bus (ohci->bus);
+	usb_free_bus (ohci->bus);
+    
+	/* unmap the IO address space */
+	iounmap (ohci->regs);
+       
+	free_pages ((unsigned long) ohci, 1);	
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Increment the module usage count, start the control thread and
+ * return success. */
+ 
+static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
+{
+	ohci_t * ohci;
+	char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+	sprintf(buf, "%d", irq);
+#else
+	bufp = __irq_itoa(irq);
+#endif
+	printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
+		(unsigned long)	mem_base, bufp);
+    
+	ohci = hc_alloc_ohci (mem_base);
+	if (!ohci) {
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
+
+	if (hc_reset (ohci) < 0) {
+		hc_release_ohci (ohci);
+		return -ENODEV;
+	}
+
+	writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
+	wait_ms (10);
+	usb_register_bus (ohci->bus);
+	
+	if (request_irq (irq, hc_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
+		struct pm_dev *pmdev;
+
+		ohci->irq = irq;     
+		hc_start (ohci);
+
+		pmdev = pm_register (PM_PCI_DEV,
+				     PM_PCI_ID(dev),
+				     handle_pm_event);
+		if (pmdev)
+			pmdev->data = ohci;
+
+#ifdef	DEBUG
+		ohci_dump (ohci, 1);
+#endif
+
+		return 0;
+ 	}	
+ 	err("request interrupt %d failed", irq);
+	hc_release_ohci (ohci);
+	return -EBUSY;
+}
+
+/*-------------------------------------------------------------------------*/
+ 
+static int hc_start_ohci (struct pci_dev * dev)
+{
+	unsigned long mem_base;
+	u16 cmd;
+
+	if (pci_enable_device(dev) < 0)
+		return -ENODEV;
+	
+	pci_set_master (dev);
+	mem_base = pci_resource_start(dev, 0);
+	mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
+
+	/* Some Mac firmware will switch memory response off */
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
+
+	if (!mem_base) {
+		err("Error mapping OHCI memory");
+		return -EFAULT;
+	}
+	return hc_found_ohci (dev, dev->irq, (void *) mem_base);
+} 
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PMAC_PBOOK
+
+/* On Powerbooks, put the controller into suspend mode when going
+ * to sleep, and do a resume when waking up. */
+
+static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
+{
+	struct list_head * ohci_l;
+	ohci_t * ohci;
+       
+	for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
+	ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
+
+		switch (when) {
+		case PBOOK_SLEEP_NOW:
+			disable_irq (ohci->irq);
+			writel (ohci->hc_control = OHCI_USB_SUSPEND, &ohci->regs->control);
+			wait_ms (10);
+			break;
+		case PBOOK_WAKE:
+ 			writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);
+			wait_ms (20);
+			ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+			writel (ohci->hc_control, &ohci->regs->control);
+			enable_irq (ohci->irq);
+			break;
+		}
+	}
+	return PBOOK_SLEEP_OK;
+}
+
+static struct pmu_sleep_notifier ohci_sleep_notifier = {
+       ohci_sleep_notify, SLEEP_LEVEL_MISC,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+/*-------------------------------------------------------------------------*/
+
+static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	ohci_t * ohci = (ohci_t*) dev->data;
+	int temp = 0;
+
+	if (ohci) {
+		switch (rqst) {
+		case PM_SUSPEND:
+			/* act as if usb suspend can always be used */
+			dbg("USB suspend: %p", ohci->regs);
+			ohci->hc_control = OHCI_USB_SUSPEND;
+			writel (ohci->hc_control, &ohci->regs->control);
+			wait_ms (10);
+			break;
+
+		case PM_RESUME:
+			/* did we suspend, or were we powered off? */
+			ohci->hc_control = readl (&ohci->regs->control);
+			temp = ohci->hc_control & OHCI_CTRL_HCFS;
+			switch (temp) {
+
+			case OHCI_USB_RESET:	// lost power
+				dbg("USB reset: %p", ohci->regs);
+				ohci->disabled = 1;
+				if (ohci->bus->root_hub)
+					usb_disconnect (&ohci->bus->root_hub);
+				hc_reinit_ohci (ohci);
+				if ((temp = hc_reset (ohci)) < 0
+					|| (temp = hc_start (ohci)) < 0) {
+					ohci->disabled = 1;
+					err ("can't restart, %d", temp);
+				}
+				dbg ("reset done");
+				break;
+
+			case OHCI_USB_SUSPEND:	// host wakeup
+			case OHCI_USB_RESUME:	// remote wakeup
+				dbg("USB resume: %p", ohci->regs);
+				ohci->hc_control = OHCI_USB_RESUME;
+				writel (ohci->hc_control, &ohci->regs->control);
+				wait_ms (20);
+
+				ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+				writel (ohci->hc_control, &ohci->regs->control);
+				break;
+
+			default:
+				warn ("odd PM_RESUME");
+			}
+			break;
+		}
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310
+ 
+int ohci_hcd_init (void) 
+{
+	int ret = -ENODEV;
+	struct pci_dev * dev = NULL;
+ 
+	while ((dev = pci_find_class (PCI_CLASS_SERIAL_USB_OHCI, dev))) { 
+		if (hc_start_ohci(dev) >= 0) ret = 0;
+	}
+    
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier (&ohci_sleep_notifier);
+#endif  
+    return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef MODULE
+int init_module (void) 
+{
+	return ohci_hcd_init ();
+}
+
+/*-------------------------------------------------------------------------*/
+
+void cleanup_module (void) 
+{	
+	ohci_t * ohci;
+	
+	pm_unregister_all (handle_pm_event);
+
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_unregister_sleep_notifier (&ohci_sleep_notifier);
+#endif  
+
+	while (!list_empty (&ohci_hcd_list)) {
+		ohci = list_entry (ohci_hcd_list.next, ohci_t, ohci_hcd_list);
+		list_del (&ohci->ohci_hcd_list);
+		INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+		hc_release_ohci (ohci);
+	}		
+}
+#endif //MODULE
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-ohci.h linux.18p8/drivers/usb/usb-ohci.h
--- linux.vanilla/drivers/usb/usb-ohci.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usb-ohci.h	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,450 @@
+ /*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ * 
+ *(C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * 
+ * usb-ohci.h
+ * 
+ */
+
+ 
+#define MODSTR "ohci: "
+
+
+static int cc_to_error[16] = { 
+
+/* mapping of the OHCI CC status to error codes */ 
+#ifdef USB_ST_CRC /* status codes */
+	/* No  Error  */               USB_ST_NOERROR,
+	/* CRC Error  */               USB_ST_CRC,
+	/* Bit Stuff  */               USB_ST_BITSTUFF,
+	/* Data Togg  */               USB_ST_CRC,
+	/* Stall      */               USB_ST_STALL,
+	/* DevNotResp */               USB_ST_NORESPONSE,
+	/* PIDCheck   */               USB_ST_BITSTUFF,
+	/* UnExpPID   */               USB_ST_BITSTUFF,
+	/* DataOver   */               USB_ST_DATAOVERRUN,
+	/* DataUnder  */               USB_ST_DATAUNDERRUN,
+	/* reservd    */               USB_ST_NORESPONSE,
+	/* reservd    */               USB_ST_NORESPONSE,
+	/* BufferOver */               USB_ST_BUFFEROVERRUN,
+	/* BuffUnder  */               USB_ST_BUFFERUNDERRUN,
+	/* Not Access */               USB_ST_NORESPONSE,
+	/* Not Access */               USB_ST_NORESPONSE 
+};
+
+#else  /* error codes */
+	/* No  Error  */               0,
+	/* CRC Error  */               -EILSEQ,
+	/* Bit Stuff  */               -EPROTO,
+	/* Data Togg  */               -EILSEQ,
+	/* Stall      */               -EPIPE,
+	/* DevNotResp */               -ETIMEDOUT,
+	/* PIDCheck   */               -EPROTO,
+	/* UnExpPID   */               -EPROTO,
+	/* DataOver   */               -EOVERFLOW,
+	/* DataUnder  */               -EREMOTEIO,
+	/* reservd    */               -ETIMEDOUT,
+	/* reservd    */               -ETIMEDOUT,
+	/* BufferOver */               -ECOMM,
+	/* BuffUnder  */               -ECOMM,
+	/* Not Access */               -ETIMEDOUT,
+	/* Not Access */               -ETIMEDOUT  
+};
+#define USB_ST_URB_PENDING		-EINPROGRESS
+#endif
+
+ 
+
+struct ed;
+struct td;
+/* for ED and TD structures */
+
+/* ED States */
+
+#define ED_NEW 		0x00
+#define ED_UNLINK 	0x01
+#define ED_OPER		0x02
+#define ED_DEL		0x04
+#define ED_URB_DEL  0x08
+
+/* usb_ohci_ed */
+typedef struct ed {
+	__u32 hwINFO;       
+	__u32 hwTailP;
+	__u32 hwHeadP;
+	__u32 hwNextED;
+
+	struct ed * ed_prev;  
+	__u8 int_period;
+	__u8 int_branch;
+	__u8 int_load; 
+	__u8 int_interval;
+	__u8 state;
+	__u8 type; 
+	__u16 last_iso;
+    struct ed * ed_rm_list;
+   
+} ed_t;
+
+ 
+/* TD info field */
+#define TD_CC       0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC       0x0C000000
+#define TD_T        0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R        0x00040000
+#define TD_DI       0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO		0x00010000
+#define TD_DEL      0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED     0x0F
+
+
+#define MAXPSW 1
+
+typedef struct td { 
+	__u32 hwINFO;
+  	__u32 hwCBP;		/* Current Buffer Pointer */
+  	__u32 hwNextTD;		/* Next TD Pointer */
+  	__u32 hwBE;		/* Memory Buffer End Pointer */
+  	__u16 hwPSW[MAXPSW];
+
+  	__u8 type;
+  	__u8 index;
+  	struct ed * ed;
+  	struct td * next_dl_td;
+  	urb_t * urb;
+} td_t;
+
+
+/* TD types */
+#define BULK		0x03
+#define INT			0x01
+#define CTRL		0x02
+#define ISO			0x00
+ 
+#define SEND            0x01
+#define ST_ADDR         0x02
+#define ADD_LEN         0x04
+#define DEL             0x08
+
+
+#define OHCI_ED_SKIP	(1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+ 
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+    __u32	int_table[NUM_INTS];	/* Interrupt ED table */
+	__u16	frame_no;		/* current frame number */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u32	done_head;		/* info returned for an interrupt */
+	u8		reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+  
+/*
+ * Maximum number of root hub ports.  
+ */
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.  You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	donehead;
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus[MAX_ROOT_PORTS];
+	} roothub;
+} __attribute((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR	(3 << 0)	/* control/bulk service ratio */
+#define OHCI_CTRL_PLE	(1 << 2)	/* periodic list enable */
+#define OHCI_CTRL_IE	(1 << 3)	/* isochronous enable */
+#define OHCI_CTRL_CLE	(1 << 4)	/* control list enable */
+#define OHCI_CTRL_BLE	(1 << 5)	/* bulk list enable */
+#define OHCI_CTRL_HCFS	(3 << 6)	/* host controller functional state */
+#define OHCI_CTRL_IR	(1 << 8)	/* interrupt routing */
+#define OHCI_CTRL_RWC	(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE	(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#	define OHCI_USB_RESET	(0 << 6)
+#	define OHCI_USB_RESUME	(1 << 6)
+#	define OHCI_USB_OPER	(2 << 6)
+#	define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_CLF  	(1 << 1)	/* control list filled */
+#define OHCI_BLF  	(1 << 2)	/* bulk list filled */
+#define OHCI_OCR  	(1 << 3)	/* ownership change request */
+#define OHCI_SOC  	(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+#define OHCI_INTR_WDH	(1 << 1)	/* writeback of done_head */
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_OC	(1 << 30)	/* ownership change */
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+	int devnum; /* Address of Root Hub endpoint */ 
+	void * urb;
+	void * int_addr;
+	int send;
+	int interval;
+	struct timer_list rh_int_timer;
+};
+
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+ 
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14  
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+ 
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS            0x00000001   	/* current connect status */
+#define RH_PS_PES            0x00000002   	/* port enable status*/
+#define RH_PS_PSS            0x00000004   	/* port suspend status */
+#define RH_PS_POCI           0x00000008   	/* port over current indicator */
+#define RH_PS_PRS            0x00000010  	/* port reset status */
+#define RH_PS_PPS            0x00000100   	/* port power status */
+#define RH_PS_LSDA           0x00000200    	/* low speed device attached */
+#define RH_PS_CSC            0x00010000 	/* connect status change */
+#define RH_PS_PESC           0x00020000   	/* port enable status change */
+#define RH_PS_PSSC           0x00040000    	/* port suspend status change */
+#define RH_PS_OCIC           0x00080000    	/* over current indicator change */
+#define RH_PS_PRSC           0x00100000   	/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS	     0x00000001		/* local power status */
+#define RH_HS_OCI	     0x00000002		/* over current indicator */
+#define RH_HS_DRWE	     0x00008000		/* device remote wakeup enable */
+#define RH_HS_LPSC	     0x00010000		/* local power status change */
+#define RH_HS_OCIC	     0x00020000		/* over current indicator change */
+#define RH_HS_CRWE	     0x80000000		/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff		/* device removable flags */
+#define RH_B_PPCM	0xffff0000		/* port power control mask */
+
+/* roothub.a masks */
+#define	RH_A_NDP	(0xff << 0)		/* number of downstream ports */
+#define	RH_A_PSM	(1 << 8)		/* power switching mode */
+#define	RH_A_NPS	(1 << 9)		/* no power switching */
+#define	RH_A_DT		(1 << 10)		/* device type (mbz) */
+#define	RH_A_OCPM	(1 << 11)		/* over current protection mode */
+#define	RH_A_NOCP	(1 << 12)		/* no over current protection */
+#define	RH_A_POTPGT	(0xff << 24)		/* power on to power good time */
+
+#define min(a,b) (((a)<(b))?(a):(b))  
+ 
+
+/* urb */
+typedef struct 
+{
+	ed_t * ed;
+	__u16 length;	// number of tds associated with this request
+	__u16 td_cnt;	// number of tds already serviced
+	int   state;
+	void * wait;
+	td_t * td[0];	// list pointer to all corresponding TDs associated with this request
+
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+	struct ohci_hcca hcca;		/* hcca */
+
+	int irq;
+	int disabled;			/* e.g. got a UE, we're hung */
+
+	struct ohci_regs * regs;	/* OHCI controller's memory */
+	struct list_head ohci_hcd_list;	/* list of all ohci_hcd */
+
+	struct ohci * next; 		// chain of uhci device contexts
+	struct list_head urb_list; 	// list of all pending urbs
+	spinlock_t urb_list_lock; 	// lock to keep consistency 
+  
+	int ohci_int_load[32];		/* load of the 32 Interrupt Chains (for load balancing)*/
+	ed_t * ed_rm_list[2];     /* lists of all endpoints to be removed */
+	ed_t * ed_bulktail;       /* last endpoint of bulk list */
+	ed_t * ed_controltail;    /* last endpoint of control list */
+ 	ed_t * ed_isotail;        /* last endpoint of iso list */
+	int intrstatus;
+	__u32 hc_control;		/* copy of the hc control reg */
+	struct usb_bus * bus;    
+	struct usb_device * dev[128];
+	struct virt_root_hub rh;
+} ohci_t;
+
+
+#define NUM_TDS	0		/* num of preallocated transfer descriptors */
+#define NUM_EDS 32		/* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+	ed_t 	ed[NUM_EDS];
+	int ed_cnt;
+	void  * wait;
+};
+
+// #define ohci_to_usb(ohci)	((ohci)->usb)
+#define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned int pipe, int interval, int load);
+static void ep_rm_ed(struct usb_device * usb_dev, ed_t * ed);
+/* td */
+static void td_fill(unsigned int info, void * data, int len, urb_t * urb, int index);
+static void td_submit_urb(urb_t * urb);
+/* root hub */
+static int rh_submit_urb(urb_t * urb);
+static int rh_unlink_urb(urb_t * urb);
+static int rh_init_int_timer(urb_t * urb);
+
+#ifdef DEBUG
+#define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d: %4x\n", -- __ohci_free_cnt, (unsigned int) x)
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); printk("OHCI ALLO: %d: %4x\n", ++ __ohci_free_cnt,(unsigned int) x)
+static int __ohci_free_cnt = 0;
+#else
+#define OHCI_FREE(x) kfree(x) 
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) 
+#endif
+ 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-storage-debug.h linux.18p8/drivers/usb/usb-storage-debug.h
--- linux.vanilla/drivers/usb/usb-storage-debug.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usb-storage-debug.h	Fri Sep  1 14:42:41 2000
@@ -0,0 +1,89 @@
+#include <linux/config.h>
+#ifdef CONFIG_USB_STORAGE_DEBUG
+
+/* Debug output for Driver for USB mass storage (scsi-like) devices
+ * 
+ * (C) Michael Gee (michael@linuxspecific.com) 1999
+ *
+ */
+
+void us_show_command(Scsi_Cmnd *srb)
+{
+	char *what = NULL;
+
+	switch (srb->cmnd[0]) {
+	case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
+	case REZERO_UNIT: what = "REZERO_UNIT"; break;
+	case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
+	case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
+	case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
+	case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
+	case READ_6: what = "READ_6"; break;
+	case WRITE_6: what = "WRITE_6"; break;
+	case SEEK_6: what = "SEEK_6"; break;
+	case READ_REVERSE: what = "READ_REVERSE"; break;
+	case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
+	case SPACE: what = "SPACE"; break;
+	case INQUIRY: what = "INQUIRY"; break;
+	case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
+	case MODE_SELECT: what = "MODE_SELECT"; break;
+	case RESERVE: what = "RESERVE"; break;
+	case RELEASE: what = "RELEASE"; break;
+	case COPY: what = "COPY"; break;
+	case ERASE: what = "ERASE"; break;
+	case MODE_SENSE: what = "MODE_SENSE"; break;
+	case START_STOP: what = "START_STOP"; break;
+	case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
+	case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
+	case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
+	case SET_WINDOW: what = "SET_WINDOW"; break;
+	case READ_CAPACITY: what = "READ_CAPACITY"; break;
+	case READ_10: what = "READ_10"; break;
+	case WRITE_10: what = "WRITE_10"; break;
+	case SEEK_10: what = "SEEK_10"; break;
+	case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
+	case VERIFY: what = "VERIFY"; break;
+	case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
+	case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
+	case SEARCH_LOW: what = "SEARCH_LOW"; break;
+	case SET_LIMITS: what = "SET_LIMITS"; break;
+	case READ_POSITION: what = "READ_POSITION"; break;
+	case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
+	case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
+	case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
+	case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
+	case COMPARE: what = "COMPARE"; break;
+	case COPY_VERIFY: what = "COPY_VERIFY"; break;
+	case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
+	case READ_BUFFER: what = "READ_BUFFER"; break;
+	case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
+	case READ_LONG: what = "READ_LONG"; break;
+	case WRITE_LONG: what = "WRITE_LONG"; break;
+	case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
+	case WRITE_SAME: what = "WRITE_SAME"; break;
+	case READ_TOC: what = "READ_TOC"; break;
+	case LOG_SELECT: what = "LOG_SELECT"; break;
+	case LOG_SENSE: what = "LOG_SENSE"; break;
+	case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
+	case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
+	case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break;
+	case READ_12: what = "READ_12"; break;
+	case WRITE_12: what = "WRITE_12"; break;
+	case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
+	case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
+	case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
+	case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
+	case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
+	case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
+	case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
+	default: break;
+	}
+	printk(KERN_DEBUG USB_STORAGE
+	       "Command %s (%d bytes)\n", what, srb->cmd_len);
+	printk(KERN_DEBUG USB_STORAGE 
+	       "  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	       srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], 
+	       srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
+}
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-storage.c linux.18p8/drivers/usb/usb-storage.c
--- linux.vanilla/drivers/usb/usb-storage.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usb-storage.c	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,2200 @@
+/* Driver for USB Mass Storage compliant devices
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * Current development and maintainance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * This driver is based on the 'USB Mass Storage Class' document. This
+ * describes in detail the protocol used to communicate with such
+ * devices.  Clearly, the designers had SCSI and ATAPI commands in
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/proc_fs.h>
+#include <linux/usb.h>
+
+#include <linux/blk.h>
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+#include "../scsi/sd.h"
+
+#include "usb-storage.h"
+#include "usb-storage-debug.h"
+
+/* direction table -- this indicates the direction of the data
+ * transfer for each command code -- a 1 indicates input
+ */
+/* FIXME: we need to use the new direction indicators in the Scsi_Cmnd
+ * structure, not this table.  First we need to evaluate if it's being set
+ * correctly for us, though
+ */
+unsigned char us_direction[256/8] = {
+	0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 
+	0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+ * Per device data
+ */
+
+static int my_host_number;
+
+struct us_data;
+
+typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);
+typedef int (*trans_reset)(struct us_data*);
+typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
+
+/* we allocate one of these for every device that we remember */
+struct us_data {
+	struct us_data		*next;		 /* next device */
+
+	/* the device we're working with */
+	struct semaphore	dev_semaphore;	 /* protect pusb_dev */
+	struct usb_device	*pusb_dev;	 /* this usb_device */
+
+	unsigned int		flags;		 /* from filter initially */
+
+	/* information about the device -- always good */
+	char			vendor[USB_STOR_STRING_LEN];
+	char			product[USB_STOR_STRING_LEN];
+	char			serial[USB_STOR_STRING_LEN];
+	char			*transport_name;
+	char			*protocol_name;
+	u8			subclass;
+	u8			protocol;
+
+	/* information about the device -- only good if device is attached */
+	u8			ifnum;		 /* interface number   */
+	u8			ep_in;		 /* bulk in endpoint   */
+	u8			ep_out;		 /* bulk out endpoint  */
+	struct usb_endpoint_descriptor *ep_int;	 /* interrupt endpoint */ 
+
+	/* function pointers for this device */
+	trans_cmnd		transport;	 /* transport function	   */
+	trans_reset		transport_reset; /* transport device reset */
+	proto_cmnd		proto_handler;	 /* protocol handler	   */
+
+	/* SCSI interfaces */
+	GUID(guid);				 /* unique dev id	*/
+	struct Scsi_Host	*host;		 /* our dummy host data */
+	Scsi_Host_Template	htmplt;		 /* own host template	*/
+	int			host_number;	 /* to find us		*/
+	int			host_no;	 /* allocated by scsi	*/
+	Scsi_Cmnd		*srb;		 /* current srb		*/
+	
+	/* thread information */
+	Scsi_Cmnd		*queue_srb;	 /* the single queue slot */
+	int			action;		 /* what to do		  */
+	int			pid;		 /* control thread	  */
+
+	/* interrupt info for CBI devices -- only good if attached */
+	struct semaphore	ip_waitq;	 /* for CBI interrupts	 */
+	int			ip_wanted;	 /* is an IRQ expected?	 */
+
+	/* interrupt communications data */
+	struct semaphore	irq_urb_sem;	 /* to protect irq_urb	 */
+	struct urb		*irq_urb;	 /* for USB int requests */
+	unsigned char		irqbuf[2];	 /* buffer for USB IRQ	 */
+
+	/* control and bulk communications data */
+	struct semaphore	current_urb_sem; /* to protect irq_urb	 */
+	struct urb		*current_urb;	 /* non-int USB requests */
+
+	/* mutual exclusion structures */
+	struct semaphore	notify;		 /* thread begin/end	    */
+	struct semaphore	sleeper;	 /* to sleep the thread on  */
+	struct semaphore	queue_exclusion; /* to protect data structs */
+};
+
+/*
+ * kernel thread actions
+ */
+
+#define US_ACT_COMMAND		1
+#define US_ACT_DEVICE_RESET	2
+#define US_ACT_BUS_RESET	3
+#define US_ACT_HOST_RESET	4
+#define US_ACT_EXIT		5
+
+/* The list of structures and the protective lock for them */
+static struct us_data *us_list;
+struct semaphore us_list_semaphore;
+
+static void * storage_probe(struct usb_device *dev, unsigned int ifnum);
+static void storage_disconnect(struct usb_device *dev, void *ptr);
+static struct usb_driver storage_driver = {
+	name:		"usb-storage",
+	probe:		storage_probe,
+	disconnect:	storage_disconnect,
+};
+
+struct proc_dir_entry proc_scsi_usb_scsi =
+{PROC_SCSI_USB_SCSI, 3, "usb", S_IFDIR | S_IRUGO | S_IXUGO, 2};
+
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+/* This is the completion handler which will wake us up when an URB
+ * completes.
+ */
+static void usb_stor_blocking_completion(urb_t *urb)
+{
+	api_wrapper_data *awd = (api_wrapper_data *)urb->context;
+
+	if (waitqueue_active(awd->wakeup))
+		wake_up(awd->wakeup);
+}
+
+/* This is our function to emulate usb_control_msg() but give us enough
+ * access to make aborts/resets work
+ */
+int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+			 u8 request, u8 requesttype, u16 value, u16 index, 
+			 void *data, u16 size)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAIT_QUEUE_HEAD(wqh);
+	api_wrapper_data awd;
+	int status;
+	devrequest *dr;
+
+	/* allocate the device request structure */
+	dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
+	if (!dr)
+		return -ENOMEM;
+
+	/* fill in the structure */
+	dr->requesttype = requesttype;
+	dr->request = request;
+	dr->value = cpu_to_le16(value);
+	dr->index = cpu_to_le16(index);
+	dr->length = cpu_to_le16(size);
+
+	/* set up data structures for the wakeup system */
+	awd.wakeup = &wqh;
+	awd.handler = 0;
+	init_waitqueue_head(&wqh); 	
+	add_wait_queue(&wqh, &wait);
+
+	/* lock the URB */
+	down(&(us->current_urb_sem));
+
+	/* fill the URB */
+	FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, 
+			 (unsigned char*) dr, data, size, 
+			 usb_stor_blocking_completion, &awd);
+
+	/* submit the URB */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	status = usb_submit_urb(us->current_urb);
+	if (status) {
+		/* something went wrong */
+		up(&(us->current_urb_sem));
+		remove_wait_queue(&wqh, &wait);
+		kfree(dr);
+		return status;
+	}
+
+	/* wait for the completion of the URB */
+	up(&(us->current_urb_sem));
+	if (us->current_urb->status == -EINPROGRESS)
+		schedule_timeout(10*HZ);
+	down(&(us->current_urb_sem));
+
+	/* we either timed out or got woken up -- clean up either way */
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&wqh, &wait);
+
+	/* did we time out? */
+	if (us->current_urb->status == -EINPROGRESS) {
+		US_DEBUGP("usb_stor_control_msg() timeout\n");
+		usb_unlink_urb(us->current_urb);
+		status = -ETIMEDOUT;
+	} else
+		status = us->current_urb->status;
+
+	/* return the actual length of the data transferred if no error*/
+	if (status >= 0)
+		status = us->current_urb->actual_length;
+
+	/* release the lock and return status */
+	up(&(us->current_urb_sem));
+	kfree(dr);
+  	return status;
+}
+
+/* This is our function to emulate usb_bulk_msg() but give us enough
+ * access to make aborts/resets work
+ */
+int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
+		      unsigned int len, unsigned int *act_len)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAIT_QUEUE_HEAD(wqh);
+	api_wrapper_data awd;
+	int status;
+
+	/* set up data structures for the wakeup system */
+	awd.wakeup = &wqh;
+	awd.handler = 0;
+	init_waitqueue_head(&wqh); 	
+	add_wait_queue(&wqh, &wait);
+
+	/* lock the URB */
+	down(&(us->current_urb_sem));
+
+	/* fill the URB */
+	FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,
+		      usb_stor_blocking_completion, &awd);
+
+	/* submit the URB */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	status = usb_submit_urb(us->current_urb);
+	if (status) {
+		/* something went wrong */
+		up(&(us->current_urb_sem));
+		remove_wait_queue(&wqh, &wait);
+		return status;
+	}
+
+	/* wait for the completion of the URB */
+	up(&(us->current_urb_sem));
+	if (us->current_urb->status == -EINPROGRESS)
+		schedule_timeout(10*HZ);
+	down(&(us->current_urb_sem));
+
+	/* we either timed out or got woken up -- clean up either way */
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&wqh, &wait);
+
+	/* did we time out? */
+	if (us->current_urb->status == -EINPROGRESS) {
+		US_DEBUGP("usb_stor_bulk_msg() timeout\n");
+		usb_unlink_urb(us->current_urb);
+		status = -ETIMEDOUT;
+	} else
+		status = us->current_urb->status;
+
+	/* return the actual length of the data transferred */
+	*act_len = us->current_urb->actual_length;
+
+	/* release the lock and return status */
+	up(&(us->current_urb_sem));
+	return status;
+}
+
+/*
+ * Transfer one SCSI scatter-gather buffer via bulk transfer
+ *
+ * Note that this function is necessary because we want the ability to
+ * use scatter-gather memory.  Good performance is achieved by a combination
+ * of scatter-gather and clustering (which makes each chunk bigger).
+ *
+ * Note that the lower layer will always retry when a NAK occurs, up to the
+ * timeout limit.  Thus we don't have to worry about it for individual
+ * packets.
+ */
+static int us_transfer_partial(struct us_data *us, char *buf, int length)
+{
+	int result;
+	int partial;
+	int pipe;
+
+	/* calculate the appropriate pipe information */
+	if (US_DIRECTION(us->srb->cmnd[0]))
+		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+	else
+		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+	/* transfer the data */
+	US_DEBUGP("us_transfer_partial(): xfer %d bytes\n", length);
+	result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);
+	US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",
+		  result, partial, length);
+
+	/* if we stall, we need to clear it before we go on */
+	if (result == -EPIPE) {
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		usb_clear_halt(us->pusb_dev, pipe);
+	}
+	
+	/* did we send all the data? */
+	if (partial == length) {
+		US_DEBUGP("us_transfer_partial(): transfer complete\n");
+		return US_BULK_TRANSFER_GOOD;
+	}
+
+	/* uh oh... we have an error code, so something went wrong. */
+	if (result) {
+		/* NAK - that means we've retried a few times allready */
+		if (result == -ETIMEDOUT) {
+			US_DEBUGP("us_transfer_partial(): device NAKed\n");
+			return US_BULK_TRANSFER_FAILED;
+		}
+
+		/* -ENOENT -- we canceled this transfer */
+		if (result == -ENOENT) {
+			US_DEBUGP("us_transfer_partial(): transfer aborted\n");
+			return US_BULK_TRANSFER_ABORTED;
+		}
+
+		/* the catch-all case */
+		US_DEBUGP("us_transfer_partial(): unknown error\n");
+		return US_BULK_TRANSFER_FAILED;
+	}
+
+	/* no error code, so we must have transferred some data, 
+	 * just not all of it */
+	return US_BULK_TRANSFER_SHORT;
+}
+
+/*
+ * Transfer an entire SCSI command's worth of data payload over the bulk
+ * pipe.
+ *
+ * Note that this uses us_transfer_partial to achieve it's goals -- this
+ * function simply determines if we're going to use scatter-gather or not,
+ * and acts appropriately.  For now, it also re-interprets the error codes.
+ */
+static void us_transfer(Scsi_Cmnd *srb, struct us_data* us, int dir_in)
+{
+	int i;
+	int result = -1;
+	struct scatterlist *sg;
+
+	/* are we scatter-gathering? */
+	if (srb->use_sg) {
+
+		/* loop over all the scatter gather structures and 
+		 * make the appropriate requests for each, until done
+		 */
+		sg = (struct scatterlist *) srb->request_buffer;
+		for (i = 0; i < srb->use_sg; i++) {
+			result = us_transfer_partial(us, sg[i].address, 
+						     sg[i].length);
+			if (result)
+				break;
+		}
+	}
+	else
+		/* no scatter-gather, just make the request */
+		result = us_transfer_partial(us, srb->request_buffer, 
+					     srb->request_bufflen);
+
+	/* return the result in the data structure itself */
+	srb->result = result;
+}
+
+/* Calculate the length of the data transfer (not the command) for any
+ * given SCSI command
+ */
+static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int i;
+	unsigned int total = 0;
+	struct scatterlist *sg;
+
+	/* support those devices which need the length calculated
+	 * differently 
+	 */
+	if (us->flags & US_FL_ALT_LENGTH) {
+		if (srb->cmnd[0] == INQUIRY) {
+			srb->cmnd[4] = 36;
+		}
+
+		if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE))
+			return srb->cmnd[4];
+
+		if (srb->cmnd[0] == TEST_UNIT_READY)
+			return 0;
+	}
+
+	/* Are we going to scatter gather? */
+	if (srb->use_sg) {
+		/* Add up the sizes of all the scatter-gather segments */
+		sg = (struct scatterlist *) srb->request_buffer;
+		for (i = 0; i < srb->use_sg; i++)
+			total += sg[i].length;
+
+		return total;
+	}
+	else
+		/* Just return the length of the buffer */
+		return srb->request_bufflen;
+}
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+/* Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and recieve the response.
+ */
+static void invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int need_auto_sense;
+	int result;
+
+	/* send the command to the transport layer */
+	result = us->transport(srb, us);
+
+	/* Determine if we need to auto-sense
+	 *
+	 * I normally don't use a flag like this, but it's almost impossible
+	 * to understand what's going on here if I don't.
+	 */
+	need_auto_sense = 0;
+
+	/*
+	 * If we're running the CB transport, which is incapable
+	 * of determining status on it's own, we need to auto-sense almost
+	 * every time.
+	 */
+	if (us->protocol == US_PR_CB) {
+		US_DEBUGP("-- CB transport device requiring auto-sense\n");
+		need_auto_sense = 1;
+
+		/* There are some exceptions to this.  Notably, if this is
+		 * a UFI device and the command is REQUEST_SENSE or INQUIRY,
+		 * then it is impossible to truly determine status.
+		 */
+		if (us->subclass == US_SC_UFI &&
+		    ((srb->cmnd[0] == REQUEST_SENSE) ||
+		     (srb->cmnd[0] == INQUIRY))) {
+			US_DEBUGP("** no auto-sense for a special command\n");
+			need_auto_sense = 0;
+		}
+	}
+
+	/*
+	 * If we have an error, we're going to do a REQUEST_SENSE 
+	 * automatically.  Note that we differentiate between a command
+	 * "failure" and an "error" in the transport mechanism.
+	 */
+	if (result == USB_STOR_TRANSPORT_FAILED) {
+		US_DEBUGP("-- transport indicates command failure\n");
+		need_auto_sense = 1;
+	}
+	if (result == USB_STOR_TRANSPORT_ERROR) {
+		/* FIXME: we need to invoke a transport reset here */
+		US_DEBUGP("-- transport indicates transport failure\n");
+		need_auto_sense = 0;
+		srb->result = DID_ERROR << 16;
+		return;
+	}
+
+	/*
+	 * Also, if we have a short transfer on a command that can't have
+	 * a short transfer, we're going to do this.
+	 */
+	if ((srb->result == US_BULK_TRANSFER_SHORT) &&
+	    !((srb->cmnd[0] == REQUEST_SENSE) ||
+	      (srb->cmnd[0] == INQUIRY) ||
+	      (srb->cmnd[0] == MODE_SENSE) ||
+	      (srb->cmnd[0] == LOG_SENSE) ||
+	      (srb->cmnd[0] == MODE_SENSE_10))) {
+		US_DEBUGP("-- unexpectedly short transfer\n");
+		need_auto_sense = 1;
+	}
+
+	/* Now, if we need to do the auto-sense, let's do it */
+	if (need_auto_sense) {
+		int temp_result;
+		void* old_request_buffer;
+		int old_sg;
+		int old_request_bufflen;
+		unsigned char old_cmnd[MAX_COMMAND_SIZE];
+
+		US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
+
+		/* save the old command */
+		memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
+
+		srb->cmnd[0] = REQUEST_SENSE;
+		srb->cmnd[1] = 0;
+		srb->cmnd[2] = 0;
+		srb->cmnd[3] = 0;
+		srb->cmnd[4] = 18;
+		srb->cmnd[5] = 0;
+
+		/* set the buffer length for transfer */
+		old_request_buffer = srb->request_buffer;
+		old_request_bufflen = srb->request_bufflen;
+		old_sg = srb->use_sg;
+		srb->use_sg = 0;
+		srb->request_bufflen = 18;
+		srb->request_buffer = srb->sense_buffer;
+
+		/* issue the auto-sense command */
+		temp_result = us->transport(us->srb, us);
+		if (temp_result != USB_STOR_TRANSPORT_GOOD) {
+			/* FIXME: we need to invoke a transport reset here */
+			US_DEBUGP("-- auto-sense failure\n");
+			srb->result = DID_ERROR << 16;
+			return;
+		}
+
+		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
+		US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+			  srb->sense_buffer[0],
+			  srb->sense_buffer[2] & 0xf,
+			  srb->sense_buffer[12], 
+			  srb->sense_buffer[13]);
+
+		/* set the result so the higher layers expect this data */
+		srb->result = CHECK_CONDITION;
+
+		/* we're done here, let's clean up */
+		srb->request_buffer = old_request_buffer;
+		srb->request_bufflen = old_request_bufflen;
+		srb->use_sg = old_sg;
+		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
+
+		/* If things are really okay, then let's show that */
+		if ((srb->sense_buffer[2] & 0xf) == 0x0)
+			srb->result = GOOD;
+	} else /* if (need_auto_sense) */
+		srb->result = GOOD;
+
+	/* Regardless of auto-sense, if we _know_ we have an error
+	 * condition, show that in the result code
+	 */
+	if (result == USB_STOR_TRANSPORT_FAILED)
+		srb->result = CHECK_CONDITION;
+
+	/* If we think we're good, then make sure the sense data shows it.
+	 * This is necessary because the auto-sense for some devices always
+	 * sets byte 0 == 0x70, even if there is no error
+	 */
+	if ((us->protocol == US_PR_CB) && 
+	    (result == USB_STOR_TRANSPORT_GOOD) &&
+	    ((srb->sense_buffer[2] & 0xf) == 0x0))
+		srb->sense_buffer[0] = 0x0;
+}
+
+/*
+ * Control/Bulk/Interrupt transport
+ */
+
+/* The interrupt handler for CBI devices */
+static void CBI_irq(struct urb *urb)
+{
+	struct us_data *us = (struct us_data *)urb->context;
+
+	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
+	US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
+	US_DEBUGP("-- IRQ state is %d\n", urb->status);
+
+	/* is the device removed? */
+	if (urb->status != -ENOENT) {
+		/* save the data for interpretation later */
+		US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
+			  ((unsigned char*)urb->transfer_buffer)[0], 
+			  ((unsigned char*)urb->transfer_buffer)[1]);
+
+
+		/* was this a wanted interrupt? */
+		if (us->ip_wanted) {
+			us->ip_wanted = 0;
+			up(&(us->ip_waitq));
+		} else
+			US_DEBUGP("ERROR: Unwanted interrupt received!\n");
+	} else
+		US_DEBUGP("-- device has been removed\n");
+}
+
+static int CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int result;
+
+	/* COMMAND STAGE */
+	/* let's send the command via the control pipe */
+	result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
+				      US_CBI_ADSC, 
+				      USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
+				      us->ifnum, srb->cmnd, srb->cmd_len);
+
+	/* check the return code for the command */
+	US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
+	if (result < 0) {
+		/* STALL must be cleared when they are detected */
+		if (result == -EPIPE) {
+			US_DEBUGP("-- Stall on control pipe. Clearing\n");
+			result = usb_clear_halt(us->pusb_dev,	
+						usb_sndctrlpipe(us->pusb_dev,
+								0));
+			US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		/* Uh oh... serious problem here */
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* Set up for status notification */
+	us->ip_wanted = 1;
+
+	/* DATA STAGE */
+	/* transfer the data payload for this command, if one exists*/
+	if (us_transfer_length(srb, us)) {
+		us_transfer(srb, us, US_DIRECTION(srb->cmnd[0]));
+		US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
+	}
+
+	/* STATUS STAGE */
+
+	/* go to sleep until we get this interrupt */
+	down(&(us->ip_waitq));
+	
+	/* if we were woken up by an abort instead of the actual interrupt */
+	if (us->ip_wanted) {
+		US_DEBUGP("Did not get interrupt on CBI\n");
+		us->ip_wanted = 0;
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	
+	US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", 
+		  ((unsigned char*)us->irq_urb->transfer_buffer)[0],
+		  ((unsigned char*)us->irq_urb->transfer_buffer)[1]);
+	
+	/* UFI gives us ASC and ASCQ, like a request sense
+	 *
+	 * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI
+	 * devices, so we ignore the information for those commands.  Note
+	 * that this means we could be ignoring a real error on these
+	 * commands, but that can't be helped.
+	 */
+	if (us->subclass == US_SC_UFI) {
+		if (srb->cmnd[0] == REQUEST_SENSE ||
+		    srb->cmnd[0] == INQUIRY)
+			return USB_STOR_TRANSPORT_GOOD;
+		else
+			if (((unsigned char*)us->irq_urb->transfer_buffer)[0])
+				return USB_STOR_TRANSPORT_FAILED;
+			else
+				return USB_STOR_TRANSPORT_GOOD;
+	}
+	
+	/* If not UFI, we interpret the data as a result code 
+	 * The first byte should always be a 0x0
+	 * The second byte & 0x0F should be 0x0 for good, otherwise error 
+	 */
+	if (((unsigned char*)us->irq_urb->transfer_buffer)[0]) {
+		US_DEBUGP("CBI IRQ data showed reserved bType\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	switch (((unsigned char*)us->irq_urb->transfer_buffer)[1] & 0x0F) {
+	case 0x00: 
+		return USB_STOR_TRANSPORT_GOOD;
+	case 0x01: 
+		return USB_STOR_TRANSPORT_FAILED;
+	default: 
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	US_DEBUGP("CBI_transport() reached end of function\n");
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Control/Bulk transport
+ */
+static int CB_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int result;
+
+	/* COMMAND STAGE */
+	/* let's send the command via the control pipe */
+	result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
+				      US_CBI_ADSC, 
+				      USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
+				      us->ifnum, srb->cmnd, srb->cmd_len);
+
+	/* check the return code for the command */
+	US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
+	if (result < 0) {
+		/* a stall is a fatal condition from the device */
+		if (result == -EPIPE) {
+			US_DEBUGP("-- Stall on control pipe. Clearing\n");
+			result = usb_clear_halt(us->pusb_dev, 
+						usb_sndctrlpipe(us->pusb_dev,
+								0));
+			US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		/* Uh oh... serious problem here */
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* DATA STAGE */
+	/* transfer the data payload for this command, if one exists*/
+	if (us_transfer_length(srb, us)) {
+		us_transfer(srb, us, US_DIRECTION(srb->cmnd[0]));
+		US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
+	}
+	
+	
+	/* STATUS STAGE */
+	/* NOTE: CB does not have a status stage.  Silly, I know.  So
+	 * we have to catch this at a higher level.
+	 */
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Bulk only transport
+ */
+
+/* Determine what the maximum LUN supported is */
+static int Bulk_max_lun(struct us_data *us)
+{
+	unsigned char data;
+	int result;
+	int pipe;
+
+	/* issue the command */
+	pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
+	result = usb_control_msg(us->pusb_dev, pipe,
+				 US_BULK_GET_MAX_LUN, 
+				 USB_DIR_IN | USB_TYPE_CLASS | 
+				 USB_RECIP_INTERFACE,
+				 0, us->ifnum, &data, sizeof(data), HZ);
+
+	US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
+		  result, data);
+
+	/* if we have a successful request, return the result */
+	if (!result)
+		return data;
+
+	/* if we get a STALL, clear the stall */
+	if (result == -EPIPE) {
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		usb_clear_halt(us->pusb_dev, pipe);
+	}
+
+	/* return the default -- no LUNs */
+	return 0;
+}
+
+static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+	struct bulk_cb_wrap bcb;
+	struct bulk_cs_wrap bcs;
+	int result;
+	int pipe;
+	int partial;
+	
+	/* set up the command wrapper */
+	bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb, us));
+	bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
+	bcb.Tag = srb->serial_number;
+	bcb.Lun = srb->cmnd[1] >> 5;
+	bcb.Length = srb->cmd_len;
+	
+	/* construct the pipe handle */
+	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+	
+	/* copy the command payload */
+	memset(bcb.CDB, 0, sizeof(bcb.CDB));
+	memcpy(bcb.CDB, srb->cmnd, bcb.Length);
+	
+	/* send it to out endpoint */
+	US_DEBUGP("Bulk command S 0x%x T 0x%x LUN %d L %d F %d CL %d\n",
+		  le32_to_cpu(bcb.Signature), bcb.Tag, bcb.Lun, 
+		  bcb.DataTransferLength, bcb.Flags, bcb.Length);
+	result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, 
+				   &partial);
+	US_DEBUGP("Bulk command transfer result=%d\n", result);
+	
+	/* if we stall, we need to clear it before we go on */
+	if (result == -EPIPE) {
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		usb_clear_halt(us->pusb_dev, pipe);
+	}
+	
+	/* if the command transfered well, then we go to the data stage */
+	if (result == 0) {
+		/* send/receive data payload, if there is any */
+		if (bcb.DataTransferLength) {
+			us_transfer(srb, us, bcb.Flags);
+			US_DEBUGP("Bulk data transfer result 0x%x\n", 
+				  srb->result);
+		}
+	}
+	
+	/* See flow chart on pg 15 of the Bulk Only Transport spec for
+	 * an explanation of how this code works.
+	 */
+	
+	/* construct the pipe handle */
+	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+	
+	/* get CSW for device status */
+	US_DEBUGP("Attempting to get CSW...\n");
+	result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, 
+				   &partial);
+	
+	/* did the attempt to read the CSW fail? */
+	if (result == -EPIPE) {
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		usb_clear_halt(us->pusb_dev, pipe);
+	       
+		/* get the status again */
+		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
+		result = usb_stor_bulk_msg(us, &bcs, pipe,
+					   US_BULK_CS_WRAP_LEN, &partial);
+		
+		/* if it fails again, we need a reset and return an error*/
+		if (result == -EPIPE) {
+			US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
+			usb_clear_halt(us->pusb_dev, pipe);
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+	}
+	
+	/* if we still have a failure at this point, we're in trouble */
+	US_DEBUGP("Bulk status result = %d\n", result);
+	if (result) {
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	
+	/* check bulk status */
+	US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n",
+		  le32_to_cpu(bcs.Signature), bcs.Tag, 
+		  bcs.Residue, bcs.Status);
+	if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || 
+	    bcs.Tag != bcb.Tag || 
+	    bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+		US_DEBUGP("Bulk logical error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	
+	/* based on the status code, we report good or bad */
+	switch (bcs.Status) {
+	case US_BULK_STAT_OK:
+		/* command good -- note that we could be short on data */
+		return USB_STOR_TRANSPORT_GOOD;
+
+	case US_BULK_STAT_FAIL:
+		/* command failed */
+		return USB_STOR_TRANSPORT_FAILED;
+		
+	case US_BULK_STAT_PHASE:
+		/* phase error */
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	
+	/* we should never get here, but if we do, we're in trouble */
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+/***********************************************************************
+ * Protocol routines
+ ***********************************************************************/
+
+static void ATAPI_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int old_cmnd = 0;
+
+	/* Fix some commands -- this is a form of mode translation
+	 * ATAPI devices only accept 12 byte long commands 
+	 *
+	 * NOTE: This only works because a Scsi_Cmnd struct field contains
+	 * a unsigned char cmnd[12], so we know we have storage available
+	 */
+
+	/* set command length to 12 bytes */
+	srb->cmd_len = 12;
+
+	/* determine the correct (or minimum) data length for these commands */
+	switch (srb->cmnd[0]) {
+
+		/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
+	case MODE_SENSE:
+	case MODE_SELECT:
+		/* save the command so we can tell what it was */
+		old_cmnd = srb->cmnd[0];
+
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+		srb->cmnd[8] = srb->cmnd[4];
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = 0;
+		srb->cmnd[4] = 0;
+		srb->cmnd[3] = 0;
+		srb->cmnd[2] = srb->cmnd[2];
+		srb->cmnd[1] = srb->cmnd[1];
+		srb->cmnd[0] = srb->cmnd[0] | 0x40;
+		break;
+
+		/* change READ_6/WRITE_6 to READ_10/WRITE_10, which 
+		 * are ATAPI commands */
+	case WRITE_6:
+	case READ_6:
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+		srb->cmnd[8] = srb->cmnd[4];
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = srb->cmnd[3];
+		srb->cmnd[4] = srb->cmnd[2];
+		srb->cmnd[3] = srb->cmnd[1] & 0x1F;
+		srb->cmnd[2] = 0;
+		srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+		srb->cmnd[0] = srb->cmnd[0] | 0x20;
+		break;
+	} /* end switch on cmnd[0] */
+
+	/* send the command to the transport layer */
+	invoke_transport(srb, us);
+
+	/* Fix the MODE_SENSE data if we translated the command
+	 */
+	if (old_cmnd == MODE_SENSE) {
+		unsigned char *dta = (unsigned char *)us->srb->request_buffer;
+
+		/* FIXME: we need to compress the entire data structure here
+		 */
+		dta[0] = dta[1];	/* data len */
+		dta[1] = dta[2];	/* med type */
+		dta[2] = dta[3];	/* dev-spec prm */
+		dta[3] = dta[7];	/* block desc len */
+		printk (KERN_DEBUG USB_STORAGE
+			"new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
+			dta[0], dta[1], dta[2], dta[3]);
+	}
+
+	/* Fix-up the return data from an INQUIRY command to show 
+	 * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+	 */
+	if (srb->cmnd[0] == INQUIRY) {
+		((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
+	}
+}
+
+
+static void ufi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int old_cmnd = 0;
+
+	/* fix some commands -- this is a form of mode translation
+	 * UFI devices only accept 12 byte long commands 
+	 *
+	 * NOTE: This only works because a Scsi_Cmnd struct field contains
+	 * a unsigned char cmnd[12], so we know we have storage available
+	 */
+
+	/* set command length to 12 bytes (this affects the transport layer) */
+	srb->cmd_len = 12;
+
+	/* determine the correct (or minimum) data length for these commands */
+	switch (srb->cmnd[0]) {
+
+		/* for INQUIRY, UFI devices only ever return 36 bytes */
+	case INQUIRY:
+		srb->cmnd[4] = 36;
+		break;
+
+		/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */
+	case MODE_SENSE:
+	case MODE_SELECT:
+		/* save the command so we can tell what it was */
+		old_cmnd = srb->cmnd[0];
+
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+
+		/* if we're sending data, we send all.	If getting data, 
+		 * get the minimum */
+		if (srb->cmnd[0] == MODE_SELECT)
+			srb->cmnd[8] = srb->cmnd[4];
+		else
+			srb->cmnd[8] = 8;
+
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = 0;
+		srb->cmnd[4] = 0;
+		srb->cmnd[3] = 0;
+		srb->cmnd[2] = srb->cmnd[2];
+		srb->cmnd[1] = srb->cmnd[1];
+		srb->cmnd[0] = srb->cmnd[0] | 0x40;
+		break;
+
+		/* again, for MODE_SENSE_10, we get the minimum (8) */
+	case MODE_SENSE_10:
+		srb->cmnd[7] = 0;
+		srb->cmnd[8] = 8;
+		break;
+
+		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
+	case REQUEST_SENSE:
+		srb->cmnd[4] = 18;
+		break;
+
+		/* change READ_6/WRITE_6 to READ_10/WRITE_10, which 
+		 * are UFI commands */
+	case WRITE_6:
+	case READ_6:
+		srb->cmnd[11] = 0;
+		srb->cmnd[10] = 0;
+		srb->cmnd[9] = 0;
+		srb->cmnd[8] = srb->cmnd[4];
+		srb->cmnd[7] = 0;
+		srb->cmnd[6] = 0;
+		srb->cmnd[5] = srb->cmnd[3];
+		srb->cmnd[4] = srb->cmnd[2];
+		srb->cmnd[3] = srb->cmnd[1] & 0x1F;
+		srb->cmnd[2] = 0;
+		srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+		srb->cmnd[0] = srb->cmnd[0] | 0x20;
+		break;
+	} /* end switch on cmnd[0] */
+
+	/* send the command to the transport layer */
+	invoke_transport(srb, us);
+	
+	/* Fix the MODE_SENSE data here if we had to translate the command
+	 */
+	if (old_cmnd == MODE_SENSE) {
+		unsigned char *dta = (unsigned char *)us->srb->request_buffer;
+
+		/* FIXME: we need to compress the entire data structure here
+		 */
+		dta[0] = dta[1];	/* data len */
+		dta[1] = dta[2];	/* med type */
+		dta[2] = dta[3];	/* dev-spec prm */
+		dta[3] = dta[7];	/* block desc len */
+		printk (KERN_DEBUG USB_STORAGE
+			"new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",
+			dta[0], dta[1], dta[2], dta[3]);
+	}
+
+	/* Fix-up the return data from an INQUIRY command to show 
+	 * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+	 */
+	if (srb->cmnd[0] == INQUIRY) {
+		((unsigned char *)us->srb->request_buffer)[2] |= 0x2;
+	}
+}
+
+static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+	/* This code supports devices which do not support {READ|WRITE}_6
+	 * Apparently, neither Windows or MacOS will use these commands,
+	 * so some devices do not support them
+	 */
+	if (us->flags & US_FL_MODE_XLATE) {
+
+		/* translate READ_6 to READ_10 */
+		if (srb->cmnd[0] == 0x08) {
+
+			/* get the control */
+			srb->cmnd[9] = us->srb->cmnd[5];
+
+			/* get the length */
+			srb->cmnd[8] = us->srb->cmnd[6];
+			srb->cmnd[7] = 0;
+
+			/* set the reserved area to 0 */
+			srb->cmnd[6] = 0;	    
+
+			/* get LBA */
+			srb->cmnd[5] = us->srb->cmnd[3];
+			srb->cmnd[4] = us->srb->cmnd[2];
+			srb->cmnd[3] = 0;
+			srb->cmnd[2] = 0;
+
+			/* LUN and other info in cmnd[1] can stay */
+
+			/* fix command code */
+			srb->cmnd[0] = 0x28;
+
+			US_DEBUGP("Changing READ_6 to READ_10\n");
+			US_DEBUG(us_show_command(srb));
+		}
+
+		/* translate WRITE_6 to WRITE_10 */
+		if (srb->cmnd[0] == 0x0A) {
+
+			/* get the control */
+			srb->cmnd[9] = us->srb->cmnd[5];
+
+			/* get the length */
+			srb->cmnd[8] = us->srb->cmnd[4];
+			srb->cmnd[7] = 0;
+
+			/* set the reserved area to 0 */
+			srb->cmnd[6] = 0;	    
+
+			/* get LBA */
+			srb->cmnd[5] = us->srb->cmnd[3];
+			srb->cmnd[4] = us->srb->cmnd[2];
+			srb->cmnd[3] = 0;
+			srb->cmnd[2] = 0;
+	    
+			/* LUN and other info in cmnd[1] can stay */
+
+			/* fix command code */
+			srb->cmnd[0] = 0x2A;
+
+			US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
+			US_DEBUG(us_show_command(us->srb));
+		}
+	} /* if (us->flags & US_FL_MODE_XLATE) */
+
+	/* send the command to the transport layer */
+	invoke_transport(srb, us);
+
+	/* fix the results of an INQUIRY */
+	if (srb->cmnd[0] == INQUIRY) {
+		US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n");
+		((unsigned char*)us->srb->request_buffer)[2] |= 2;
+	}
+}
+
+/***********************************************************************
+ * Reset routines
+ ***********************************************************************/
+
+/* This issues a CB[I] Reset to the device in question
+ */
+static int CB_reset(struct us_data *us)
+{
+	unsigned char cmd[12];
+	int result;
+
+	US_DEBUGP("CB_reset() called\n");
+
+	memset(cmd, 0xFF, sizeof(cmd));
+	cmd[0] = SEND_DIAGNOSTIC;
+	cmd[1] = 4;
+	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+				 US_CBI_ADSC, 
+				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 0, us->ifnum, cmd, sizeof(cmd), HZ*5);
+
+	/* long wait for reset */
+	schedule_timeout(HZ*6);
+
+	US_DEBUGP("CB_reset: clearing endpoint halt\n");
+	usb_clear_halt(us->pusb_dev, 
+		       usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	usb_clear_halt(us->pusb_dev, 
+		       usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+
+	US_DEBUGP("CB_reset done\n");
+	return 0;
+}
+
+/* FIXME: Does this work? */
+static int Bulk_reset(struct us_data *us)
+{
+	int result;
+
+	result = usb_control_msg(us->pusb_dev, 
+				 usb_sndctrlpipe(us->pusb_dev,0), 
+				 US_BULK_RESET_REQUEST, 
+				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 0, us->ifnum, NULL, 0, HZ*5);
+
+	if (result < 0)
+		US_DEBUGP("Bulk hard reset failed %d\n", result);
+
+	usb_clear_halt(us->pusb_dev, 
+		       usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	usb_clear_halt(us->pusb_dev, 
+		       usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+
+	/* long wait for reset */
+	schedule_timeout(HZ*6);
+
+	return result;
+}
+
+/***********************************************************************
+ * Host functions 
+ ***********************************************************************/
+
+static const char* us_info(struct Scsi_Host *host)
+{
+	return "SCSI emulation for USB Mass Storage devices";
+}
+
+/* detect a virtual adapter (always works) */
+static int us_detect(struct SHT *sht)
+{
+	struct us_data *us;
+	char local_name[32];
+
+	/* This is not nice at all, but how else are we to get the
+	 * data here? */
+	us = (struct us_data *)sht->proc_dir;
+
+	/* set up the name of our subdirectory under /proc/scsi/ */
+	sprintf(local_name, "usb-storage-%d", us->host_number);
+	sht->name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
+	if (!sht->name)
+		return 0;
+	strcpy((char *)sht->name, local_name);
+
+	/* we start with no /proc directory entry */
+	sht->proc_dir = &proc_scsi_usb_scsi;
+
+	/* register the host */
+	us->host = scsi_register(sht, sizeof(us));
+	if (us->host) {
+		us->host->hostdata[0] = (unsigned long)us;
+		us->host_no = us->host->host_no;
+		return 1;
+	}
+
+	/* odd... didn't register properly.  Abort and free pointers */
+	kfree(sht->name);
+	sht->name = NULL;
+
+	return 0;
+}
+
+/* Release all resources used by the virtual host
+ *
+ * NOTE: There is no contention here, because we're allready deregistered
+ * the driver and we're doing each virtual host in turn, not in parallel
+ */
+static int us_release(struct Scsi_Host *psh)
+{
+	struct us_data *us = (struct us_data *)psh->hostdata[0];
+
+	US_DEBUGP("us_release() called for host %s\n", us->htmplt.name);
+
+	/* Kill the control threads
+	 *
+	 * Enqueue the command, wake up the thread, and wait for 
+	 * notification that it's exited.
+	 */
+	US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
+	us->action = US_ACT_EXIT;
+	up(&(us->sleeper));
+	down(&(us->notify));
+	
+	/* free the data structure we were using */
+	US_DEBUGP("-- freeing private host data structure\n");
+	kfree(us->current_urb);
+	kfree(us);
+	(struct us_data*)psh->hostdata[0] = NULL;
+
+	/* we always have a successful release */
+	return 0;
+}
+
+/* run command */
+static int us_command( Scsi_Cmnd *srb )
+{
+	US_DEBUGP("Bad use of us_command\n");
+
+	return DID_BAD_TARGET << 16;
+}
+
+/* run command */
+static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
+{
+	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+	US_DEBUGP("us_queuecommand() called\n");
+	srb->host_scribble = (unsigned char *)us;
+
+	/* get exclusive access to the structures we want */
+	down(&(us->queue_exclusion));
+
+	/* enqueue the command */
+	us->queue_srb = srb;
+	srb->scsi_done = done;
+	us->action = US_ACT_COMMAND;
+
+	/* wake up the process task */
+	up(&(us->queue_exclusion));
+	up(&(us->sleeper));
+
+	return 0;
+}
+
+/***********************************************************************
+ * Error handling functions
+ ***********************************************************************/
+
+/* Command abort
+ *
+ * Note that this is really only meaningful right now for CBI transport
+ * devices which have failed to give us the command completion interrupt
+ */
+static int us_abort( Scsi_Cmnd *srb )
+{
+	struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+	US_DEBUGP("us_abort() called\n");
+
+	/* if we're stuck waiting for an IRQ, simulate it */
+	if (us->ip_wanted) {
+		US_DEBUGP("-- simulating missing IRQ\n");
+		up(&(us->ip_waitq));
+		return SUCCESS;
+	}
+
+	return FAILED;
+}
+
+/* FIXME: this doesn't do anything right now */
+static int us_bus_reset( Scsi_Cmnd *srb )
+{
+	// struct us_data *us = (struct us_data *)srb->host->hostdata[0];
+
+	printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" );
+	US_DEBUGP("Bus reset requested\n");
+	//  us->transport_reset(us);
+	return FAILED;
+}
+
+/* FIXME: This doesn't actually reset anything */
+static int us_host_reset( Scsi_Cmnd *srb )
+{
+	printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" );
+	return FAILED;
+}
+
+/***********************************************************************
+ * /proc/scsi/ functions
+ ***********************************************************************/
+
+/* we use this macro to help us write into the buffer */
+#undef SPRINTF
+#define SPRINTF(args...) \
+	do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
+
+int usb_stor_proc_info (char *buffer, char **start, off_t offset, 
+			int length, int hostno, int inout)
+{
+	struct us_data *us;
+	char *pos = buffer;
+
+	/* if someone is sending us data, just throw it away */
+	if (inout)
+		return length;
+
+	/* lock the data structures */
+	down(&us_list_semaphore);
+
+	/* find our data from hostno */
+	us = us_list;
+	while (us) {
+		if (us->host_no == hostno)
+			break;
+		us = us->next;
+	}
+
+	/* if we couldn't find it, we return an error */
+	if (!us) {
+		up(&us_list_semaphore);
+		return -ESRCH;
+	}
+	
+	/* print the controler name */
+	SPRINTF("   Host scsi%d: usb-storage\n", hostno);
+
+	/* print product, vendor, and serial number strings */
+	SPRINTF("	Vendor: %s\n", us->vendor);
+	SPRINTF("      Product: %s\n", us->product);
+	SPRINTF("Serial Number: %s\n", us->serial);
+
+	/* show the protocol and transport */
+	SPRINTF("     Protocol: %s\n", us->protocol_name);
+	SPRINTF("    Transport: %s\n", us->transport_name);
+
+	/* show the GUID of the device */
+	SPRINTF("	  GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid));
+
+	/* release our lock on the data structures */
+	up(&us_list_semaphore);
+
+	/*
+	 * Calculate start of next buffer, and return value.
+	 */
+	*start = buffer + offset;
+
+	if ((pos - buffer) < offset)
+		return (0);
+	else if ((pos - buffer - offset) < length)
+		return (pos - buffer - offset);
+	else
+		return (length);
+}
+
+/*
+ * this defines our 'host'
+ */
+
+static Scsi_Host_Template my_host_template = {
+	name:			"usb-storage",
+	proc_info:		usb_stor_proc_info,
+	info:			us_info,
+
+	detect:			us_detect,
+	release:		us_release,
+	command:		us_command,
+	queuecommand:		us_queuecommand,
+
+	eh_abort_handler:	us_abort,
+	eh_device_reset_handler:us_bus_reset,
+	eh_bus_reset_handler:	us_bus_reset,
+	eh_host_reset_handler:	us_host_reset,
+
+	can_queue:		1,
+	this_id:		-1,
+
+	sg_tablesize:		SG_ALL,
+	cmd_per_lun:		1,
+	present:		0,
+	unchecked_isa_dma:	FALSE,
+	use_clustering:		TRUE,
+	use_new_eh_code:	TRUE,
+	emulated:		TRUE
+};
+
+static unsigned char sense_notready[] = {
+	[0]	= 0x70,			    /* current error */
+	[2]	= 0x02,			    /* not ready */
+	[5]	= 0x0a,			    /* additional length */
+	[10]	= 0x04,			    /* not ready */
+	[11]	= 0x03			    /* manual intervention */
+};
+
+static int usb_stor_control_thread(void * __us)
+{
+	struct us_data *us = (struct us_data *)__us;
+	int action;
+
+	lock_kernel();
+
+	/*
+	 * This thread doesn't need any user-level access,
+	 * so get rid of all our resources..
+	 */
+	daemonize();
+
+	/* set our name for identification purposes */
+	sprintf(current->comm, "usb-storage-%d", us->host_number);
+
+	unlock_kernel();
+
+	/* signal that we've started the thread */
+	up(&(us->notify));
+
+	for(;;) {
+		US_DEBUGP("*** thread sleeping.\n");
+		down(&(us->sleeper));
+		down(&(us->queue_exclusion));
+		US_DEBUGP("*** thread awakened.\n");
+
+		/* take the command off the queue */
+		action = us->action;
+		us->action = 0;
+		us->srb = us->queue_srb;
+	
+		/* release the queue lock as fast as possible */
+		up(&(us->queue_exclusion));
+
+		switch (action) {
+		case US_ACT_COMMAND:
+			/* reject if target != 0 or if single-lun device
+			 * and LUN != 0
+			 */
+			if (us->srb->target ||
+			    ((us->flags & US_FL_SINGLE_LUN) && us->srb->lun)) {
+				US_DEBUGP("Bad device number (%d/%d)\n",
+					  us->srb->target, us->srb->lun);
+
+				us->srb->result = DID_BAD_TARGET << 16;
+
+				us->srb->scsi_done(us->srb);
+				us->srb = NULL;
+				break;
+			}
+
+			/* handle those devices which can't do a START_STOP */
+			if ((us->srb->cmnd[0] == START_STOP) &&
+			    (us->flags & US_FL_START_STOP)) {
+				us->srb->result = GOOD;
+				us->srb->scsi_done(us->srb);
+				us->srb = NULL;
+				break;
+			}
+				     
+			/* lock the device pointers */
+			down(&(us->dev_semaphore));
+
+			/* our device has gone - pretend not ready */
+			if (!us->pusb_dev) {
+				US_DEBUGP("Request is for removed device\n");
+				/* For REQUEST_SENSE, it's the data.  But
+				 * for anything else, it should look like
+				 * we auto-sensed for it.
+				 */
+				if (us->srb->cmnd[0] == REQUEST_SENSE) {
+					memcpy(us->srb->request_buffer, 
+					       sense_notready, 
+					       sizeof(sense_notready));
+					us->srb->result = GOOD;
+				} else {
+					memcpy(us->srb->sense_buffer, 
+					       sense_notready, 
+					       sizeof(sense_notready));
+					us->srb->result = CHECK_CONDITION;
+				}
+			} else { /* !us->pusb_dev */
+				/* we've got a command, let's do it! */
+				US_DEBUG(us_show_command(us->srb));
+				us->proto_handler(us->srb, us);
+			}
+
+			/* unlock the device pointers */
+			up(&(us->dev_semaphore));
+
+			/* indicate that the command is done */
+			US_DEBUGP("scsi cmd done, result=0x%x\n", 
+				  us->srb->result);
+			us->srb->scsi_done(us->srb);
+			us->srb = NULL;
+			break;
+
+		case US_ACT_DEVICE_RESET:
+			break;
+
+		case US_ACT_BUS_RESET:
+			break;
+
+		case US_ACT_HOST_RESET:
+			break;
+
+		} /* end switch on action */
+
+		/* exit if we get a signal to exit */
+		if (action == US_ACT_EXIT) {
+			US_DEBUGP("-- US_ACT_EXIT command recieved\n");
+			break;
+		}
+	} /* for (;;) */
+
+	/* notify the exit routine that we're actually exiting now */
+	up(&(us->notify));
+
+	return 0;
+}	
+
+/* This is the list of devices we recognize, along with their flag data */
+static struct us_unusual_dev us_unusual_dev_list[] = {
+	{ 0x03f0, 0x0107, 0x0200,
+	  "HP USB CD-Writer Plus", US_SC_8070, US_PR_CB, 0}, 
+	{ 0x04e6, 0x0001, 0x0200,
+	  "Matshita LS-120", US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN},
+	{ 0x04e6, 0x0002, 0x0100,
+	  "Shuttle eUSCSI Bridge", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, 
+	{ 0x04e6, 0x0006, 0x0100,
+	  "Shuttle eUSB MMC Adapter", US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN}, 
+	{ 0x057b, 0x0000, 0x0114,
+	  "Y-E Data Flashbuster-U", US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN},
+	{ 0x059b, 0x0030, 0x0100,
+	  "Iomega Zip 250", US_SC_SCSI, US_PR_BULK, US_FL_SINGLE_LUN},
+	{ 0x0693, 0x0002, 0x0100,
+	  "Hagiwara FlashGate SmartMedia", US_SC_SCSI, US_PR_BULK,
+	  US_FL_ALT_LENGTH},
+	{ 0x0781, 0x0001, 0x0200,
+	  "Sandisk ImageMate (SDDR-01)", US_SC_SCSI, US_PR_CB, 
+	  US_FL_SINGLE_LUN | US_FL_START_STOP},
+	{ 0x0781, 0x0002, 0x0009,
+	  "Sandisk Imagemate (SDDR-31)", US_SC_SCSI, US_PR_BULK, 
+	  US_FL_SINGLE_LUN | US_FL_IGNORE_SER},
+	{ 0x07af, 0x0005, 0x0100,
+	  "Microtech USB-SCSI-HD50", US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, 
+	{ 0x0000, 0x0000, 0x0,
+	  "", 0, 0, 0}
+};
+
+/* Search our ususual device list, based on vendor/product combinations
+ * to see if we can support this device.  Returns a pointer to a structure
+ * defining how we should support this device, or NULL if it's not in the
+ * list
+ */
+static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct, 
+					  u16 bcdDevice)
+{
+	struct us_unusual_dev* ptr;
+
+	US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n",
+		  idVendor, idProduct, bcdDevice);
+
+	ptr = us_unusual_dev_list;
+	while ((ptr->idVendor != 0x0000) && 
+	       !((ptr->idVendor == idVendor) && 
+		 (ptr->idProduct == idProduct) &&
+		 (ptr->bcdDevice == bcdDevice)))
+		ptr++;
+	
+	/* if the search ended because we hit the end record, we failed */
+	if (ptr->idVendor == 0x0000) {
+		US_DEBUGP("-- did not find a matching device\n");
+		return NULL;
+	}
+
+	/* otherwise, we found one! */
+	US_DEBUGP("-- found matching device: %s\n", ptr->name);
+	return ptr;
+}
+
+/* Set up the IRQ pipe and handler
+ * Note that this function assumes that all the data in the us_data
+ * strucuture is current.  This includes the ep_int field, which gives us
+ * the endpoint for the interrupt.
+ * Returns non-zero on failure, zero on success
+ */ 
+static int usb_stor_allocate_irq(struct us_data *ss)
+{
+	unsigned int pipe;
+	int maxp;
+	int result;
+
+	US_DEBUGP("Allocating IRQ for CBI transport\n");
+	
+	/* lock access to the data structure */
+	down(&(ss->irq_urb_sem));
+
+	/* allocate the URB */
+	ss->irq_urb = usb_alloc_urb(0);
+	if (!ss->irq_urb) {
+		up(&(ss->irq_urb_sem));
+		US_DEBUGP("couldn't allocate interrupt URB");
+		return 1;
+	}
+	
+	/* calculate the pipe and max packet size */
+	pipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int->bEndpointAddress & 
+			      USB_ENDPOINT_NUMBER_MASK);
+	maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
+	if (maxp > sizeof(ss->irqbuf))
+		maxp = sizeof(ss->irqbuf);
+	
+	/* fill in the URB with our data */
+	FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf, maxp, 
+		     CBI_irq, ss, ss->ep_int->bInterval); 
+	
+	/* submit the URB for processing */
+	result = usb_submit_urb(ss->irq_urb);
+	US_DEBUGP("usb_submit_urb() returns %d\n", result);
+	if (result) {
+		usb_free_urb(ss->irq_urb);
+		up(&(ss->irq_urb_sem));
+		return 2;
+	}
+
+	/* unlock the data structure and return success */
+	up(&(ss->irq_urb_sem));
+	return 0;
+}
+
+/* Probe to see if a new device is actually a SCSI device */
+static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	int i;
+	char mf[USB_STOR_STRING_LEN];		     /* manufacturer */
+	char prod[USB_STOR_STRING_LEN];		     /* product */
+	char serial[USB_STOR_STRING_LEN];	     /* serial number */
+	GUID(guid);			   /* Global Unique Identifier */
+	unsigned int flags;
+	struct us_unusual_dev *unusual_dev;
+	struct us_data *ss = NULL;
+	int result;
+
+	/* these are temporary copies -- we test on these, then put them
+	 * in the us-data structure 
+	 */
+	struct usb_endpoint_descriptor *ep_in = NULL;
+	struct usb_endpoint_descriptor *ep_out = NULL;
+	struct usb_endpoint_descriptor *ep_int = NULL;
+	u8 subclass = 0;
+	u8 protocol = 0;
+
+	/* the altsettting 0 on the interface we're probing */
+	struct usb_interface_descriptor *altsetting = 
+		&(dev->actconfig->interface[ifnum].altsetting[0]); 
+
+	/* clear the temporary strings */
+	memset(mf, 0, sizeof(mf));
+	memset(prod, 0, sizeof(prod));
+	memset(serial, 0, sizeof(serial));
+
+	/* search for this device in our unusual device list */
+	unusual_dev = us_find_dev(dev->descriptor.idVendor, 
+				  dev->descriptor.idProduct,
+				  dev->descriptor.bcdDevice);
+
+	/* 
+	 * Can we support this device, either because we know about it
+	 * from our unusual device list, or because it advertises that it's
+	 * compliant to the specification?
+	 */
+	if (!unusual_dev &&
+	    !(dev->descriptor.bDeviceClass == 0 &&
+	      altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
+	      altsetting->bInterfaceSubClass >= US_SC_MIN &&
+	      altsetting->bInterfaceSubClass <= US_SC_MAX)) {
+		/* if it's not a mass storage, we go no further */
+		return NULL;
+	}
+
+	/* At this point, we know we've got a live one */
+	US_DEBUGP("USB Mass Storage device detected\n");
+
+	/* Determine subclass and protocol, or copy from the interface */
+	if (unusual_dev) {
+		subclass = unusual_dev->useProtocol;
+		protocol = unusual_dev->useTransport;
+		flags = unusual_dev->flags;
+	} else {
+		subclass = altsetting->bInterfaceSubClass;
+		protocol = altsetting->bInterfaceProtocol;
+		flags = 0;
+	}
+	
+	/*
+	 * Find the endpoints we need
+	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
+	 * An optional interrupt is OK (necessary for CBI protocol).
+	 * We will ignore any others.
+	 */
+	for (i = 0; i < altsetting->bNumEndpoints; i++) {
+		/* is it an BULK endpoint? */
+		if ((altsetting->endpoint[i].bmAttributes & 
+		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
+			/* BULK in or out? */
+			if (altsetting->endpoint[i].bEndpointAddress & 
+			    USB_DIR_IN)
+				ep_in = &altsetting->endpoint[i];
+			else
+				ep_out = &altsetting->endpoint[i];
+		}
+
+		/* is it an interrupt endpoint? */
+		if ((altsetting->endpoint[i].bmAttributes & 
+		     USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
+			ep_int = &altsetting->endpoint[i];
+		}
+	}
+	US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n",
+		  ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0);
+
+	/* set the interface -- STALL is an acceptable response here */
+	result = usb_set_interface(dev, altsetting->bInterfaceNumber, 0);
+	US_DEBUGP("Result from usb_set_interface is %d\n", result);
+	if (result == -EPIPE) {
+		US_DEBUGP("-- clearing stall on control interface\n");
+		usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
+	} else if (result != 0) {
+		/* it's not a stall, but another error -- time to bail */
+		US_DEBUGP("-- Unknown error.  Rejecting device\n");
+		return NULL;
+	}
+
+	/* Do some basic sanity checks, and bail if we find a problem */
+	if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
+		US_DEBUGP("Sanity check failed.	 Rejecting device.\n");
+		return NULL;
+	}
+
+	/* At this point, we're committed to using the device */
+
+	/* clear the GUID and fetch the strings */
+	GUID_CLEAR(guid);
+	if (dev->descriptor.iManufacturer)
+		usb_string(dev, dev->descriptor.iManufacturer, 
+			   mf, sizeof(mf));
+	if (dev->descriptor.iProduct)
+		usb_string(dev, dev->descriptor.iProduct, 
+			   prod, sizeof(prod));
+	if (dev->descriptor.iSerialNumber && !(flags & US_FL_IGNORE_SER))
+		usb_string(dev, dev->descriptor.iSerialNumber, 
+			   serial, sizeof(serial));
+	
+	/* Create a GUID for this device */
+	if (dev->descriptor.iSerialNumber && serial[0]) {
+		/* If we have a serial number, and it's a non-NULL string */
+		make_guid(guid, dev->descriptor.idVendor, 
+			  dev->descriptor.idProduct, serial);
+	} else {
+		/* We don't have a serial number, so we use 0 */
+		make_guid(guid, dev->descriptor.idVendor, 
+			  dev->descriptor.idProduct, "0");
+	}
+
+	/* lock access to the data structures */
+	down(&us_list_semaphore);
+
+	/*
+	 * Now check if we have seen this GUID before
+	 * We're looking for a device with a matching GUID that isn't
+	 * allready on the system
+	 */
+	ss = us_list;
+	while ((ss != NULL) && 
+	       ((ss->pusb_dev) || !GUID_EQUAL(guid, ss->guid)))
+		ss = ss->next;
+
+	if (ss != NULL) {
+		/* Existing device -- re-connect */
+		US_DEBUGP("Found existing GUID " GUID_FORMAT "\n",
+			  GUID_ARGS(guid));
+
+		/* establish the connection to the new device upon reconnect */
+		ss->ifnum = ifnum;
+		ss->pusb_dev = dev;
+	
+		/* copy over the endpoint data */
+		if (ep_in)
+			ss->ep_in = ep_in->bEndpointAddress & 
+				USB_ENDPOINT_NUMBER_MASK;
+		if (ep_out)
+			ss->ep_out = ep_out->bEndpointAddress & 
+				USB_ENDPOINT_NUMBER_MASK;
+		ss->ep_int = ep_int;
+
+		/* allocate an IRQ callback if one is needed */
+		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+			return NULL;
+	} else { 
+		/* New device -- allocate memory and initialize */
+		US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
+	
+		if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data), 
+						    GFP_KERNEL)) == NULL) {
+			printk(KERN_WARNING USB_STORAGE "Out of memory\n");
+			up(&us_list_semaphore);
+			return NULL;
+		}
+		memset(ss, 0, sizeof(struct us_data));
+
+		/* allocate the URB we're going to use */
+		ss->current_urb = usb_alloc_urb(0);
+		if (!ss->current_urb) {
+			kfree(ss);
+			return NULL;
+		}
+
+		/* Initialize the mutexes only when the struct is new */
+		init_MUTEX_LOCKED(&(ss->sleeper));
+		init_MUTEX_LOCKED(&(ss->notify));
+		init_MUTEX_LOCKED(&(ss->ip_waitq));
+		init_MUTEX(&(ss->queue_exclusion));
+		init_MUTEX(&(ss->irq_urb_sem));
+		init_MUTEX(&(ss->current_urb_sem));
+		init_MUTEX(&(ss->dev_semaphore));
+
+		/* copy over the subclass and protocol data */
+		ss->subclass = subclass;
+		ss->protocol = protocol;
+		ss->flags = flags;
+
+		/* copy over the endpoint data */
+		if (ep_in)
+			ss->ep_in = ep_in->bEndpointAddress & 
+				USB_ENDPOINT_NUMBER_MASK;
+		if (ep_out)
+			ss->ep_out = ep_out->bEndpointAddress & 
+				USB_ENDPOINT_NUMBER_MASK;
+		ss->ep_int = ep_int;
+
+		/* establish the connection to the new device */
+		ss->ifnum = ifnum;
+		ss->pusb_dev = dev;
+
+		/* copy over the identifiying strings */
+		strncpy(ss->vendor, mf, USB_STOR_STRING_LEN);
+		strncpy(ss->product, prod, USB_STOR_STRING_LEN);
+		strncpy(ss->serial, serial, USB_STOR_STRING_LEN);
+		if (strlen(ss->vendor) == 0)
+			strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN);
+		if (strlen(ss->product) == 0)
+			strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN);
+		if (strlen(ss->serial) == 0)
+			strncpy(ss->serial, "None", USB_STOR_STRING_LEN);
+
+		/* copy the GUID we created before */
+		memcpy(ss->guid, guid, sizeof(guid));
+		
+		/* 
+		 * Set the handler pointers based on the protocol
+		 * Again, this data is persistant across reattachments
+		 */
+		switch (ss->protocol) {
+		case US_PR_CB:
+			ss->transport_name = "Control/Bulk";
+			ss->transport = CB_transport;
+			ss->transport_reset = CB_reset;
+			break;
+			
+		case US_PR_CBI:
+			ss->transport_name = "Control/Bulk/Interrupt";
+			ss->transport = CBI_transport;
+			ss->transport_reset = CB_reset;
+			break;
+			
+		case US_PR_BULK:
+			ss->transport_name = "Bulk";
+			ss->transport = Bulk_transport;
+			ss->transport_reset = Bulk_reset;
+			/* FIXME: for testing purposes only */
+			Bulk_max_lun(ss);
+			break;
+			
+		default:
+			ss->transport_name = "Unknown";
+			up(&us_list_semaphore);
+			kfree(ss->current_urb);
+			kfree(ss);
+			return NULL;
+			break;
+		}
+		US_DEBUGP("Transport: %s\n", ss->transport_name);
+
+		switch (ss->subclass) {
+		case US_SC_RBC:
+			ss->protocol_name = "Reduced Block Commands (RBC)";
+			ss->proto_handler = transparent_scsi_command;
+			break;
+
+		case US_SC_8020:
+			ss->protocol_name = "8020i";
+			ss->proto_handler = ATAPI_command;
+			break;
+
+		case US_SC_QIC:
+			ss->protocol_name = "QIC-157";
+			US_DEBUGP("Sorry, device not supported.	 Please\n");
+			US_DEBUGP("contact mdharm-usb@one-eyed-alien.net\n");
+			US_DEBUGP("if you see this message.\n");
+			up(&us_list_semaphore);
+			kfree(ss->current_urb);
+			kfree(ss);
+			return NULL;
+			break;
+
+		case US_SC_8070:
+			ss->protocol_name = "8070i";
+			ss->proto_handler = ATAPI_command;
+			break;
+
+		case US_SC_SCSI:
+			ss->protocol_name = "Transparent SCSI";
+			ss->proto_handler = transparent_scsi_command;
+			break;
+
+		case US_SC_UFI:
+			ss->protocol_name = "Uniform Floppy Interface (UFI)";
+			ss->proto_handler = ufi_command;
+			break;
+
+		default:
+			ss->protocol_name = "Unknown";
+			up(&us_list_semaphore);
+			kfree(ss->current_urb);
+			kfree(ss);
+			return NULL;
+			break;
+		}
+		US_DEBUGP("Protocol: %s\n", ss->protocol_name);
+
+		/* allocate an IRQ callback if one is needed */
+		if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+			return NULL;
+		
+		/*
+		 * Since this is a new device, we need to generate a scsi 
+		 * host definition, and register with the higher SCSI layers
+		 */
+
+		/* Initialize the host template based on the default one */
+		memcpy(&(ss->htmplt), &my_host_template, 
+		       sizeof(my_host_template));
+
+		/* Grab the next host number */
+		ss->host_number = my_host_number++;
+			
+		/* We abuse this pointer so we can pass the ss pointer to 
+		 * the host controler thread in us_detect.  But how else are
+		 * we to do it?
+		 */
+		(struct us_data *)ss->htmplt.proc_dir = ss; 
+		
+		/* start up our control thread */
+		ss->pid = kernel_thread(usb_stor_control_thread, ss,
+					CLONE_FS | CLONE_FILES |
+					CLONE_SIGHAND);
+		if (ss->pid < 0) {
+			printk(KERN_WARNING USB_STORAGE 
+			       "Unable to start control thread\n");
+			kfree(ss->current_urb);
+			kfree(ss);
+			return NULL;
+		}
+		
+		/* wait for the thread to start */
+		down(&(ss->notify));
+			
+		/* now register	 - our detect function will be called */
+		ss->htmplt.module = THIS_MODULE;
+		scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt));
+		
+		/* put us in the list */
+		ss->next = us_list;
+		us_list = ss;
+	}
+
+	/* release the data structure lock */
+	up(&us_list_semaphore);
+
+	printk(KERN_DEBUG 
+	       "WARNING: USB Mass Storage data integrity not assured\n");
+	printk(KERN_DEBUG 
+	       "USB Mass Storage device found at %d\n", dev->devnum);
+
+	/* return a pointer for the disconnect function */
+	return ss;
+}
+
+/* Handle a disconnect event from the USB core */
+static void storage_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct us_data *ss = ptr;
+	int result;
+
+	US_DEBUGP("storage_disconnect() called\n");
+
+	/* this is the odd case -- we disconnected but weren't using it */
+	if (!ss) {
+		US_DEBUGP("-- device was not in use\n");
+		return;
+	}
+
+	/* lock access to the device data structure */
+	down(&(ss->dev_semaphore));
+
+	/* release the IRQ, if we have one */
+	down(&(ss->irq_urb_sem));
+	if (ss->irq_urb) {
+		US_DEBUGP("-- releasing irq handle\n");
+		result = usb_unlink_urb(ss->irq_urb);
+		ss->irq_urb = NULL;
+		US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
+		usb_free_urb(ss->irq_urb);
+	}
+	up(&(ss->irq_urb_sem));
+
+	/* mark the device as gone */
+	ss->pusb_dev = NULL;
+
+	/* lock access to the device data structure */
+	up(&(ss->dev_semaphore));
+}
+
+
+/***********************************************************************
+ * Initialization and registration
+ ***********************************************************************/
+
+int __init usb_stor_init(void)
+{
+	/* initialize internal global data elements */
+	us_list = NULL;
+	init_MUTEX(&us_list_semaphore);
+	my_host_number = 0;
+
+	/* register the driver, return -1 if error */
+	if (usb_register(&storage_driver) < 0)
+		return -1;
+
+	/* we're all set */
+	printk(KERN_INFO "USB Mass Storage support registered.\n");
+	return 0;
+}
+
+void __exit usb_stor_exit(void)
+{
+	struct us_data *next;
+	
+	US_DEBUGP("usb_stor_exit() called\n");
+
+	/* Deregister the driver
+	 * This eliminates races with probes and disconnects 
+	 */
+	US_DEBUGP("-- calling usb_deregister()\n");
+	usb_deregister(&storage_driver) ;
+	
+	/* lock access to the data structures */
+	down(&us_list_semaphore);
+
+	/* While there are still virtual hosts, unregister them
+	 *
+	 * Note that the us_release() routine will destroy the local data
+	 * structure.  So we have to peel these off the top of the list
+	 * and keep updating the head pointer as we go.
+	 */
+	while (us_list) {
+		/* keep track of where the next one is */
+		next = us_list->next;
+
+		US_DEBUGP("-- calling scsi_unregister_module()\n");
+		scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt));
+
+		/* advance the list pointer */
+		us_list = next;
+	}
+	
+	/* unlock the data structures */
+	up(&us_list_semaphore);
+}
+
+module_init(usb_stor_init) ;
+module_exit(usb_stor_exit) ;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-storage.h linux.18p8/drivers/usb/usb-storage.h
--- linux.vanilla/drivers/usb/usb-storage.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usb-storage.h	Fri Sep  1 14:42:41 2000
@@ -0,0 +1,159 @@
+/* Driver for USB mass storage - include file
+ *
+ * (c) 1999 Michael Gee (michael@linuxspecific.com)
+ * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ */
+
+#include <linux/config.h>
+
+#define USB_STORAGE "usb-storage.c: "
+#define USB_STOR_STRING_LEN 32
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+void us_show_command(Scsi_Cmnd *srb);
+#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE ## x )
+#define US_DEBUGPX(x...) printk( ## x )
+#define US_DEBUG(x) x 
+#else
+#define US_DEBUGP(x...)
+#define US_DEBUGPX(x...)
+#define US_DEBUG(x)
+#endif
+
+/* bit set if input */
+extern unsigned char us_direction[256/8];
+#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
+
+/* Sub Classes */
+
+#define US_SC_RBC	0x01		/* Typically, flash devices */
+#define US_SC_8020	0x02		/* CD-ROM */
+#define US_SC_QIC	0x03		/* QIC-157 Tapes */
+#define US_SC_UFI	0x04		/* Floppy */
+#define US_SC_8070	0x05		/* Removable media */
+#define US_SC_SCSI	0x06		/* Transparent */
+#define US_SC_MIN	US_SC_RBC
+#define US_SC_MAX	US_SC_SCSI
+
+/* Protocols */
+
+#define US_PR_CBI	0x00		/* Control/Bulk/Interrupt */
+#define US_PR_CB	0x01		/* Control/Bulk w/o interrupt */
+#define US_PR_BULK	0x50		/* bulk only */
+
+/*
+ * Bulk only data structures
+ */
+
+/* command block wrapper */
+struct bulk_cb_wrap {
+	__u32	Signature;		/* contains 'USBC' */
+	__u32	Tag;			/* unique per command id */
+	__u32	DataTransferLength;	/* size of data */
+	__u8	Flags;			/* direction in bit 0 */
+	__u8	Lun;			/* LUN normally 0 */
+	__u8	Length;			/* of of the CDB */
+	__u8	CDB[16];		/* max command */
+};
+
+#define US_BULK_CB_WRAP_LEN	31
+#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */
+#define US_BULK_FLAG_IN		1
+#define US_BULK_FLAG_OUT	0
+
+/* command status wrapper */
+struct bulk_cs_wrap {
+	__u32	Signature;		/* should = 'USBS' */
+	__u32	Tag;			/* same as original command */
+	__u32	Residue;		/* amount not transferred */
+	__u8	Status;			/* see below */
+	__u8	Filler[18];
+};
+
+#define US_BULK_CS_WRAP_LEN	13
+#define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */
+#define US_BULK_STAT_OK		0
+#define US_BULK_STAT_FAIL	1
+#define US_BULK_STAT_PHASE	2
+
+/* bulk-only class specific requests */
+#define US_BULK_RESET_REQUEST	0xff
+#define US_BULK_GET_MAX_LUN	0xfe
+
+/*
+ * us_bulk_transfer() return codes
+ */
+#define US_BULK_TRANSFER_GOOD		0  /* good transfer                 */
+#define US_BULK_TRANSFER_SHORT		1  /* transfered less than expected */
+#define US_BULK_TRANSFER_FAILED		2  /* transfer died in the middle   */
+#define US_BULK_TRANSFER_ABORTED	3  /* transfer canceled             */
+
+/*
+ * Transport return codes
+ */
+
+#define USB_STOR_TRANSPORT_GOOD	   0   /* Transport good, command good	   */
+#define USB_STOR_TRANSPORT_FAILED  1   /* Transport good, command failed   */
+#define USB_STOR_TRANSPORT_ERROR   2   /* Transport bad (i.e. device dead) */
+#define USB_STOR_TRANSPORT_ABORTED 3   /* Transport aborted                */
+
+/*
+ * CBI accept device specific command
+ */
+
+#define US_CBI_ADSC		0
+
+/* 
+ * GUID definitions
+ */
+
+#define GUID(x) __u32 x[3]
+#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2])
+#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0;
+#define GUID_NONE(x) (!x[0] && !x[1] && !x[2])
+#define GUID_FORMAT "%08x%08x%08x"
+#define GUID_ARGS(x) x[0], x[1], x[2]
+
+static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial)
+{
+	pg[0] = (vendor << 16) | product;
+	pg[1] = pg[2] = 0;
+	while (*serial) {
+		pg[1] <<= 4;
+		pg[1] |= pg[2] >> 28;
+		pg[2] <<= 4;
+		if (*serial >= 'a')
+			*serial -= 'a' - 'A';
+		pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0'
+			: *serial - 'A' + 10;
+		serial++;
+	}
+}
+
+/*
+ * Unusual device list definitions 
+ */
+
+struct us_unusual_dev {
+	/* we search the list based on these parameters */
+	__u16 idVendor;
+	__u16 idProduct;
+	__u16 bcdDevice;
+
+	/* the list specifies these parameters */
+	const char* name;
+	__u8  useProtocol;
+	__u8  useTransport;
+	unsigned int flags;
+};
+
+/* Flag definitions */
+#define US_FL_SINGLE_LUN      0x00000001 /* allow access to only LUN 0	    */
+#define US_FL_MODE_XLATE      0x00000002 /* translate _6 to _10 comands for
+						    Win/MacOS compatibility */
+#define US_FL_START_STOP      0x00000004 /* ignore START_STOP commands	    */
+#define US_FL_ALT_LENGTH      0x00000008 /* use the alternate algorithm for
+						    us_transfer_length()    */
+#define US_FL_IGNORE_SER      0x00000010 /* Ignore the serial number given  */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-uhci-debug.h linux.18p8/drivers/usb/usb-uhci-debug.h
--- linux.vanilla/drivers/usb/usb-uhci-debug.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usb-uhci-debug.h	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,182 @@
+#ifdef DEBUG
+static void uhci_show_qh (puhci_desc_t qh)
+{
+	if (qh->type != QH_TYPE) {
+		dbg("qh has not QH_TYPE");
+		return;
+	}
+	dbg("QH @ %p/%08lX:", qh, virt_to_bus (qh));
+
+	if (qh->hw.qh.head & UHCI_PTR_TERM)
+		dbg("    Head Terminate");
+	else 
+		dbg("    Head: %s @ %08X",
+		    (qh->hw.qh.head & UHCI_PTR_QH?"QH":"TD"),
+		    qh->hw.qh.head & ~UHCI_PTR_BITS);
+
+	if (qh->hw.qh.element & UHCI_PTR_TERM)
+		dbg("    Element Terminate");
+	else 
+		dbg("    Element: %s @ %08X",
+		    (qh->hw.qh.element & UHCI_PTR_QH?"QH":"TD"),
+		    qh->hw.qh.element & ~UHCI_PTR_BITS);
+}
+#endif
+
+static void uhci_show_td (puhci_desc_t td)
+{
+	char *spid;
+	
+	switch (td->hw.td.info & 0xff) {
+	case USB_PID_SETUP:
+		spid = "SETUP";
+		break;
+	case USB_PID_OUT:
+		spid = " OUT ";
+		break;
+	case USB_PID_IN:
+		spid = " IN  ";
+		break;
+	default:
+		spid = "  ?  ";
+		break;
+	}
+
+	warn("  TD @ %p/%08lX, MaxLen=%02x DT%d EP=%x Dev=%x PID=(%s) buf=%08x",
+	     td, virt_to_bus (td),
+	     td->hw.td.info >> 21,
+	     ((td->hw.td.info >> 19) & 1),
+	     (td->hw.td.info >> 15) & 15,
+	     (td->hw.td.info >> 8) & 127,
+	     spid,
+	     td->hw.td.buffer);
+
+	warn("    Len=%02x e%d %s%s%s%s%s%s%s%s%s%s",
+	     td->hw.td.status & 0x7ff,
+	     ((td->hw.td.status >> 27) & 3),
+	     (td->hw.td.status & TD_CTRL_SPD) ? "SPD " : "",
+	     (td->hw.td.status & TD_CTRL_LS) ? "LS " : "",
+	     (td->hw.td.status & TD_CTRL_IOC) ? "IOC " : "",
+	     (td->hw.td.status & TD_CTRL_ACTIVE) ? "Active " : "",
+	     (td->hw.td.status & TD_CTRL_STALLED) ? "Stalled " : "",
+	     (td->hw.td.status & TD_CTRL_DBUFERR) ? "DataBufErr " : "",
+	     (td->hw.td.status & TD_CTRL_BABBLE) ? "Babble " : "",
+	     (td->hw.td.status & TD_CTRL_NAK) ? "NAK " : "",
+	     (td->hw.td.status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
+	     (td->hw.td.status & TD_CTRL_BITSTUFF) ? "BitStuff " : ""
+		);
+
+	if (td->hw.td.link & UHCI_PTR_TERM)
+		warn("   TD Link Terminate");
+	else 
+		warn("    Link points to %s @ %08x, %s",
+		     (td->hw.td.link & UHCI_PTR_QH?"QH":"TD"),
+		     td->hw.td.link & ~UHCI_PTR_BITS,
+		     (td->hw.td.link & UHCI_PTR_DEPTH ? "Depth first" : "Breadth first"));
+}
+#ifdef DEBUG
+static void uhci_show_td_queue (puhci_desc_t td)
+{
+	//dbg("uhci_show_td_queue %p (%08lX):", td, virt_to_bus (td));
+	while (1) {
+		uhci_show_td (td);
+		if (td->hw.td.link & UHCI_PTR_TERM)
+			break;
+		if (td != bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS))
+			td = bus_to_virt (td->hw.td.link & ~UHCI_PTR_BITS);
+		else {
+			dbg("td points to itself!");
+			break;
+		}
+	}
+}
+
+static void uhci_show_queue (puhci_desc_t qh)
+{
+	uhci_desc_t *start_qh=qh;
+
+	dbg("uhci_show_queue %p:", qh);
+	while (1) {
+		uhci_show_qh (qh);
+
+		if (!(qh->hw.qh.element & UHCI_PTR_TERM))
+			uhci_show_td_queue (bus_to_virt (qh->hw.qh.element & ~UHCI_PTR_BITS));
+
+		if (qh->hw.qh.head & UHCI_PTR_TERM)
+			break;
+
+		if (qh != bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS))
+			qh = bus_to_virt (qh->hw.qh.head & ~UHCI_PTR_BITS);
+		else {
+			dbg("qh points to itself!");
+			break;
+		}
+		
+		if (qh==start_qh) { // avoid loop
+			dbg("Loop detect");
+			break;
+		}
+	}		
+}
+
+static void uhci_show_sc (int port, unsigned short status)
+{
+	dbg("  stat%d     =     %04x   %s%s%s%s%s%s%s%s",
+	     port,
+	     status,
+	     (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
+	     (status & USBPORTSC_PR) ? "PortReset " : "",
+	     (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
+	     (status & USBPORTSC_RD) ? "ResumeDetect " : "",
+	     (status & USBPORTSC_PEC) ? "EnableChange " : "",
+	     (status & USBPORTSC_PE) ? "PortEnabled " : "",
+	     (status & USBPORTSC_CSC) ? "ConnectChange " : "",
+	     (status & USBPORTSC_CCS) ? "PortConnected " : "");
+}
+
+void uhci_show_status (puhci_t s)
+{
+	unsigned int io_addr = s->io_addr;
+	unsigned short usbcmd, usbstat, usbint, usbfrnum;
+	unsigned int flbaseadd;
+	unsigned char sof;
+	unsigned short portsc1, portsc2;
+
+	usbcmd = inw (io_addr + 0);
+	usbstat = inw (io_addr + 2);
+	usbint = inw (io_addr + 4);
+	usbfrnum = inw (io_addr + 6);
+	flbaseadd = inl (io_addr + 8);
+	sof = inb (io_addr + 12);
+	portsc1 = inw (io_addr + 16);
+	portsc2 = inw (io_addr + 18);
+
+	dbg("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s",
+	     usbcmd,
+	     (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ",
+	     (usbcmd & USBCMD_CF) ? "CF " : "",
+	     (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "",
+	     (usbcmd & USBCMD_FGR) ? "FGR " : "",
+	     (usbcmd & USBCMD_EGSM) ? "EGSM " : "",
+	     (usbcmd & USBCMD_GRESET) ? "GRESET " : "",
+	     (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
+	     (usbcmd & USBCMD_RS) ? "RS " : "");
+
+	dbg("  usbstat   =     %04x   %s%s%s%s%s%s",
+	     usbstat,
+	     (usbstat & USBSTS_HCH) ? "HCHalted " : "",
+	     (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "",
+	     (usbstat & USBSTS_HSE) ? "HostSystemError " : "",
+	     (usbstat & USBSTS_RD) ? "ResumeDetect " : "",
+	     (usbstat & USBSTS_ERROR) ? "USBError " : "",
+	     (usbstat & USBSTS_USBINT) ? "USBINT " : "");
+
+	dbg("  usbint    =     %04x", usbint);
+	dbg("  usbfrnum  =   (%d)%03x", (usbfrnum >> 10) & 1,
+	     0xfff & (4 * (unsigned int) usbfrnum));
+	dbg("  flbaseadd = %08x", flbaseadd);
+	dbg("  sof       =       %02x", sof);
+	uhci_show_sc (1, portsc1);
+	uhci_show_sc (2, portsc2);
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-uhci.c linux.18p8/drivers/usb/usb-uhci.c
--- linux.vanilla/drivers/usb/usb-uhci.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usb-uhci.c	Wed Sep 13 16:24:37 2000
@@ -0,0 +1,2896 @@
+/* 
+ * Universal Host Controller Interface driver for USB (take II).
+ *
+ * (c) 1999 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
+ *          Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
+ *          Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
+ *          Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
+ *          
+ * HW-initalization based on material of
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ *
+ * $Id: usb-uhci.c,v 1.232 2000/06/11 13:18:30 acher Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>	/* for in_interrupt() */
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+/* This enables more detailed sanity checks in submit_iso */
+//#define ISO_SANITY_CHECK
+
+/* This enables debug printks */
+//#define DEBUG
+
+/* This enables all symbols to be exported, to ease debugging oopses */
+//#define DEBUG_SYMBOLS
+
+/* This enables an extra UHCI slab for memory debugging */
+#define DEBUG_SLAB
+
+#define VERSTR "$Revision: 1.232 $ time " __TIME__ " " __DATE__
+
+#include <linux/usb.h>
+#include "usb-uhci.h"
+#include "usb-uhci-debug.h"
+
+#undef DEBUG
+#undef dbg
+#define dbg(format, arg...) do {} while (0)
+#define DEBUG_SYMBOLS
+#ifdef DEBUG_SYMBOLS
+	#define _static
+	#ifndef EXPORT_SYMTAB
+		#define EXPORT_SYMTAB
+	#endif
+#else
+	#define _static static
+#endif
+
+#define queue_dbg dbg //err
+#define async_dbg dbg //err
+
+#ifdef DEBUG_SLAB
+	static kmem_cache_t *uhci_desc_kmem;
+	static kmem_cache_t *urb_priv_kmem;
+#endif
+
+#define SLAB_FLAG     (in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL)
+#define KMALLOC_FLAG  (in_interrupt ()? GFP_ATOMIC : GFP_KERNEL)
+
+#define CONFIG_USB_UHCI_HIGH_BANDWIDTH 
+#define USE_CTRL_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
+#define USE_BULK_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
+
+// stop bandwidth reclamation after (roughly) 50ms
+#define IDLE_TIMEOUT  (HZ/20)
+
+_static int rh_submit_urb (urb_t *urb);
+_static int rh_unlink_urb (urb_t *urb);
+_static int delete_qh (uhci_t *s, uhci_desc_t *qh);
+_static int process_transfer (uhci_t *s, urb_t *urb, int mode);
+_static int process_interrupt (uhci_t *s, urb_t *urb);
+_static int process_iso (uhci_t *s, urb_t *urb, int force);
+
+static uhci_t *devs = NULL;
+
+/* used by userspace UHCI data structure dumper */
+uhci_t **uhci_devices = &devs;
+
+/*-------------------------------------------------------------------*/
+// Cleans up collected QHs
+void clean_descs(uhci_t *s, int force)
+{
+	struct list_head *q;
+	uhci_desc_t *qh;
+	int now=UHCI_GET_CURRENT_FRAME(s);
+
+	q=s->free_desc.prev;
+
+	while (q != &s->free_desc) {
+		qh = list_entry (q, uhci_desc_t, horizontal);
+		q=qh->horizontal.prev;
+
+		if ((qh->last_used!=now) || force)
+			delete_qh(s,qh);
+	}
+}
+/*-------------------------------------------------------------------*/
+_static void uhci_switch_timer_int(uhci_t *s)
+{
+
+	if (!list_empty(&s->urb_unlinked)) {
+		s->td1ms->hw.td.status |= TD_CTRL_IOC;
+	}
+	else {
+		s->td1ms->hw.td.status &= ~TD_CTRL_IOC;
+	}
+
+	if (s->timeout_urbs) {
+		s->td32ms->hw.td.status |= TD_CTRL_IOC;
+	}
+	else {
+		s->td32ms->hw.td.status &= ~TD_CTRL_IOC;
+	}
+
+	wmb();
+}
+/*-------------------------------------------------------------------*/
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+_static void enable_desc_loop(uhci_t *s, urb_t *urb)
+{
+	int flags;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+	s->chain_end->hw.qh.head&=~UHCI_PTR_TERM; 
+	mb();
+	s->loop_usage++;
+	((urb_priv_t*)urb->hcpriv)->use_loop=1;
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+}
+/*-------------------------------------------------------------------*/
+_static void disable_desc_loop(uhci_t *s, urb_t *urb)
+{
+	int flags;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+
+	if (((urb_priv_t*)urb->hcpriv)->use_loop) {
+		s->loop_usage--;
+
+		if (!s->loop_usage) {
+			s->chain_end->hw.qh.head|=UHCI_PTR_TERM;
+			mb();
+		}
+		((urb_priv_t*)urb->hcpriv)->use_loop=0;
+	}
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+}
+#endif
+/*-------------------------------------------------------------------*/
+_static void queue_urb_unlocked (uhci_t *s, urb_t *urb)
+{
+	struct list_head *p=&urb->urb_list;
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	{
+		int type;
+		type=usb_pipetype (urb->pipe);
+
+		if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+			enable_desc_loop(s, urb);
+	}
+#endif
+	((urb_priv_t*)urb->hcpriv)->started=jiffies;
+	list_add (p, &s->urb_list);
+	if (urb->timeout)
+		s->timeout_urbs++;
+	uhci_switch_timer_int(s);
+}
+/*-------------------------------------------------------------------*/
+_static void queue_urb (uhci_t *s, urb_t *urb)
+{
+	unsigned long flags=0;
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+	queue_urb_unlocked(s,urb);
+	spin_unlock_irqrestore (&s->urb_list_lock, flags);
+}
+/*-------------------------------------------------------------------*/
+_static void dequeue_urb (uhci_t *s, urb_t *urb)
+{
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	int type;
+
+	type=usb_pipetype (urb->pipe);
+
+	if ((type == PIPE_BULK) || (type == PIPE_CONTROL))
+		disable_desc_loop(s, urb);
+#endif
+
+	list_del (&urb->urb_list);
+	if (urb->timeout && s->timeout_urbs)
+		s->timeout_urbs--;
+
+}
+/*-------------------------------------------------------------------*/
+_static int alloc_td (uhci_desc_t ** new, int flags)
+{
+#ifdef DEBUG_SLAB
+	*new= kmem_cache_alloc(uhci_desc_kmem, SLAB_FLAG);
+#else
+	*new = (uhci_desc_t *) kmalloc (sizeof (uhci_desc_t), KMALLOC_FLAG);
+#endif
+	if (!*new)
+		return -ENOMEM;
+	 memset (*new, 0, sizeof (uhci_desc_t));
+	(*new)->hw.td.link = UHCI_PTR_TERM | (flags & UHCI_PTR_BITS);	// last by default
+	(*new)->type = TD_TYPE;
+	mb();
+	INIT_LIST_HEAD (&(*new)->vertical);
+	INIT_LIST_HEAD (&(*new)->horizontal);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// append a qh to td.link physically, the SW linkage is not affected
+_static void append_qh(uhci_t *s, uhci_desc_t *td, uhci_desc_t* qh, int  flags)
+{
+	unsigned long xxx;
+	
+	spin_lock_irqsave (&s->td_lock, xxx);
+
+	td->hw.td.link = virt_to_bus (qh) | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH;
+       
+	mb();
+	spin_unlock_irqrestore (&s->td_lock, xxx);
+}
+/*-------------------------------------------------------------------*/
+/* insert td at last position in td-list of qh (vertical) */
+_static int insert_td (uhci_t *s, uhci_desc_t *qh, uhci_desc_t* new, int flags)
+{
+	uhci_desc_t *prev;
+	unsigned long xxx;
+	
+	spin_lock_irqsave (&s->td_lock, xxx);
+
+	list_add_tail (&new->vertical, &qh->vertical);
+
+	prev = list_entry (new->vertical.prev, uhci_desc_t, vertical);
+
+	if (qh == prev ) {
+		// virgin qh without any tds
+		qh->hw.qh.element = virt_to_bus (new);
+	}
+	else {
+		// already tds inserted, implicitely remove TERM bit of prev
+		prev->hw.td.link = virt_to_bus (new) | (flags & UHCI_PTR_DEPTH);
+	}
+	mb();
+	spin_unlock_irqrestore (&s->td_lock, xxx);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+/* insert new_td after td (horizontal) */
+_static int insert_td_horizontal (uhci_t *s, uhci_desc_t *td, uhci_desc_t* new)
+{
+	uhci_desc_t *next;
+	unsigned long flags;
+	
+	spin_lock_irqsave (&s->td_lock, flags);
+
+	next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
+	list_add (&new->horizontal, &td->horizontal);
+	new->hw.td.link = td->hw.td.link;
+	td->hw.td.link = virt_to_bus (new);
+	mb();
+	spin_unlock_irqrestore (&s->td_lock, flags);	
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int unlink_td (uhci_t *s, uhci_desc_t *element, int phys_unlink)
+{
+	uhci_desc_t *next, *prev;
+	int dir = 0;
+	unsigned long flags;
+	
+	spin_lock_irqsave (&s->td_lock, flags);
+	
+	next = list_entry (element->vertical.next, uhci_desc_t, vertical);
+	
+	if (next == element) {
+		dir = 1;
+		prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
+	}
+	else 
+		prev = list_entry (element->vertical.prev, uhci_desc_t, vertical);
+	
+	if (phys_unlink) {
+		// really remove HW linking
+		if (prev->type == TD_TYPE)
+			prev->hw.td.link = element->hw.td.link;
+		else
+			prev->hw.qh.element = element->hw.td.link;
+	}
+
+	mb ();
+
+	if (dir == 0)
+		list_del (&element->vertical);
+	else
+		list_del (&element->horizontal);
+	
+	spin_unlock_irqrestore (&s->td_lock, flags);	
+	
+	return 0;
+}
+
+/*-------------------------------------------------------------------*/
+_static int delete_desc (uhci_desc_t *element)
+{
+#ifdef DEBUG_SLAB
+	kmem_cache_free(uhci_desc_kmem, element);
+#else
+	kfree (element);
+#endif
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// Allocates qh element
+_static int alloc_qh (uhci_desc_t ** new)
+{
+#ifdef DEBUG_SLAB
+	*new= kmem_cache_alloc(uhci_desc_kmem, SLAB_FLAG);
+#else
+	*new = (uhci_desc_t *) kmalloc (sizeof (uhci_desc_t), KMALLOC_FLAG);
+#endif	
+	if (!*new)
+		return -ENOMEM;
+	memset (*new, 0, sizeof (uhci_desc_t));
+	(*new)->hw.qh.head = UHCI_PTR_TERM;
+	(*new)->hw.qh.element = UHCI_PTR_TERM;
+	(*new)->type = QH_TYPE;
+	
+	mb();
+	INIT_LIST_HEAD (&(*new)->horizontal);
+	INIT_LIST_HEAD (&(*new)->vertical);
+	
+	dbg("Allocated qh @ %p", *new);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// inserts new qh before/after the qh at pos
+// flags: 0: insert before pos, 1: insert after pos (for low speed transfers)
+_static int insert_qh (uhci_t *s, uhci_desc_t *pos, uhci_desc_t *new, int order)
+{
+	uhci_desc_t *old;
+	unsigned long flags;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+
+	if (!order) {
+		// (OLD) (POS) -> (OLD) (NEW) (POS)
+		old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
+		list_add_tail (&new->horizontal, &pos->horizontal);
+		new->hw.qh.head = MAKE_QH_ADDR (pos) ;
+		if (!(old->hw.qh.head & UHCI_PTR_TERM))
+			old->hw.qh.head = MAKE_QH_ADDR (new) ;
+	}
+	else {
+		// (POS) (OLD) -> (POS) (NEW) (OLD)
+		old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal);
+		list_add (&new->horizontal, &pos->horizontal);
+		new->hw.qh.head = MAKE_QH_ADDR (old);
+		pos->hw.qh.head = MAKE_QH_ADDR (new) ;
+	}
+
+	mb ();
+	
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------*/
+_static int unlink_qh (uhci_t *s, uhci_desc_t *element)
+{
+	uhci_desc_t  *prev;
+	unsigned long flags;
+
+	spin_lock_irqsave (&s->qh_lock, flags);
+	
+	prev = list_entry (element->horizontal.prev, uhci_desc_t, horizontal);
+	prev->hw.qh.head = element->hw.qh.head;
+
+	list_del(&element->horizontal);
+
+	mb ();
+	spin_unlock_irqrestore (&s->qh_lock, flags);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int delete_qh (uhci_t *s, uhci_desc_t *qh)
+{
+	uhci_desc_t *td;
+	struct list_head *p;
+	
+	list_del (&qh->horizontal);
+
+	while ((p = qh->vertical.next) != &qh->vertical) {
+		td = list_entry (p, uhci_desc_t, vertical);
+		dbg("unlink td @ %p",td);
+		unlink_td (s, td, 0); // no physical unlink
+		delete_desc (td);
+	}
+
+	delete_desc (qh);
+	
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static void clean_td_chain (uhci_desc_t *td)
+{
+	struct list_head *p;
+	uhci_desc_t *td1;
+
+	if (!td)
+		return;
+	
+	while ((p = td->horizontal.next) != &td->horizontal) {
+		td1 = list_entry (p, uhci_desc_t, horizontal);
+		delete_desc (td1);
+	}
+	
+	delete_desc (td);
+}
+
+/*-------------------------------------------------------------------*/
+_static void fill_td (uhci_desc_t *td, int status, int info, __u32 buffer)
+{
+	td->hw.td.status = status;
+	td->hw.td.info = info;
+	td->hw.td.buffer = buffer;
+}
+/*-------------------------------------------------------------------*/
+// Removes ALL qhs in chain (paranoia!)
+_static void cleanup_skel (uhci_t *s)
+{
+	unsigned int n;
+	uhci_desc_t *td;
+
+	dbg("cleanup_skel");
+
+	clean_descs(s,1);
+
+	
+	if (s->td32ms) {
+	
+		unlink_td(s,s->td32ms,1);
+		delete_desc(s->td32ms);
+	}
+
+	for (n = 0; n < 8; n++) {
+		td = s->int_chain[n];
+		clean_td_chain (td);
+	}
+
+	if (s->iso_td) {
+		for (n = 0; n < 1024; n++) {
+			td = s->iso_td[n];
+			clean_td_chain (td);
+		}
+		kfree (s->iso_td);
+	}
+
+	if (s->framelist)
+		free_page ((unsigned long) s->framelist);
+
+	if (s->control_chain) {
+		// completed init_skel?
+		struct list_head *p;
+		uhci_desc_t *qh, *qh1;
+
+		qh = s->control_chain;
+		while ((p = qh->horizontal.next) != &qh->horizontal) {
+			qh1 = list_entry (p, uhci_desc_t, horizontal);
+			delete_qh (s, qh1);
+		}
+
+		delete_qh (s, qh);
+	}
+	else {
+		if (s->ls_control_chain)
+			delete_desc (s->ls_control_chain);
+		if (s->control_chain)
+			 delete_desc(s->control_chain);
+		if (s->bulk_chain)
+			delete_desc (s->bulk_chain);
+		if (s->chain_end)
+			delete_desc (s->chain_end);
+	}
+	dbg("cleanup_skel finished");	
+}
+/*-------------------------------------------------------------------*/
+// allocates framelist and qh-skeletons
+// only HW-links provide continous linking, SW-links stay in their domain (ISO/INT)
+_static int init_skel (uhci_t *s)
+{
+	int n, ret;
+	uhci_desc_t *qh, *td;
+	
+	dbg("init_skel");
+	
+	s->framelist = (__u32 *) get_free_page (GFP_KERNEL);
+
+	if (!s->framelist)
+		return -ENOMEM;
+
+	memset (s->framelist, 0, 4096);
+
+	dbg("allocating iso desc pointer list");
+	s->iso_td = (uhci_desc_t **) kmalloc (1024 * sizeof (uhci_desc_t*), GFP_KERNEL);
+	
+	if (!s->iso_td)
+		goto init_skel_cleanup;
+
+	s->ls_control_chain = NULL;
+	s->control_chain = NULL;
+	s->bulk_chain = NULL;
+	s->chain_end = NULL;
+
+	dbg("allocating iso descs");
+	for (n = 0; n < 1024; n++) {
+	 	// allocate skeleton iso/irq-tds
+		ret = alloc_td (&td, 0);
+		if (ret)
+			goto init_skel_cleanup;
+		s->iso_td[n] = td;
+		s->framelist[n] = ((__u32) virt_to_bus (td));
+	}
+
+	dbg("allocating qh: chain_end");
+	ret = alloc_qh (&qh);
+	
+	if (ret)
+		goto init_skel_cleanup;
+				
+	s->chain_end = qh;
+
+	ret = alloc_td (&td, 0);
+
+	if (ret)
+		goto init_skel_cleanup;
+	
+	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
+	insert_td (s, qh, td, 0);
+	s->td1ms=td;
+
+	dbg("allocating qh: bulk_chain");
+	ret = alloc_qh (&qh);
+	if (ret)
+		goto init_skel_cleanup;
+	
+	insert_qh (s, s->chain_end, qh, 0);
+	s->bulk_chain = qh;
+
+	dbg("allocating qh: control_chain");
+	ret = alloc_qh (&qh);
+	if (ret)
+		goto init_skel_cleanup;
+	
+	insert_qh (s, s->bulk_chain, qh, 0);
+	s->control_chain = qh;
+
+#ifdef	CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	// disabled reclamation loop
+	s->chain_end->hw.qh.head=virt_to_bus(s->control_chain) | UHCI_PTR_QH | UHCI_PTR_TERM;
+#endif
+
+	dbg("allocating qh: ls_control_chain");
+	ret = alloc_qh (&qh);
+	if (ret)
+		goto init_skel_cleanup;
+	
+	insert_qh (s, s->control_chain, qh, 0);
+	s->ls_control_chain = qh;
+
+	for (n = 0; n < 8; n++)
+		s->int_chain[n] = 0;
+
+	dbg("allocating skeleton INT-TDs");
+	
+	for (n = 0; n < 8; n++) {
+		uhci_desc_t *td;
+
+		alloc_td (&td, 0);
+		if (!td)
+			goto init_skel_cleanup;
+		s->int_chain[n] = td;
+		if (n == 0) {
+			s->int_chain[0]->hw.td.link = virt_to_bus (s->ls_control_chain) | UHCI_PTR_QH;
+		}
+		else {
+			s->int_chain[n]->hw.td.link = virt_to_bus (s->int_chain[0]);
+		}
+	}
+
+	dbg("Linking skeleton INT-TDs");
+	
+	for (n = 0; n < 1024; n++) {
+		// link all iso-tds to the interrupt chains
+		int m, o;
+		dbg("framelist[%i]=%x",n,s->framelist[n]);
+		if ((n&127)==127) 
+			((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus(s->int_chain[0]);
+		else 
+			for (o = 1, m = 2; m <= 128; o++, m += m)
+				if ((n & (m - 1)) == ((m - 1) / 2))
+					((uhci_desc_t*) s->iso_td[n])->hw.td.link = virt_to_bus (s->int_chain[o]);
+	}
+
+	ret = alloc_td (&td, 0);
+
+	if (ret)
+		goto init_skel_cleanup;
+	
+	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt
+	s->td32ms=td;
+
+	insert_td_horizontal (s, s->int_chain[5], td);
+
+	mb();
+	//uhci_show_queue(s->control_chain);   
+	dbg("init_skel exit");
+	return 0;
+
+      init_skel_cleanup:
+	cleanup_skel (s);
+	return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------*/
+//                         LOW LEVEL STUFF
+//          assembles QHs und TDs for control, bulk and iso
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_control_urb (urb_t *urb)
+{
+	uhci_desc_t *qh, *td;
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	unsigned long destination, status;
+	int maxsze = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+	unsigned long len;
+	char *data;
+	int depth_first=USE_CTRL_DEPTH_FIRST;  // UHCI descriptor chasing method
+
+	if (!maxsze) {
+		err("uhci_submit_control_urb: pipesize for pipe %x is zero", urb->pipe);
+		return -EINVAL;
+	}
+
+	dbg("uhci_submit_control start");
+	alloc_qh (&qh);		// alloc qh for this request
+
+	if (!qh)
+		return -ENOMEM;
+
+	alloc_td (&td, UHCI_PTR_DEPTH * depth_first);		// get td for setup stage
+
+	if (!td) {
+		delete_qh (s, qh);
+		return -ENOMEM;
+	}
+
+	/* The "pipe" thing contains the destination in bits 8--18 */
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
+
+	/* 3 errors */
+	status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
+		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+	/*  Build the TD for the control request, try forever, 8 bytes of data */
+	fill_td (td, status, destination | (7 << 21), virt_to_bus (urb->setup_packet));
+
+	insert_td (s, qh, td, 0);	// queue 'setup stage'-td in qh
+#if 0
+	{
+		char *sp=urb->setup_packet;
+		dbg("SETUP to pipe %x: %x %x %x %x %x %x %x %x", urb->pipe,
+		    sp[0],sp[1],sp[2],sp[3],sp[4],sp[5],sp[6],sp[7]);
+	}
+	//uhci_show_td(td);
+#endif
+
+	len = urb->transfer_buffer_length;
+	data = urb->transfer_buffer;
+
+	/* If direction is "send", change the frame from SETUP (0x2D)
+	   to OUT (0xE1). Else change it from SETUP to IN (0x69). */
+
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | (usb_pipeout (urb->pipe)?USB_PID_OUT:USB_PID_IN);
+
+	while (len > 0) {
+		int pktsze = len;
+
+		alloc_td (&td, UHCI_PTR_DEPTH * depth_first);
+		if (!td) {
+			delete_qh (s, qh);
+			return -ENOMEM;
+		}
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		destination ^= 1 << TD_TOKEN_TOGGLE;	// toggle DATA0/1
+
+		fill_td (td, status, destination | ((pktsze - 1) << 21),
+			 virt_to_bus (data));	// Status, pktsze bytes of data
+
+		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue 'data stage'-td in qh
+
+		data += pktsze;
+		len -= pktsze;
+	}
+
+	/*  Build the final TD for control status */
+	/* It's only IN if the pipe is out AND we aren't expecting data */
+
+	destination &= ~UHCI_PID;
+
+	if (usb_pipeout (urb->pipe) || (urb->transfer_buffer_length == 0))
+		destination |= USB_PID_IN;
+	else
+		destination |= USB_PID_OUT;
+
+	destination |= 1 << TD_TOKEN_TOGGLE;	/* End in Data1 */
+
+	alloc_td (&td, UHCI_PTR_DEPTH);
+	
+	if (!td) {
+		delete_qh (s, qh);
+		return -ENOMEM;
+	}
+	status &=~TD_CTRL_SPD;
+
+	/* no limit on errors on final packet , 0 bytes of data */
+	fill_td (td, status | TD_CTRL_IOC, destination | (UHCI_NULL_DATA_SIZE << 21),
+		 0);
+
+	insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);	// queue status td
+
+	list_add (&qh->desc_list, &urb_priv->desc_list);
+
+	urb->status = -EINPROGRESS;
+	queue_urb (s, urb);	// queue before inserting in desc chain
+
+	qh->hw.qh.element &= ~UHCI_PTR_TERM;
+
+	//uhci_show_queue(qh);
+	/* Start it up... put low speed first */
+	if (urb->pipe & TD_CTRL_LS)
+		insert_qh (s, s->control_chain, qh, 0);
+	else
+		insert_qh (s, s->bulk_chain, qh, 0);
+
+	dbg("uhci_submit_control end");
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// For queued bulk transfers, two additional QH helpers are allocated (nqh, bqh)
+// Due to the linking with other bulk urbs, it has to be locked with urb_list_lock!
+
+_static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	uhci_desc_t *qh, *td, *nqh, *bqh;
+	unsigned long destination, status;
+	char *data;
+	unsigned int pipe = urb->pipe;
+	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+	int info, len;
+	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method
+	urb_priv_t *upriv, *bpriv;
+
+	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
+		return -EPIPE;
+
+	if (urb->transfer_buffer_length < 0) {
+		err("Negative transfer length in submit_bulk");
+		return -EINVAL;
+	}
+	
+	if (!maxsze)
+		return -EMSGSIZE;
+	
+	queue_dbg("uhci_submit_bulk_urb: urb %p, old %p, pipe %08x, len %i",
+		  urb,bulk_urb,urb->pipe,urb->transfer_buffer_length);
+
+	upriv=(urb_priv_t*)urb->hcpriv;
+
+	if (!bulk_urb) {
+		alloc_qh (&qh);		// get qh for this request
+		
+		if (!qh)
+			return -ENOMEM;
+
+		if (urb->transfer_flags & USB_QUEUE_BULK) {
+			alloc_qh(&nqh); // placeholder for clean unlink
+			if (!nqh) {
+				delete_desc (qh);
+				return -ENOMEM;
+			}
+			upriv->next_qh = nqh;
+			queue_dbg("new next qh %p",nqh);
+		}
+	}
+	else { 
+		bpriv = (urb_priv_t*)bulk_urb->hcpriv;
+		qh = bpriv->bottom_qh;  // re-use bottom qh and next qh
+		nqh = bpriv->next_qh;
+		upriv->next_qh=nqh;
+		bpriv->next_queued_urb=urb;
+		upriv->prev_queued_urb=bulk_urb;
+	}
+
+	queue_dbg("uhci_submit_bulk: qh=%p, nqh=%p\n",bqh,nqh);
+
+	if (urb->transfer_flags & USB_QUEUE_BULK) {
+		alloc_qh (&bqh); // "bottom" QH,
+		
+		if (!bqh) {
+			if (!bulk_urb) { 
+				delete_desc(qh);
+				delete_desc(nqh);
+			}
+			return -ENOMEM;
+		}
+		bqh->hw.qh.element = UHCI_PTR_TERM;
+		bqh->hw.qh.element = virt_to_bus(nqh)|UHCI_PTR_QH;
+		upriv->bottom_qh = bqh;
+		queue_dbg("uhci_submit_bulk: new bqh %p\n",bqh);
+	}
+	
+
+	/* The "pipe" thing contains the destination in bits 8--18. */
+	destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
+
+	/* 3 errors */
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE |
+		((urb->transfer_flags & USB_DISABLE_SPD) ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+	/* Build the TDs for the bulk request */
+	len = urb->transfer_buffer_length;
+	data = urb->transfer_buffer;
+	
+	do {					// TBD: Really allow zero-length packets?
+		int pktsze = len;
+
+		alloc_td (&td, UHCI_PTR_DEPTH * depth_first);
+
+		if (!td) {
+			delete_qh (s, qh);
+			return -ENOMEM;
+		}
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		// pktsze bytes of data 
+		info = destination | (((pktsze - 1)&UHCI_NULL_DATA_SIZE) << 21) |
+			(usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+		fill_td (td, status, info, virt_to_bus (data));
+
+		data += pktsze;
+		len -= pktsze;
+
+		if (!len)
+			td->hw.td.status |= TD_CTRL_IOC;	// last one generates INT
+
+		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
+		usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+	} while (len > 0);
+
+	list_add (&qh->desc_list, &urb_priv->desc_list);
+
+	if (urb->transfer_flags & USB_QUEUE_BULK) {
+		qh->hw.qh.element&=~UHCI_PTR_TERM;
+		append_qh(s, td, bqh, UHCI_PTR_DEPTH * depth_first);
+	}
+
+	urb->status = -EINPROGRESS;
+	queue_urb_unlocked (s, urb);
+	
+	qh->hw.qh.element  &= ~UHCI_PTR_TERM;
+
+	if (!bulk_urb) { 
+		if (urb->transfer_flags & USB_QUEUE_BULK) {
+			spin_lock (&s->td_lock);			// both QHs in one go
+			insert_qh (s, s->chain_end, qh, 0);	// Main QH
+			insert_qh (s, s->chain_end, nqh, 0);	// Helper QH
+			spin_unlock (&s->td_lock);
+		}
+		else
+			insert_qh (s, s->chain_end, qh, 0);
+	}
+	
+	//uhci_show_queue(s->bulk_chain);
+	//dbg("uhci_submit_bulk_urb: exit\n");
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static void uhci_clean_iso_step1(uhci_t *s, urb_priv_t *urb_priv)
+{
+	struct list_head *p;
+	uhci_desc_t *td;
+
+	for (p = urb_priv->desc_list.next; p != &urb_priv->desc_list; p = p->next) {
+				td = list_entry (p, uhci_desc_t, desc_list);
+				unlink_td (s, td, 1);
+	}
+}
+/*-------------------------------------------------------------------*/
+_static void uhci_clean_iso_step2(uhci_t *s, urb_priv_t *urb_priv)
+{
+	struct list_head *p;
+	uhci_desc_t *td;
+
+	while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
+				td = list_entry (p, uhci_desc_t, desc_list);
+				list_del (p);
+				delete_desc (td);
+	}
+}
+/*-------------------------------------------------------------------*/
+// mode: 0: unlink + no deletion mark, 1: regular (unlink/delete-mark), 2: don't unlink
+// looks a bit complicated because of all the bulk queueing goodies
+
+_static void uhci_clean_transfer (uhci_t *s, urb_t *urb, uhci_desc_t *qh, int mode)
+{
+	uhci_desc_t *bqh, *nqh, *prevqh;
+	int now;
+	urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
+
+	now=UHCI_GET_CURRENT_FRAME(s);
+
+	dbg("clean transfer urb %p, qh %p, mode %i",urb,qh,mode);
+	bqh=priv->bottom_qh;	
+
+	if (!priv->next_queued_urb)  { // no more appended bulk queues
+
+		if (mode != 2) 
+			unlink_qh (s, qh);
+	
+		if (priv->prev_queued_urb) {
+			urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
+
+			ppriv->bottom_qh = priv->bottom_qh;
+			ppriv->next_queued_urb = NULL;
+		}
+		else if (bqh) {  // queue dead
+			nqh=priv->next_qh;
+			
+			if (mode != 2)
+				unlink_qh(s, nqh);
+
+			if (mode) {
+				nqh->last_used = bqh->last_used = now;
+				list_add_tail (&nqh->horizontal, &s->free_desc);
+				list_add_tail (&bqh->horizontal, &s->free_desc);
+			}			
+		}
+	}
+	else { // there are queued urbs following
+		urb_t *nurb;
+		unsigned long flags;
+		
+       		nurb=priv->next_queued_urb;
+		spin_lock_irqsave (&s->qh_lock, flags);
+		
+		if (!priv->prev_queued_urb) { // top
+			if (mode !=2) {
+				prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal);
+				prevqh->hw.qh.head = virt_to_bus(bqh) | UHCI_PTR_QH;
+				queue_dbg ("TOP relink of %p to %p-%p",qh,prevqh,bqh);	
+			
+				list_del (&qh->horizontal);
+				list_add (&bqh->horizontal, &prevqh->horizontal);
+			}	
+		}
+		else {		//intermediate
+			urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
+			uhci_desc_t * bnqh;
+			
+			bnqh=list_entry (&((urb_priv_t*)(nurb->hcpriv))->desc_list.next, uhci_desc_t, desc_list);
+			ppriv->bottom_qh=bnqh;
+			ppriv->next_queued_urb=nurb;
+			
+			if (mode!=2) {
+				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
+				prevqh->hw.qh.head = virt_to_bus(bqh) | UHCI_PTR_QH;
+				queue_dbg ("IM relink of %p to %p-%p",qh,prevqh,bqh);	
+			}
+		}
+		mb();
+		spin_unlock_irqrestore (&s->qh_lock, flags);
+		((urb_priv_t*)nurb->hcpriv)->prev_queued_urb=priv->prev_queued_urb;	
+	}
+
+	if (mode) {
+		qh->last_used = now;
+		list_add_tail (&qh->horizontal, &s->free_desc); // mark for later deletion
+	}
+}
+/*-------------------------------------------------------------------*/
+// unlinks an urb by dequeuing its qh, waits some frames and forgets it
+_static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
+{
+	uhci_desc_t *qh;
+	urb_priv_t *urb_priv;
+	unsigned long flags=0;
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+
+	if (urb->status == -EINPROGRESS) {
+		// URB probably still in work
+		dequeue_urb (s, urb);
+		uhci_switch_timer_int(s);
+		s->unlink_urb_done=1;
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);		
+		
+		urb->status = -ENOENT;	// mark urb as killed		
+		urb_priv = urb->hcpriv;
+
+		switch (usb_pipetype (urb->pipe)) {
+
+		case PIPE_INTERRUPT:
+			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+
+		case PIPE_ISOCHRONOUS:
+			uhci_clean_iso_step1(s, urb_priv);
+			uhci_wait_ms(1);
+			uhci_clean_iso_step2(s, urb_priv);
+			break;
+
+		case PIPE_BULK:
+		case PIPE_CONTROL:
+			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
+			spin_lock_irqsave (&s->urb_list_lock, flags);
+			uhci_clean_transfer(s, urb, qh, 1);
+			spin_unlock_irqrestore (&s->urb_list_lock, flags);
+			uhci_wait_ms(1);
+		}
+		
+#ifdef DEBUG_SLAB
+		kmem_cache_free (urb_priv_kmem, urb->hcpriv);
+#else
+		kfree (urb->hcpriv);
+#endif
+		if (urb->complete) {
+			dbg("unlink_urb: calling completion");
+			urb->complete ((struct urb *) urb);
+		}
+		usb_dec_dev_use (urb->dev);
+		return 0;
+	}
+	else
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// async unlink_urb completion/cleanup work
+// has to be protected by urb_list_lock!
+// features: if set in transfer_flags, the resulting status of the killed
+// transaction is not overwritten
+
+_static void uhci_cleanup_unlink(uhci_t *s, int force)
+{
+	struct list_head *q;
+	urb_t *urb;
+	struct usb_device *dev;
+	int pipe,now;
+	urb_priv_t *urb_priv;
+
+	q=s->urb_unlinked.next;
+	now=UHCI_GET_CURRENT_FRAME(s);
+
+	while (q != &s->urb_unlinked) {
+
+		urb = list_entry (q, urb_t, urb_list);
+
+		urb_priv = (urb_priv_t*)urb->hcpriv;
+		q = urb->urb_list.next;
+		
+		if (force ||
+ 		    ((urb_priv->started != 0xffffffff) && (urb_priv->started != now))) {
+			async_dbg("async cleanup %p",urb);
+			switch (usb_pipetype (urb->pipe)) { // process descriptors
+			case PIPE_CONTROL:
+				process_transfer (s, urb, 2);
+				break;
+			case PIPE_BULK:
+				if (!s->avoid_bulk.counter)
+					process_transfer (s, urb, 2); // don't unlink (already done)
+				else
+					continue;
+				break;
+			case PIPE_ISOCHRONOUS:
+				process_iso (s, urb, 1); // force, don't unlink
+				break;
+			case PIPE_INTERRUPT:
+				process_interrupt (s, urb);
+				break;
+			}
+
+			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
+		  		urb->status = -ECONNRESET; // mark as asynchronously killed
+
+			pipe = urb->pipe;		// completion may destroy all...
+			dev = urb->dev;
+			urb_priv = urb->hcpriv;
+
+			if (urb->complete) {
+				spin_unlock(&s->urb_list_lock);
+				urb->complete ((struct urb *) urb);
+				spin_lock(&s->urb_list_lock);
+			}
+
+			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
+				urb->status = -ENOENT;  // now the urb is really dead
+			switch (usb_pipetype (pipe)) {
+			case PIPE_ISOCHRONOUS:
+			case PIPE_INTERRUPT:
+				uhci_clean_iso_step2(s, urb_priv);
+				break;
+			}
+	
+			usb_dec_dev_use (dev);
+#ifdef DEBUG_SLAB
+			kmem_cache_free (urb_priv_kmem, urb_priv);
+#else
+			kfree (urb_priv);
+#endif
+
+			list_del (&urb->urb_list);
+		}
+	}
+}
+
+/*-------------------------------------------------------------------*/
+_static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
+{
+	uhci_desc_t *qh;
+	urb_priv_t *urb_priv;
+	
+	async_dbg("unlink_urb_async called %p",urb);
+
+	if ((urb->status == -EINPROGRESS) ||
+	    ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
+	{
+		((urb_priv_t*)urb->hcpriv)->started = ~0;
+
+		dequeue_urb (s, urb);
+		list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
+		uhci_switch_timer_int(s);
+			
+		s->unlink_urb_done = 1;
+		
+		urb->status = -ECONNABORTED;	// mark urb as "waiting to be killed"	
+		urb_priv = (urb_priv_t*)urb->hcpriv;
+
+		switch (usb_pipetype (urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));		
+
+		case PIPE_ISOCHRONOUS:
+			uhci_clean_iso_step1 (s, urb_priv);
+			break;
+
+		case PIPE_BULK:
+		case PIPE_CONTROL:
+			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
+			uhci_clean_transfer (s, urb, qh, 0);
+			break;
+		}
+		((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
+	}		
+
+	return -EINPROGRESS;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_unlink_urb (urb_t *urb)
+{
+	uhci_t *s;
+	unsigned long flags=0;
+	dbg("uhci_unlink_urb called for %p",urb);
+	if (!urb || !urb->dev)		// you never know...
+		return -EINVAL;
+	
+	s = (uhci_t*) urb->dev->bus->hcpriv;
+
+	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
+		return rh_unlink_urb (urb);
+
+	if (!urb->hcpriv)
+		return -EINVAL;
+
+	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+		int ret;
+
+		spin_lock_irqsave (&s->urb_list_lock, flags);
+		ret = uhci_unlink_urb_async(s, urb);
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+		return ret;
+	}
+	else
+		return uhci_unlink_urb_sync(s, urb);
+}
+/*-------------------------------------------------------------------*/
+// In case of ASAP iso transfer, search the URB-list for already queued URBs
+// for this EP and calculate the earliest start frame for the new
+// URB (easy seamless URB continuation!)
+_static int find_iso_limits (urb_t *urb, unsigned int *start, unsigned int *end)
+{
+	urb_t *u, *last_urb = NULL;
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	struct list_head *p;
+	int ret=-1;
+	unsigned long flags;
+	
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+	p=s->urb_list.prev;
+
+	for (; p != &s->urb_list; p = p->prev) {
+		u = list_entry (p, urb_t, urb_list);
+		// look for pending URBs with identical pipe handle
+		// works only because iso doesn't toggle the data bit!
+		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) && (u->status == -EINPROGRESS)) {
+			if (!last_urb)
+				*start = u->start_frame;
+			last_urb = u;
+		}
+	}
+	
+	if (last_urb) {
+		*end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
+		ret=0;
+	}
+	
+	spin_unlock_irqrestore(&s->urb_list_lock, flags);
+	
+	return ret;
+}
+/*-------------------------------------------------------------------*/
+// adjust start_frame according to scheduling constraints (ASAP etc)
+
+_static int iso_find_start (urb_t *urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	unsigned int now;
+	unsigned int start_limit = 0, stop_limit = 0, queued_size;
+	int limits;
+
+	now = UHCI_GET_CURRENT_FRAME (s) & 1023;
+
+	if ((unsigned) urb->number_of_packets > 900)
+		return -EFBIG;
+	
+	limits = find_iso_limits (urb, &start_limit, &stop_limit);
+	queued_size = (stop_limit - start_limit) & 1023;
+
+	if (urb->transfer_flags & USB_ISO_ASAP) {
+		// first iso
+		if (limits) {
+			// 10ms setup should be enough //FIXME!
+			urb->start_frame = (now + 10) & 1023;
+		}
+		else {
+			urb->start_frame = stop_limit;		//seamless linkage
+
+			if (((now - urb->start_frame) & 1023) <= (unsigned) urb->number_of_packets) {
+				info("iso_find_start: gap in seamless isochronous scheduling");
+				dbg("iso_find_start: now %u start_frame %u number_of_packets %u pipe 0x%08x",
+					now, urb->start_frame, urb->number_of_packets, urb->pipe);
+				urb->start_frame = (now + 5) & 1023;	// 5ms setup should be enough //FIXME!
+			}
+		}
+	}
+	else {
+		urb->start_frame &= 1023;
+		if (((now - urb->start_frame) & 1023) < (unsigned) urb->number_of_packets) {
+			dbg("iso_find_start: now between start_frame and end");
+			return -EAGAIN;
+		}
+	}
+
+	/* check if either start_frame or start_frame+number_of_packets-1 lies between start_limit and stop_limit */
+	if (limits)
+		return 0;
+
+	if (((urb->start_frame - start_limit) & 1023) < queued_size ||
+	    ((urb->start_frame + urb->number_of_packets - 1 - start_limit) & 1023) < queued_size) {
+		dbg("iso_find_start: start_frame %u number_of_packets %u start_limit %u stop_limit %u",
+			urb->start_frame, urb->number_of_packets, start_limit, stop_limit);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+// submits USB interrupt (ie. polling ;-) 
+// ASAP-flag set implicitely
+// if period==0, the the transfer is only done once
+
+_static int uhci_submit_int_urb (urb_t *urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	int nint, n, ret;
+	uhci_desc_t *td;
+	int status, destination;
+	int info;
+	unsigned int pipe = urb->pipe;
+
+	if (urb->interval < 0 || urb->interval >= 256)
+		return -EINVAL;
+
+	if (urb->interval == 0)
+		nint = 0;
+	else {
+		for (nint = 0, n = 1; nint <= 8; nint++, n += n)	// round interval down to 2^n
+		 {
+			if (urb->interval < n) {
+				urb->interval = n / 2;
+				break;
+			}
+		}
+		nint--;
+	}
+
+	dbg("Rounded interval to %i, chain  %i", urb->interval, nint);
+
+	urb->start_frame = UHCI_GET_CURRENT_FRAME (s) & 1023;	// remember start frame, just in case...
+
+	urb->number_of_packets = 1;
+
+	// INT allows only one packet
+	if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)))
+		return -EINVAL;
+
+	ret = alloc_td (&td, UHCI_PTR_DEPTH);
+
+	if (ret)
+		return -ENOMEM;
+
+	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+		(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe) |
+		(((urb->transfer_buffer_length - 1) & 0x7ff) << 21);
+
+
+	info = destination | (usb_gettoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)) << TD_TOKEN_TOGGLE);
+
+	fill_td (td, status, info, virt_to_bus (urb->transfer_buffer));
+	list_add_tail (&td->desc_list, &urb_priv->desc_list);
+
+	urb->status = -EINPROGRESS;
+	queue_urb (s, urb);
+
+	insert_td_horizontal (s, s->int_chain[nint], td);	// store in INT-TDs
+
+	usb_dotoggle (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_iso_urb (urb_t *urb)
+{
+	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	int pipe=urb->pipe;
+	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+	int n, ret, last=0;
+	uhci_desc_t *td, **tdm;
+	int status, destination;
+	unsigned long flags;
+
+	__save_flags(flags);
+	__cli();		      // Disable IRQs to schedule all ISO-TDs in time
+	ret = iso_find_start (urb);	// adjusts urb->start_frame for later use
+	
+	if (ret)
+		goto err;
+
+	tdm = (uhci_desc_t **) kmalloc (urb->number_of_packets * sizeof (uhci_desc_t*), KMALLOC_FLAG);
+
+	if (!tdm) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	// First try to get all TDs
+	for (n = 0; n < urb->number_of_packets; n++) {
+		dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length);
+		if (!urb->iso_frame_desc[n].length) {
+			// allows ISO striping by setting length to zero in iso_descriptor
+			tdm[n] = 0;
+			continue;
+		}
+		
+		if(urb->iso_frame_desc[n].length > maxsze) {
+#ifdef ISO_SANITY_CHECK
+			err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
+			tdm[n] = 0;
+			ret=-EINVAL;
+			goto inval;
+#endif
+		}
+		
+		ret = alloc_td (&td, UHCI_PTR_DEPTH);
+	inval:
+		if (ret) {
+			int i;	// Cleanup allocated TDs
+
+			for (i = 0; i < n; n++)
+				if (tdm[i])
+					 delete_desc(tdm[i]);
+			kfree (tdm);
+			goto err;
+		}
+		last=n;
+		tdm[n] = td;
+	}
+
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;	//| (urb->transfer_flags&USB_DISABLE_SPD?0:TD_CTRL_SPD);
+
+	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe);
+
+	
+	// Queue all allocated TDs
+	for (n = 0; n < urb->number_of_packets; n++) {
+		td = tdm[n];
+		if (!td)
+			continue;
+			
+		if (n  == last)
+			status |= TD_CTRL_IOC;
+
+		fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
+			 virt_to_bus (urb->transfer_buffer + urb->iso_frame_desc[n].offset));
+		list_add_tail (&td->desc_list, &urb_priv->desc_list);
+	
+		if (n == last) {
+			urb->status = -EINPROGRESS;
+			queue_urb (s, urb);
+		}
+		insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td);	// store in iso-tds
+		//uhci_show_td(td);
+
+	}
+
+	kfree (tdm);
+	dbg("ISO-INT# %i, start %i, now %i", urb->number_of_packets, urb->start_frame, UHCI_GET_CURRENT_FRAME (s) & 1023);
+	ret = 0;
+
+      err:
+	__restore_flags(flags);
+	return ret;
+
+}
+/*-------------------------------------------------------------------*/
+// returns: 0 (no transfer queued), urb* (this urb already queued)
+ 
+_static urb_t* search_dev_ep (uhci_t *s, urb_t *urb)
+{
+	struct list_head *p;
+	urb_t *tmp;
+	unsigned int mask = usb_pipecontrol(urb->pipe) ? (~USB_DIR_IN) : (~0);
+
+	dbg("search_dev_ep:");
+
+	p=s->urb_list.next;
+
+	for (; p != &s->urb_list; p = p->next) {
+		tmp = list_entry (p, urb_t, urb_list);
+		dbg("urb: %p", tmp);
+		// we can accept this urb if it is not queued at this time 
+		// or if non-iso transfer requests should be scheduled for the same device and pipe
+		if ((!usb_pipeisoc(urb->pipe) && (tmp->dev == urb->dev) && !((tmp->pipe ^ urb->pipe) & mask)) ||
+		    (urb == tmp)) {
+			return tmp;	// found another urb already queued for processing
+		}
+	}
+
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+_static int uhci_submit_urb (urb_t *urb)
+{
+	uhci_t *s;
+	urb_priv_t *urb_priv;
+	int ret = 0;
+	unsigned long flags;
+	urb_t *bulk_urb=NULL;
+		
+	if (!urb->dev || !urb->dev->bus)
+		return -ENODEV;
+
+	s = (uhci_t*) urb->dev->bus->hcpriv;
+	//dbg("submit_urb: %p type %d",urb,usb_pipetype(urb->pipe));
+	
+	if (!s->running)
+		return -ENODEV;
+		
+	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
+		return rh_submit_urb (urb);	/* virtual root hub */
+
+	usb_inc_dev_use (urb->dev);
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+
+	bulk_urb = search_dev_ep (s, urb);
+
+	if (bulk_urb) {
+
+		queue_dbg("found bulk urb %p\n",bulk_urb);
+
+		if ((usb_pipetype (urb->pipe) != PIPE_BULK) ||
+		    ((usb_pipetype (urb->pipe) == PIPE_BULK) &&
+		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(bulk_urb->transfer_flags & USB_QUEUE_BULK)))) {
+			spin_unlock_irqrestore (&s->urb_list_lock, flags);
+			usb_dec_dev_use (urb->dev);
+			err("ENXIO %08x, flags %x, urb %p, burb %p",urb->pipe,urb->transfer_flags,urb,bulk_urb);
+			return -ENXIO;	// urb already queued
+		}
+	}
+
+#ifdef DEBUG_SLAB
+	urb_priv = kmem_cache_alloc(urb_priv_kmem, SLAB_FLAG);
+#else
+	urb_priv = kmalloc (sizeof (urb_priv_t), KMALLOC_FLAG);
+#endif
+	if (!urb_priv) {
+		usb_dec_dev_use (urb->dev);
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+		return -ENOMEM;
+	}
+
+	urb->hcpriv = urb_priv;
+	INIT_LIST_HEAD (&urb_priv->desc_list);
+	urb_priv->flags = 0;
+	dbg("submit_urb: scheduling %p", urb);
+	urb_priv->next_queued_urb = NULL;
+	urb_priv->prev_queued_urb = NULL;
+	urb_priv->bottom_qh = NULL;
+	urb_priv->next_qh = NULL;
+	
+	if (usb_pipetype (urb->pipe) == PIPE_BULK) {
+	
+		if (bulk_urb) {
+			while (((urb_priv_t*)bulk_urb->hcpriv)->next_queued_urb)  // find last queued bulk
+				bulk_urb=((urb_priv_t*)bulk_urb->hcpriv)->next_queued_urb;
+			
+			((urb_priv_t*)bulk_urb->hcpriv)->next_queued_urb=urb;
+		}
+		atomic_inc (&s->avoid_bulk);
+		ret = uhci_submit_bulk_urb (urb, bulk_urb);
+		atomic_dec (&s->avoid_bulk);
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+	}
+	else {
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+		switch (usb_pipetype (urb->pipe)) {
+		case PIPE_ISOCHRONOUS:
+			ret = uhci_submit_iso_urb (urb);
+			break;
+		case PIPE_INTERRUPT:
+			ret = uhci_submit_int_urb (urb);
+			break;
+		case PIPE_CONTROL:
+			ret = uhci_submit_control_urb (urb);
+			break;
+		default:
+			ret = -EINVAL;
+		}
+	}
+
+	dbg("submit_urb: scheduled with ret: %d", ret);
+	
+	if (ret != 0) {
+		usb_dec_dev_use (urb->dev);
+#ifdef DEBUG_SLAB
+		kmem_cache_free(urb_priv_kmem, urb_priv);
+#else
+		kfree (urb_priv);
+#endif
+		return ret;
+	}
+
+	return 0;
+}
+
+// Checks for URB timeout and removes bandwidth reclamation 
+// if URB idles too long
+_static void uhci_check_timeouts(uhci_t *s)
+{
+	struct list_head *p,*p2;
+	urb_t *urb;
+	int type;	
+
+	p = s->urb_list.prev;	
+
+	while (p != &s->urb_list) {
+		urb_priv_t *hcpriv;
+
+		p2 = p;
+		p = p->prev;
+		urb = list_entry (p2, urb_t, urb_list);
+		type = usb_pipetype (urb->pipe);
+
+		hcpriv = (urb_priv_t*)urb->hcpriv;
+				
+		if ( urb->timeout && 
+			((hcpriv->started + urb->timeout) < jiffies)) {
+			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
+			async_dbg("uhci_check_timeout: timeout for %p",urb);
+			uhci_unlink_urb_async(s, urb);
+		}
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
+		     (hcpriv->use_loop) &&
+		     ((hcpriv->started + IDLE_TIMEOUT) < jiffies))
+			disable_desc_loop(s, urb);
+#endif
+
+	}
+	s->timeout_check=jiffies;
+}
+
+/*-------------------------------------------------------------------
+ Virtual Root Hub
+ -------------------------------------------------------------------*/
+
+_static __u8 root_hub_dev_des[] =
+{
+	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x00,			/*  __u16 bcdUSB; v1.0 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x02,			/*  __u8  iProduct; */
+	0x01,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+_static __u8 root_hub_config_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes; 
+				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+     /* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+     /* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x08,			/*  __u16 ep_wMaxPacketSize; 8 Bytes */
+	0x00,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
+
+
+_static __u8 root_hub_hub_des[] =
+{
+	0x09,			/*  __u8  bLength; */
+	0x29,			/*  __u8  bDescriptorType; Hub-descriptor */
+	0x02,			/*  __u8  bNbrPorts; */
+	0x00,			/* __u16  wHubCharacteristics; */
+	0x00,
+	0x01,			/*  __u8  bPwrOn2pwrGood; 2ms */
+	0x00,			/*  __u8  bHubContrCurrent; 0 mA */
+	0x00,			/*  __u8  DeviceRemovable; *** 7 Ports max *** */
+	0xff			/*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/*-------------------------------------------------------------------------*/
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+_static int rh_send_irq (urb_t *urb)
+{
+	int len = 1;
+	int i;
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 data = 0;
+
+	for (i = 0; i < uhci->rh.numports; i++) {
+		data |= ((inw (io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
+		len = (i + 1) / 8 + 1;
+	}
+
+	*(__u16 *) urb->transfer_buffer = cpu_to_le16 (data);
+	urb->actual_length = len;
+	urb->status = 0;
+	
+	if ((data > 0) && (uhci->rh.send != 0)) {
+		dbg("Root-Hub INT complete: port1: %x port2: %x data: %x",
+		     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2), data);
+		urb->complete (urb);
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+_static int rh_init_int_timer (urb_t *urb);
+
+_static void rh_int_timer_do (unsigned long ptr)
+{
+	int len;
+	urb_t *urb = (urb_t*) ptr;
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+
+	if (uhci->rh.send) {
+		len = rh_send_irq (urb);
+		if (len > 0) {
+			urb->actual_length = len;
+			if (urb->complete)
+				urb->complete (urb);
+		}
+	}
+	rh_init_int_timer (urb);
+}
+
+/*-------------------------------------------------------------------------*/
+/* Root Hub INTs are polled by this timer, polling interval 20ms */
+/* This time is also used for URB-timeout checking */
+
+_static int rh_init_int_timer (urb_t *urb)
+{
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+
+	uhci->rh.interval = urb->interval;
+	init_timer (&uhci->rh.rh_int_timer);
+	uhci->rh.rh_int_timer.function = rh_int_timer_do;
+	uhci->rh.rh_int_timer.data = (unsigned long) urb;
+	uhci->rh.rh_int_timer.expires = jiffies + (HZ * 20) / 1000;
+	add_timer (&uhci->rh.rh_int_timer);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+#define OK(x) 			len = (x); break
+
+#define CLR_RH_PORTSTAT(x) \
+		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
+		status = (status & 0xfff5) & ~(x); \
+		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
+
+#define SET_RH_PORTSTAT(x) \
+		status = inw(io_addr+USBPORTSC1+2*(wIndex-1)); \
+		status = (status & 0xfff5) | (x); \
+		outw(status, io_addr+USBPORTSC1+2*(wIndex-1))
+
+
+/*-------------------------------------------------------------------------*/
+/****
+ ** Root Hub Control Pipe
+ *************************/
+
+
+_static int rh_submit_urb (urb_t *urb)
+{
+	struct usb_device *usb_dev = urb->dev;
+	uhci_t *uhci = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	devrequest *cmd = (devrequest *) urb->setup_packet;
+	void *data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = 0;
+	int stat = 0;
+	int i;
+	unsigned int io_addr = uhci->io_addr;
+	__u16 cstatus;
+
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+	if (usb_pipetype (pipe) == PIPE_INTERRUPT) {
+		dbg("Root-Hub submit IRQ: every %d ms", urb->interval);
+		uhci->rh.urb = urb;
+		uhci->rh.send = 1;
+		uhci->rh.interval = urb->interval;
+		rh_init_int_timer (urb);
+
+		return 0;
+	}
+
+
+	bmRType_bReq = cmd->requesttype | cmd->request << 8;
+	wValue = le16_to_cpu (cmd->value);
+	wIndex = le16_to_cpu (cmd->index);
+	wLength = le16_to_cpu (cmd->length);
+
+	for (i = 0; i < 8; i++)
+		uhci->rh.c_p_r[i] = 0;
+
+	dbg("Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x",
+	     uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+	switch (bmRType_bReq) {
+		/* Request Destination:
+		   without flags: Device, 
+		   RH_INTERFACE: interface, 
+		   RH_ENDPOINT: endpoint,
+		   RH_CLASS means HUB here, 
+		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+		 */
+
+	case RH_GET_STATUS:
+		*(__u16 *) data = cpu_to_le16 (1);
+		OK (2);
+	case RH_GET_STATUS | RH_INTERFACE:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+	case RH_GET_STATUS | RH_ENDPOINT:
+		*(__u16 *) data = cpu_to_le16 (0);
+		OK (2);
+	case RH_GET_STATUS | RH_CLASS:
+		*(__u32 *) data = cpu_to_le32 (0);
+		OK (4);		/* hub power ** */
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		status = inw (io_addr + USBPORTSC1 + 2 * (wIndex - 1));
+		cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
+			((status & USBPORTSC_PEC) >> (3 - 1)) |
+			(uhci->rh.c_p_r[wIndex - 1] << (0 + 4));
+		status = (status & USBPORTSC_CCS) |
+			((status & USBPORTSC_PE) >> (2 - 1)) |
+			((status & USBPORTSC_SUSP) >> (12 - 2)) |
+			((status & USBPORTSC_PR) >> (9 - 4)) |
+			(1 << 8) |	/* power on ** */
+			((status & USBPORTSC_LSDA) << (-8 + 9));
+
+		*(__u16 *) data = cpu_to_le16 (status);
+		*(__u16 *) (data + 2) = cpu_to_le16 (cstatus);
+		OK (4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+		case (RH_ENDPOINT_STALL):
+			OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+		case (RH_C_HUB_OVER_CURRENT):
+			OK (0);	/* hub power over current ** */
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_ENABLE):
+			CLR_RH_PORTSTAT (USBPORTSC_PE);
+			OK (0);
+		case (RH_PORT_SUSPEND):
+			CLR_RH_PORTSTAT (USBPORTSC_SUSP);
+			OK (0);
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_C_PORT_CONNECTION):
+			SET_RH_PORTSTAT (USBPORTSC_CSC);
+			OK (0);
+		case (RH_C_PORT_ENABLE):
+			SET_RH_PORTSTAT (USBPORTSC_PEC);
+			OK (0);
+		case (RH_C_PORT_SUSPEND):
+/*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+			OK (0);
+		case (RH_C_PORT_OVER_CURRENT):
+			OK (0);	/* port power over current ** */
+		case (RH_C_PORT_RESET):
+			uhci->rh.c_p_r[wIndex - 1] = 0;
+			OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+		case (RH_PORT_SUSPEND):
+			SET_RH_PORTSTAT (USBPORTSC_SUSP);
+			OK (0);
+		case (RH_PORT_RESET):
+			SET_RH_PORTSTAT (USBPORTSC_PR);
+			uhci_wait_ms (10);
+			uhci->rh.c_p_r[wIndex - 1] = 1;
+			CLR_RH_PORTSTAT (USBPORTSC_PR);
+			udelay (10);
+			SET_RH_PORTSTAT (USBPORTSC_PE);
+			uhci_wait_ms (10);
+			SET_RH_PORTSTAT (0xa);
+			OK (0);
+		case (RH_PORT_POWER):
+			OK (0);	/* port power ** */
+		case (RH_PORT_ENABLE):
+			SET_RH_PORTSTAT (USBPORTSC_PE);
+			OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS:
+		uhci->rh.devnum = wValue;
+		OK (0);
+
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+		case (0x01):	/* device descriptor */
+			len = min (leni, min (sizeof (root_hub_dev_des), wLength));
+			memcpy (data, root_hub_dev_des, len);
+			OK (len);
+		case (0x02):	/* configuration descriptor */
+			len = min (leni, min (sizeof (root_hub_config_des), wLength));
+			memcpy (data, root_hub_config_des, len);
+			OK (len);
+		case (0x03):	/* string descriptors */
+			len = usb_root_hub_string (wValue & 0xff,
+			        uhci->io_addr, "UHCI",
+				data, wLength);
+			if (len > 0) {
+				OK (min (leni, len));
+			} else 
+				stat = -EPIPE;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		root_hub_hub_des[2] = uhci->rh.numports;
+		len = min (leni, min (sizeof (root_hub_hub_des), wLength));
+		memcpy (data, root_hub_hub_des, len);
+		OK (len);
+
+	case RH_GET_CONFIGURATION:
+		*(__u8 *) data = 0x01;
+		OK (1);
+
+	case RH_SET_CONFIGURATION:
+		OK (0);
+	default:
+		stat = -EPIPE;
+	}
+
+	dbg("Root-Hub stat port1: %x port2: %x",
+	     inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
+
+	urb->actual_length = len;
+	urb->status = stat;
+	if (urb->complete)
+		urb->complete (urb);
+	return 0;
+}
+/*-------------------------------------------------------------------------*/
+
+_static int rh_unlink_urb (urb_t *urb)
+{
+	uhci_t *uhci = urb->dev->bus->hcpriv;
+
+	if (uhci->rh.urb==urb) {
+		dbg("Root-Hub unlink IRQ");
+		uhci->rh.send = 0;
+		del_timer (&uhci->rh.rh_int_timer);
+	}
+	return 0;
+}
+/*-------------------------------------------------------------------*/
+
+/*
+ * Map status to standard result codes
+ *
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
+ * <dir_out> is True for output TDs and False for input TDs.
+ */
+_static int uhci_map_status (int status, int dir_out)
+{
+	if (!status)
+		return 0;
+	if (status & TD_CTRL_BITSTUFF)	/* Bitstuff error */
+		return -EPROTO;
+	if (status & TD_CTRL_CRCTIMEO) {	/* CRC/Timeout */
+		if (dir_out)
+			return -ETIMEDOUT;
+		else
+			return -EILSEQ;
+	}
+	if (status & TD_CTRL_NAK)	/* NAK */
+		return -ETIMEDOUT;
+	if (status & TD_CTRL_BABBLE)	/* Babble */
+		return -EPIPE;
+	if (status & TD_CTRL_DBUFERR)	/* Buffer error */
+		return -ENOSR;
+	if (status & TD_CTRL_STALLED)	/* Stalled */
+		return -EPIPE;
+	if (status & TD_CTRL_ACTIVE)	/* Active */
+		return 0;
+
+	return -EPROTO;
+}
+
+/*
+ * Only the USB core should call uhci_alloc_dev and uhci_free_dev
+ */
+_static int uhci_alloc_dev (struct usb_device *usb_dev)
+{
+	return 0;
+}
+
+_static void uhci_unlink_urbs(uhci_t *s, struct usb_device *usb_dev, int remove_all)
+{
+	unsigned long flags;
+	struct list_head *p;
+	struct list_head *p2;
+	urb_t *urb;
+
+	spin_lock_irqsave (&s->urb_list_lock, flags);
+	p = s->urb_list.prev;	
+	while (p != &s->urb_list) {
+		p2 = p;
+		p = p->prev ;
+		urb = list_entry (p2, urb_t, urb_list);
+		dbg("urb: %p, dev %p, %p", urb, usb_dev,urb->dev);
+		
+		//urb->transfer_flags |=USB_ASYNC_UNLINK; 
+			
+		if (remove_all || (usb_dev == urb->dev)) {
+			spin_unlock_irqrestore (&s->urb_list_lock, flags);
+			warn("forced removing of queued URB %p due to disconnect",urb);
+			uhci_unlink_urb(urb);
+			urb->dev = NULL; // avoid further processing of this UR
+			spin_lock_irqsave (&s->urb_list_lock, flags);
+			p = s->urb_list.prev;	
+		}
+	}
+	spin_unlock_irqrestore (&s->urb_list_lock, flags);
+}
+
+_static int uhci_free_dev (struct usb_device *usb_dev)
+{
+	uhci_t *s;
+	
+
+	if(!usb_dev || !usb_dev->bus || !usb_dev->bus->hcpriv)
+		return -EINVAL;
+	
+	s=(uhci_t*) usb_dev->bus->hcpriv;	
+	uhci_unlink_urbs(s, usb_dev, 0);
+
+	return 0;
+}
+
+/*
+ * uhci_get_current_frame_number()
+ *
+ * returns the current frame number for a USB bus/controller.
+ */
+_static int uhci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	return UHCI_GET_CURRENT_FRAME ((uhci_t*) usb_dev->bus->hcpriv);
+}
+
+struct usb_operations uhci_device_operations =
+{
+	uhci_alloc_dev,
+	uhci_free_dev,
+	uhci_get_current_frame_number,
+	uhci_submit_urb,
+	uhci_unlink_urb
+};
+
+/* 
+ * For IN-control transfers, process_transfer gets a bit more complicated,
+ * since there are devices that return less data (eg. strings) than they
+ * have announced. This leads to a queue abort due to the short packet,
+ * the status stage is not executed. If this happens, the status stage
+ * is manually re-executed.
+ * mode: 0: QHs already unlinked
+ */
+
+_static int process_transfer (uhci_t *s, urb_t *urb, int mode)
+{
+	int ret = 0;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	struct list_head *qhl = urb_priv->desc_list.next;
+	uhci_desc_t *qh = list_entry (qhl, uhci_desc_t, desc_list);
+	struct list_head *p = qh->vertical.next;
+	uhci_desc_t *desc= list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
+	uhci_desc_t *last_desc = list_entry (desc->vertical.prev, uhci_desc_t, vertical);
+	int data_toggle = usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));	// save initial data_toggle
+	int maxlength; 	// extracted and remapped info from TD
+	int actual_length;
+	int status = 0;
+
+	//dbg("process_transfer: urb contains bulk/control request");
+
+	/* if the status phase has been retriggered and the
+	   queue is empty or the last status-TD is inactive, the retriggered
+	   status stage is completed
+	 */
+
+	if (urb_priv->flags && 
+		((qh->hw.qh.element == UHCI_PTR_TERM) ||(!(last_desc->hw.td.status & TD_CTRL_ACTIVE)))) 
+		goto transfer_finished;
+
+	urb->actual_length=0;
+
+	for (; p != &qh->vertical; p = p->next) {
+		desc = list_entry (p, uhci_desc_t, vertical);
+
+		if (desc->hw.td.status & TD_CTRL_ACTIVE)	// do not process active TDs
+			return ret;
+	
+		actual_length = (desc->hw.td.status + 1) & 0x7ff;		// extract transfer parameters from TD
+		maxlength = (((desc->hw.td.info >> 21) & 0x7ff) + 1) & 0x7ff;
+		status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (urb->pipe));
+
+		if (status == -EPIPE) { 		// see if EP is stalled
+			// set up stalled condition
+			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+		}
+
+		if (status != 0) {		// if any error occured stop processing of further TDs
+			// only set ret if status returned an error
+			if (status != -EPIPE) 
+				uhci_show_td (desc);
+			ret = status;
+			urb->error_count++;
+			break;
+		}
+		else if ((desc->hw.td.info & 0xff) != USB_PID_SETUP)
+			urb->actual_length += actual_length;
+
+		// got less data than requested
+		if ( (actual_length < maxlength)) {
+			if (urb->transfer_flags & USB_DISABLE_SPD) {
+				status = -EREMOTEIO;	// treat as real error
+				dbg("process_transfer: SPD!!");
+				break;	// exit after this TD because SP was detected
+			}
+
+			// short read during control-IN: re-start status stage
+			if ((usb_pipetype (urb->pipe) == PIPE_CONTROL)) {
+				if (uhci_packetid(last_desc->hw.td.info) == USB_PID_OUT) {
+			
+					qh->hw.qh.element = virt_to_bus (last_desc);  // re-trigger status stage
+					dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
+					//uhci_show_td (desc);
+					//uhci_show_td (last_desc);
+					urb_priv->flags = 1; // mark as short control packet
+					return 0;
+				}
+			}
+			// all other cases: short read is OK
+			data_toggle = uhci_toggle (desc->hw.td.info);
+			break;
+		}
+
+		data_toggle = uhci_toggle (desc->hw.td.info);
+		queue_dbg("process_transfer: len:%d status:%x mapped:%x toggle:%d", actual_length, desc->hw.td.status,status, data_toggle);      
+
+	}
+
+	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle);
+
+ transfer_finished:
+	
+	uhci_clean_transfer(s, urb, qh, (mode==0?2:1));
+
+	urb->status = status;
+
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH	
+	disable_desc_loop(s,urb);
+#endif	
+
+	queue_dbg("process_transfer: (end) urb %p, wanted len %d, len %d status %x err %d",
+		urb,urb->transfer_buffer_length,urb->actual_length, urb->status, urb->error_count);
+	return ret;
+}
+
+_static int process_interrupt (uhci_t *s, urb_t *urb)
+{
+	int i, ret = -EINPROGRESS;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	struct list_head *p = urb_priv->desc_list.next;
+	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
+
+	int actual_length;
+	int status = 0;
+
+	//dbg("urb contains interrupt request");
+
+	for (i = 0; p != &urb_priv->desc_list; p = p->next, i++)	// Maybe we allow more than one TD later ;-)
+	{
+		desc = list_entry (p, uhci_desc_t, desc_list);
+
+		if (desc->hw.td.status & TD_CTRL_ACTIVE) {
+			// do not process active TDs
+			//dbg("TD ACT Status @%p %08x",desc,desc->hw.td.status);
+			break;
+		}
+
+		if (!desc->hw.td.status & TD_CTRL_IOC) {
+			// do not process one-shot TDs, no recycling
+			break;
+		}
+		// extract transfer parameters from TD
+
+		actual_length = (desc->hw.td.status + 1) & 0x7ff;
+		status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (urb->pipe));
+
+		// see if EP is stalled
+		if (status == -EPIPE) {
+			// set up stalled condition
+			usb_endpoint_halt (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+		}
+
+		// if any error occured: ignore this td, and continue
+		if (status != 0) {
+			//uhci_show_td (desc);
+			urb->error_count++;
+			goto recycle;
+		}
+		else
+			urb->actual_length = actual_length;
+
+	recycle:
+		if (urb->complete) {
+			//dbg("process_interrupt: calling completion, status %i",status);
+			urb->status = status;
+			((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is called during completion
+
+			spin_unlock(&s->urb_list_lock);
+			
+			urb->complete ((struct urb *) urb);
+			
+			spin_lock(&s->urb_list_lock);
+
+			((urb_priv_t*)urb->hcpriv)->flags=0;		       			
+		}
+		
+		if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
+			    (urb->status != -ENOENT)) {
+
+			urb->status = -EINPROGRESS;
+
+			// Recycle INT-TD if interval!=0, else mark TD as one-shot
+			if (urb->interval) {
+				
+				desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE);
+				if (status==0) {
+					((urb_priv_t*)urb->hcpriv)->started=jiffies;
+					desc->hw.td.info |= (usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+									    usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+					usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+				} else {
+					desc->hw.td.info |= (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe),
+									     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+				}
+				desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
+					(urb->transfer_flags & USB_DISABLE_SPD ? 0 : TD_CTRL_SPD) | (3 << 27);
+				mb();
+			}
+			else {
+				uhci_unlink_urb_async(s, urb);
+				desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
+			}
+		}
+	}
+
+	return ret;
+}
+
+// mode: 1: force processing, don't unlink tds (already unlinked)
+_static int process_iso (uhci_t *s, urb_t *urb, int mode)
+{
+	int i;
+	int ret = 0;
+	urb_priv_t *urb_priv = urb->hcpriv;
+	struct list_head *p = urb_priv->desc_list.next;
+	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
+
+	dbg("urb contains iso request");
+	if ((desc->hw.td.status & TD_CTRL_ACTIVE) && !mode)
+		return -EXDEV;	// last TD not finished
+
+	urb->error_count = 0;
+	urb->actual_length = 0;
+	urb->status = 0;
+	dbg("process iso urb %p, %li, %i, %i, %i %08x",urb,jiffies,UHCI_GET_CURRENT_FRAME(s),
+	    urb->number_of_packets,mode,desc->hw.td.status);
+
+	for (i = 0; p != &urb_priv->desc_list;  i++) {
+		desc = list_entry (p, uhci_desc_t, desc_list);
+		
+		//uhci_show_td(desc);
+		if (desc->hw.td.status & TD_CTRL_ACTIVE) {
+			// means we have completed the last TD, but not the TDs before
+			desc->hw.td.status &= ~TD_CTRL_ACTIVE;
+			dbg("TD still active (%x)- grrr. paranoia!", desc->hw.td.status);
+			ret = -EXDEV;
+			urb->iso_frame_desc[i].status = ret;
+			unlink_td (s, desc, 1);
+			// FIXME: immediate deletion may be dangerous
+			goto err;
+		}
+
+		if (!mode)
+			unlink_td (s, desc, 1);
+
+		if (urb->number_of_packets <= i) {
+			dbg("urb->number_of_packets (%d)<=(%d)", urb->number_of_packets, i);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (urb->iso_frame_desc[i].offset + urb->transfer_buffer != bus_to_virt (desc->hw.td.buffer)) {
+			// Hm, something really weird is going on
+			dbg("Pointer Paranoia: %p!=%p", urb->iso_frame_desc[i].offset + urb->transfer_buffer, bus_to_virt (desc->hw.td.buffer));
+			ret = -EINVAL;
+			urb->iso_frame_desc[i].status = ret;
+			goto err;
+		}
+		urb->iso_frame_desc[i].actual_length = (desc->hw.td.status + 1) & 0x7ff;
+		urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (desc->hw.td.status), usb_pipeout (urb->pipe));
+		urb->actual_length += urb->iso_frame_desc[i].actual_length;
+
+	      err:
+
+		if (urb->iso_frame_desc[i].status != 0) {
+			urb->error_count++;
+			urb->status = urb->iso_frame_desc[i].status;
+		}
+		dbg("process_iso: %i: len:%d %08x status:%x",
+		     i, urb->iso_frame_desc[i].actual_length, desc->hw.td.status,urb->iso_frame_desc[i].status);
+
+		list_del (p);
+		p = p->next;
+		delete_desc (desc);
+	}
+	
+	dbg("process_iso: exit %i (%d), actual_len %i", i, ret,urb->actual_length);
+	return ret;
+}
+
+
+_static int process_urb (uhci_t *s, struct list_head *p)
+{
+	int ret = 0;
+	urb_t *urb;
+
+
+	urb=list_entry (p, urb_t, urb_list);
+	//dbg("process_urb: found queued urb: %p", urb);
+
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+		ret = process_transfer (s, urb, 1);
+		break;
+	case PIPE_BULK:
+		if (!s->avoid_bulk.counter)
+			ret = process_transfer (s, urb, 1);
+		else
+			return 0;
+		break;
+	case PIPE_ISOCHRONOUS:
+		ret = process_iso (s, urb, 0);
+		break;
+	case PIPE_INTERRUPT:
+		ret = process_interrupt (s, urb);
+		break;
+	}
+
+	if (urb->status != -EINPROGRESS) {
+		int proceed = 0;
+
+		dbg("dequeued urb: %p", urb);
+		dequeue_urb (s, urb);
+
+#ifdef DEBUG_SLAB
+		kmem_cache_free(urb_priv_kmem, urb->hcpriv);
+#else
+		kfree (urb->hcpriv);
+#endif
+
+		if ((usb_pipetype (urb->pipe) != PIPE_INTERRUPT)) {
+			urb_t *tmp = urb->next;	// pointer to first urb
+			int is_ring = 0;
+			
+			if (urb->next) {
+				do {
+					if (tmp->status != -EINPROGRESS) {
+						proceed = 1;
+						break;
+					}
+					tmp = tmp->next;
+				}
+				while (tmp != NULL && tmp != urb->next);
+				if (tmp == urb->next)
+					is_ring = 1;
+			}
+
+			spin_unlock(&s->urb_list_lock);
+
+			// In case you need the current URB status for your completion handler
+			if (urb->complete && (!proceed || (urb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
+				dbg("process_transfer: calling early completion");
+				urb->complete ((struct urb *) urb);
+				if (!proceed && is_ring && (urb->status != -ENOENT))
+					uhci_submit_urb (urb);
+			}
+
+			if (proceed && urb->next) {
+				// if there are linked urbs - handle submitting of them right now.
+				tmp = urb->next;	// pointer to first urb
+
+				do {
+					if ((tmp->status != -EINPROGRESS) && (tmp->status != -ENOENT) && uhci_submit_urb (tmp) != 0)
+						break;
+					tmp = tmp->next;
+				}
+				while (tmp != NULL && tmp != urb->next);	// submit until we reach NULL or our own pointer or submit fails
+
+				if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE)) {
+					dbg("process_transfer: calling completion");
+					urb->complete ((struct urb *) urb);
+				}
+			}
+
+			spin_lock(&s->urb_list_lock);
+
+			usb_dec_dev_use (urb->dev);
+		}
+	}
+
+	return ret;
+}
+
+_static void uhci_interrupt (int irq, void *__uhci, struct pt_regs *regs)
+{
+	uhci_t *s = __uhci;
+	unsigned int io_addr = s->io_addr;
+	unsigned short status;
+	struct list_head *p, *p2;
+
+	/*
+	 * Read the interrupt status, and write it back to clear the
+	 * interrupt cause
+	 */
+
+	status = inw (io_addr + USBSTS);
+
+	if (!status)		/* shared interrupt, not mine */
+		return;
+
+	dbg("interrupt");
+
+	if (status != 1) {
+		/* warn("interrupt, status %x, frame# %i", status, 
+		     UHCI_GET_CURRENT_FRAME(s)); */
+
+		// remove host controller halted state
+		if ((status&0x20) && (s->running)) {
+			outw (USBCMD_RS | inw(io_addr + USBCMD), io_addr + USBCMD);
+		}
+		//uhci_show_status (s);
+	}
+	/*
+	 * traverse the list in *reverse* direction, because new entries
+	 * may be added at the end.
+	 * also, because process_urb may unlink the current urb,
+	 * we need to advance the list before
+	 */
+
+	spin_lock (&s->urb_list_lock);
+restart:
+	s->unlink_urb_done=0;
+	p = s->urb_list.prev;	
+
+	while (p != &s->urb_list) {
+		p2 = p;
+		p = p->prev;
+		process_urb (s, p2);
+		if (s->unlink_urb_done) {
+			s->unlink_urb_done=0;
+			goto restart;
+		}
+	}
+	if ((jiffies - s->timeout_check) > (HZ/30)) 
+		uhci_check_timeouts(s);
+
+	clean_descs(s,0);
+	uhci_cleanup_unlink(s, 0);
+	uhci_switch_timer_int(s);
+							
+	spin_unlock (&s->urb_list_lock);
+	
+	outw (status, io_addr + USBSTS);
+
+	//dbg("uhci_interrupt: done");
+}
+
+_static void reset_hc (uhci_t *s)
+{
+	unsigned int io_addr = s->io_addr;
+
+	s->apm_state = 0;
+	/* Global reset for 50ms */
+	outw (USBCMD_GRESET, io_addr + USBCMD);
+	uhci_wait_ms (50);
+	outw (0, io_addr + USBCMD);
+	uhci_wait_ms (10);
+}
+
+_static void start_hc (uhci_t *s)
+{
+	unsigned int io_addr = s->io_addr;
+	int timeout = 1000;
+
+	/*
+	 * Reset the HC - this will force us to get a
+	 * new notification of any already connected
+	 * ports due to the virtual disconnect that it
+	 * implies.
+	 */
+	outw (USBCMD_HCRESET, io_addr + USBCMD);
+
+	while (inw (io_addr + USBCMD) & USBCMD_HCRESET) {
+		if (!--timeout) {
+			err("USBCMD_HCRESET timed out!");
+			break;
+		}
+	}
+
+	/* Turn on all interrupts */
+	outw (USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+
+	/* Start at frame 0 */
+	outw (0, io_addr + USBFRNUM);
+	outl (virt_to_bus (s->framelist), io_addr + USBFLBASEADD);
+
+	/* Run and mark it configured with a 64-byte max packet */
+	outw (USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
+	s->apm_state = 1;
+	s->running = 1;
+}
+
+_static void uhci_cleanup_dev(uhci_t *s)
+{
+	struct usb_device *root_hub = s->bus->root_hub;
+
+	s->running = 0;		    // Don't allow submit_urb
+
+	if (root_hub)
+		usb_disconnect (&root_hub);
+
+	reset_hc (s);
+	wait_ms (1);
+
+	uhci_unlink_urbs (s, 0, 1);  // Forced unlink of remaining URBs
+	uhci_cleanup_unlink (s, 1);  // force cleanup of async killed URBs
+	
+	usb_deregister_bus (s->bus);
+
+	release_region (s->io_addr, s->io_size);
+	free_irq (s->irq, s);
+	usb_free_bus (s->bus);
+	cleanup_skel (s);
+	kfree (s);
+}
+
+_static int __init uhci_start_usb (uhci_t *s)
+{				/* start it up */
+	/* connect the virtual root hub */
+	struct usb_device *usb_dev;
+
+	usb_dev = usb_alloc_dev (NULL, s->bus);
+	if (!usb_dev)
+		return -1;
+
+	s->bus->root_hub = usb_dev;
+	usb_connect (usb_dev);
+
+	if (usb_new_device (usb_dev) != 0) {
+		usb_free_dev (usb_dev);
+		return -1;
+	}
+
+	return 0;
+}
+
+_static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data)
+{
+	uhci_t *s = (uhci_t*) dev->data;
+	dbg("handle_apm_event(%d)", rqst);
+	if (s) {
+		switch (rqst) {
+		case PM_SUSPEND:
+			reset_hc (s);
+			break;
+		case PM_RESUME:
+			start_hc (s);
+			break;
+		}
+	}
+	return 0;
+}
+
+_static int __init alloc_uhci (struct pci_dev *dev, int irq, unsigned int io_addr, unsigned int io_size)
+{
+	uhci_t *s;
+	struct usb_bus *bus;
+	struct pm_dev *pmdev;
+	char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+	sprintf(buf, "%d", irq);
+#else
+	bufp = __irq_itoa(irq);
+#endif
+	printk(KERN_INFO __FILE__ ": USB UHCI at I/O 0x%x, IRQ %s\n",
+		io_addr, bufp);
+
+	s = kmalloc (sizeof (uhci_t), GFP_KERNEL);
+	if (!s)
+		return -1;
+
+	memset (s, 0, sizeof (uhci_t));
+	INIT_LIST_HEAD (&s->free_desc);
+	INIT_LIST_HEAD (&s->urb_list);
+	INIT_LIST_HEAD (&s->urb_unlinked);
+	spin_lock_init (&s->urb_list_lock);
+	spin_lock_init (&s->qh_lock);
+	spin_lock_init (&s->td_lock);
+	atomic_set(&s->avoid_bulk, 0);
+	s->timeout_urbs = 0;	
+	s->irq = -1;
+	s->io_addr = io_addr;
+	s->io_size = io_size;
+	s->next = devs;	//chain new uhci device into global list	
+	s->timeout_check = 0;
+	s->uhci_pci=dev;
+
+	bus = usb_alloc_bus (&uhci_device_operations);
+	if (!bus) {
+		kfree (s);
+		return -1;
+	}
+
+	s->bus = bus;
+	bus->hcpriv = s;
+
+	/* UHCI specs says devices must have 2 ports, but goes on to say */
+	/* they may have more but give no way to determine how many they */
+	/* have, so default to 2 */
+	/* According to the UHCI spec, Bit 7 is always set to 1. So we try */
+	/* to use this to our advantage */
+
+	for (s->maxports = 0; s->maxports < (io_size - 0x10) / 2; s->maxports++) {
+		unsigned int portstatus;
+
+		portstatus = inw (io_addr + 0x10 + (s->maxports * 2));
+		dbg("port %i, adr %x status %x", s->maxports,
+			io_addr + 0x10 + (s->maxports * 2), portstatus);
+		if (!(portstatus & 0x0080))
+			break;
+	}
+	warn("Detected %d ports", s->maxports);
+
+	/* This is experimental so anything less than 2 or greater than 8 is */
+	/*  something weird and we'll ignore it */
+	if (s->maxports < 2 || s->maxports > 8) {
+		dbg("Port count misdetected, forcing to 2 ports");
+		s->maxports = 2;
+	}
+
+	s->rh.numports = s->maxports;
+	s->loop_usage=0;
+	if (init_skel (s)) {
+		usb_free_bus (bus);
+		kfree(s);
+		return -1;
+	}
+
+	request_region (s->io_addr, io_size, MODNAME);
+	reset_hc (s);
+	usb_register_bus (s->bus);
+
+	start_hc (s);
+
+	if (request_irq (irq, uhci_interrupt, SA_SHIRQ, MODNAME, s)) {
+		err("request_irq %d failed!",irq);
+		usb_free_bus (bus);
+		reset_hc (s);
+		release_region (s->io_addr, s->io_size);
+		cleanup_skel(s);
+		kfree(s);
+		return -1;
+	}
+
+	s->irq = irq;
+
+	if(uhci_start_usb (s) < 0) {
+		uhci_cleanup_dev(s);
+		return -1;
+	}
+
+	//chain new uhci device into global list
+	devs = s;
+
+	pmdev = pm_register(PM_PCI_DEV, PM_PCI_ID(dev), handle_pm_event);
+	if (pmdev)
+		pmdev->data = s;
+
+	return 0;
+}
+
+_static int __init start_uhci (struct pci_dev *dev)
+{
+	int i;
+
+	/* Search for the IO base address.. */
+	for (i = 0; i < 6; i++) {
+
+		unsigned int io_addr = dev->base_address[i];
+		unsigned int io_size = 0x14;
+		if (!(io_addr & 1))
+			continue;
+		io_addr &= ~1;
+
+		/* Is it already in use? */
+		if (check_region (io_addr, io_size))
+			break;
+		/* disable legacy emulation */
+		pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+		if(dev->vendor==0x8086) {
+			info("Intel USB controller: setting latency timer to %d", UHCI_LATENCY_TIMER);
+			pci_write_config_byte(dev, PCI_LATENCY_TIMER, UHCI_LATENCY_TIMER);
+		}
+	
+		return alloc_uhci(dev, dev->irq, io_addr, io_size);
+	}
+	return -1;
+}
+
+int __init uhci_init (void)
+{
+	int retval = -ENODEV;
+	struct pci_dev *dev = NULL;
+	u8 type;
+	int i=0;
+
+#ifdef DEBUG_SLAB
+
+	uhci_desc_kmem = kmem_cache_create("uhci_desc", sizeof(uhci_desc_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	
+	if(!uhci_desc_kmem) {
+		err("kmem_cache_create for uhci_desc failed (out of memory)");
+		return -ENOMEM;
+	}
+
+	urb_priv_kmem = kmem_cache_create("urb_priv", sizeof(urb_priv_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	
+	if(!urb_priv_kmem) {
+		err("kmem_cache_create for urb_priv_t failed (out of memory)");
+		kmem_cache_destroy(urb_priv_kmem);
+		return -ENOMEM;
+	}
+#endif	
+	info(VERSTR);
+
+#ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
+	info("High bandwidth mode enabled");	
+#endif
+	for (;;) {
+		dev = pci_find_class (PCI_CLASS_SERIAL_USB << 8, dev);
+		if (!dev)
+			break;
+
+		/* Is it UHCI */
+		pci_read_config_byte (dev, PCI_CLASS_PROG, &type);
+		if (type != 0)
+			continue;
+
+		if (pci_enable_device (dev) < 0)
+			continue;
+
+		if(!dev->irq)
+		{
+			err("Found UHCI device with no IRQ assigned. Check BIOS settings!");
+			continue;
+		}
+
+		/* Ok set it up */
+		retval = start_uhci (dev);
+	
+		if (!retval)
+			i++;
+	}
+
+#ifdef DEBUG_SLAB
+	if (retval < 0 ) {
+		if(kmem_cache_destroy(uhci_desc_kmem))
+			err("uhci_desc_kmem remained");
+		if(kmem_cache_destroy(urb_priv_kmem))
+			err("urb_priv_kmem remained");
+	}
+#endif
+	
+	return retval;
+}
+
+void __exit uhci_cleanup (void)
+{
+	uhci_t *s;
+	while ((s = devs)) {
+		devs = devs->next;
+		uhci_cleanup_dev(s);
+	}
+#ifdef DEBUG_SLAB
+	if(kmem_cache_destroy(uhci_desc_kmem))
+		err("uhci_desc_kmem remained");
+
+	if(kmem_cache_destroy(urb_priv_kmem))
+		err("urb_priv_kmem remained");
+#endif
+}
+
+#ifdef MODULE
+int init_module (void)
+{
+	return uhci_init ();
+}
+
+void cleanup_module (void)
+{
+	pm_unregister_all (handle_pm_event);
+	uhci_cleanup ();
+}
+
+#endif //MODULE
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb-uhci.h linux.18p8/drivers/usb/usb-uhci.h
--- linux.vanilla/drivers/usb/usb-uhci.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usb-uhci.h	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,282 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+/*
+   $Id: usb-uhci.h,v 1.55 2000/05/13 12:50:30 acher Exp $
+ */
+#define MODNAME "usb-uhci"
+#define UHCI_LATENCY_TIMER 0
+
+static __inline__ void uhci_wait_ms(unsigned int ms)
+{
+	if(!in_interrupt())
+	{
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(1 + ms * HZ / 1000);
+	}
+	else
+		mdelay(ms);
+}
+
+/* Command register */
+#define USBCMD		0
+#define   USBCMD_RS		0x0001	/* Run/Stop */
+#define   USBCMD_HCRESET	0x0002	/* Host reset */
+#define   USBCMD_GRESET		0x0004	/* Global reset */
+#define   USBCMD_EGSM		0x0008	/* Global Suspend Mode */
+#define   USBCMD_FGR		0x0010	/* Force Global Resume */
+#define   USBCMD_SWDBG		0x0020	/* SW Debug mode */
+#define   USBCMD_CF		0x0040	/* Config Flag (sw only) */
+#define   USBCMD_MAXP		0x0080	/* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS		2
+#define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
+#define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
+#define   USBSTS_RD		0x0004	/* Resume Detect */
+#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
+#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HCH		0x0020	/* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR		4
+#define   USBINTR_TIMEOUT	0x0001	/* Timeout/CRC error enable */
+#define   USBINTR_RESUME	0x0002	/* Resume interrupt enable */
+#define   USBINTR_IOC		0x0004	/* Interrupt On Complete enable */
+#define   USBINTR_SP		0x0008	/* Short packet interrupt enable */
+
+#define USBFRNUM	6
+#define USBFLBASEADD	8
+#define USBSOF		12
+
+/* USB port status and control registers */
+#define USBPORTSC1	16
+#define USBPORTSC2	18
+#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
+#define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
+#define   USBPORTSC_PE		0x0004	/* Port Enable */
+#define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
+#define   USBPORTSC_LS		0x0030	/* Line Status */
+#define   USBPORTSC_RD		0x0040	/* Resume Detect */
+#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
+#define   USBPORTSC_PR		0x0200	/* Port Reset */
+#define   USBPORTSC_SUSP	0x1000	/* Suspend */
+
+/* Legacy support register */
+#define USBLEGSUP 0xc0
+#define USBLEGSUP_DEFAULT 0x2000	/* only PIRQ enable set */
+
+#define UHCI_NULL_DATA_SIZE	0x7ff	/* for UHCI controller TD */
+#define UHCI_PID 		0xff	/* PID MASK */
+
+#define UHCI_PTR_BITS		0x000F
+#define UHCI_PTR_TERM		0x0001
+#define UHCI_PTR_QH		0x0002
+#define UHCI_PTR_DEPTH		0x0004
+
+#define UHCI_NUMFRAMES		1024	/* in the frame list [array] */
+#define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
+
+/*
+ * for TD <status>:
+ */
+#define TD_CTRL_SPD		(1 << 29)	/* Short Packet Detect */
+#define TD_CTRL_C_ERR_MASK	(3 << 27)	/* Error Counter bits */
+#define TD_CTRL_LS		(1 << 26)	/* Low Speed Device */
+#define TD_CTRL_IOS		(1 << 25)	/* Isochronous Select */
+#define TD_CTRL_IOC		(1 << 24)	/* Interrupt on Complete */
+#define TD_CTRL_ACTIVE		(1 << 23)	/* TD Active */
+#define TD_CTRL_STALLED		(1 << 22)	/* TD Stalled */
+#define TD_CTRL_DBUFERR		(1 << 21)	/* Data Buffer Error */
+#define TD_CTRL_BABBLE		(1 << 20)	/* Babble Detected */
+#define TD_CTRL_NAK		(1 << 19)	/* NAK Received */
+#define TD_CTRL_CRCTIMEO	(1 << 18)	/* CRC/Time Out Error */
+#define TD_CTRL_BITSTUFF	(1 << 17)	/* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK	0x7ff	/* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR	(TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+				 TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define uhci_status_bits(ctrl_sts)	(ctrl_sts & 0xFE0000)
+#define uhci_actual_length(ctrl_sts)	((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK)	/* 1-based */
+#define uhci_ptr_to_virt(x)	bus_to_virt(x & ~UHCI_PTR_BITS)
+
+/*
+ * for TD <flags>:
+ */
+#define UHCI_TD_REMOVE		0x0001	/* Remove when done */
+
+/*
+ * for TD <info>: (a.k.a. Token)
+ */
+#define TD_TOKEN_TOGGLE		19
+
+#define uhci_maxlen(token)	((token) >> 21)
+#define uhci_toggle(token)	(((token) >> TD_TOKEN_TOGGLE) & 1)
+#define uhci_endpoint(token)	(((token) >> 15) & 0xf)
+#define uhci_devaddr(token)	(((token) >> 8) & 0x7f)
+#define uhci_devep(token)	(((token) >> 8) & 0x7ff)
+#define uhci_packetid(token)	((token) & 0xff)
+#define uhci_packetout(token)	(uhci_packetid(token) != USB_PID_IN)
+#define uhci_packetin(token)	(uhci_packetid(token) == USB_PID_IN)
+
+/* ------------------------------------------------------------------------------------
+   New TD/QH-structures
+   ------------------------------------------------------------------------------------ */
+typedef enum {
+	TD_TYPE, QH_TYPE
+} uhci_desc_type_t;
+
+typedef struct {
+	__u32 link;
+	__u32 status;
+	__u32 info;
+	__u32 buffer;
+} uhci_td_t, *puhci_td_t;
+
+typedef struct {
+	__u32 head;
+	__u32 element;		/* Queue element pointer */
+} uhci_qh_t, *puhci_qh_t;
+
+typedef struct {
+	union {
+		uhci_td_t td;
+		uhci_qh_t qh;
+	} hw;
+	uhci_desc_type_t type;
+	struct list_head horizontal;
+	struct list_head vertical;
+	struct list_head desc_list;
+	int last_used;
+} uhci_desc_t, *puhci_desc_t;
+
+typedef struct {
+	struct list_head desc_list;	// list pointer to all corresponding TDs/QHs associated with this request
+	unsigned long started;
+	urb_t *next_queued_urb;         // next queued urb for this EP
+	urb_t *prev_queued_urb;
+	uhci_desc_t *bottom_qh;
+	uhci_desc_t *next_qh;       	// next helper QH
+	char use_loop;
+	char flags;
+} urb_priv_t, *purb_priv_t;
+
+struct virt_root_hub {
+	int devnum;		/* Address of Root Hub endpoint */
+	void *urb;
+	void *int_addr;
+	int send;
+	int interval;
+	int numports;
+	int c_p_r[8];
+	struct timer_list rh_int_timer;
+};
+
+typedef struct uhci {
+	int irq;
+	unsigned int io_addr;
+	unsigned int io_size;
+	unsigned int maxports;
+	int running;
+
+	int apm_state;
+
+	struct uhci *next;	// chain of uhci device contexts
+
+	struct list_head urb_list;	// list of all pending urbs
+
+	spinlock_t urb_list_lock;	// lock to keep consistency 
+
+	int unlink_urb_done;
+	atomic_t avoid_bulk;
+	
+	struct usb_bus *bus;	// our bus
+
+	__u32 *framelist;
+	uhci_desc_t **iso_td;
+	uhci_desc_t *int_chain[8];
+	uhci_desc_t *ls_control_chain;
+	uhci_desc_t *control_chain;
+	uhci_desc_t *bulk_chain;
+	uhci_desc_t *chain_end;
+	uhci_desc_t *td1ms;
+	uhci_desc_t *td32ms;
+	struct list_head free_desc;
+	spinlock_t qh_lock;
+	spinlock_t td_lock;
+	struct virt_root_hub rh;	//private data of the virtual root hub
+	int loop_usage;            // URBs using bandwidth reclamation
+
+	struct list_head urb_unlinked;	// list of all unlinked  urbs
+	long timeout_check;
+	int timeout_urbs;
+	struct pci_dev *uhci_pci;
+} uhci_t, *puhci_t;
+
+
+#define MAKE_TD_ADDR(a) (virt_to_bus(a)&~UHCI_PTR_QH)
+#define MAKE_QH_ADDR(a) (virt_to_bus(a)|UHCI_PTR_QH)
+#define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM))
+
+/* ------------------------------------------------------------------------------------ 
+   Virtual Root HUB 
+   ------------------------------------------------------------------------------------ */
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS			0x0500
+#define RH_GET_DESCRIPTOR		0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb.c linux.18p8/drivers/usb/usb.c
--- linux.vanilla/drivers/usb/usb.c	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/usb.c	Fri Sep  8 17:02:03 2000
@@ -1,7 +1,12 @@
 /*
- * driver/usb/usb.c
+ * drivers/usb/usb.c
  *
  * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
  *
  * NOTE! This is not actually a driver at all, rather this is
  * just a collection of helper routines that implement the
@@ -10,318 +15,1082 @@
  * Think of this as a "USB library" rather than anything else.
  * It should be considered a slave, with no callbacks. Callbacks
  * are evil.
- */
-
-/*
- * Table 9-2
  *
- * Offset	Field		Size	Value		Desc
- * 0		bmRequestType	1	Bitmap		D7:	Direction
- *							0 = Host-to-device
- *							1 = Device-to-host
- *							D6..5:	Type
- *							0 = Standard
- *							1 = Class
- *							2 = Vendor
- *							3 = Reserved
- *							D4..0:	Recipient
- *							0 = Device
- *							1 = Interface
- *							2 = Endpoint
- *							3 = Other
- *							4..31 = Reserved
- * 1		bRequest	1	Value		Specific request (9-3)
- * 2		wValue		2	Value		Varies
- * 4		wIndex		2	Index/Offset	Varies
- * 6		wLength		2	Count		Bytes for data
+ * $Id: usb.c,v 1.53 2000/01/14 16:19:09 acher Exp $
  */
 
+#include <linux/config.h>
+#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
 #include <linux/malloc.h>
+#include <linux/interrupt.h>  /* for in_interrupt() */
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
 
-#include "usb.h"
+static const int usb_bandwidth_option =
+#ifdef CONFIG_USB_BANDWIDTH
+				1;
+#else
+				0;
+#endif
+
+/*
+ * Prototypes for the device driver probing/loading functions
+ */
+static void usb_find_drivers(struct usb_device *);
+static int  usb_find_interface_driver(struct usb_device *, unsigned int);
+static void usb_check_support(struct usb_device *);
 
 /*
  * We have a per-interface "registered driver" list.
  */
-static LIST_HEAD(usb_driver_list);
+LIST_HEAD(usb_driver_list);
+LIST_HEAD(usb_bus_list);
+
+static struct usb_busmap busmap;
+
+static struct usb_driver *usb_minors[16];
 
 int usb_register(struct usb_driver *new_driver)
 {
+	if (new_driver->fops != NULL) {
+		if (usb_minors[new_driver->minor/16]) {
+			 err("error registering %s driver", new_driver->name);
+			return -EINVAL;
+		}
+		usb_minors[new_driver->minor/16] = new_driver;
+	}
+
+	info("registered new driver %s", new_driver->name);
+
+	init_MUTEX(&new_driver->serialize);
+
 	/* Add it to the list of known drivers */
 	list_add(&new_driver->driver_list, &usb_driver_list);
 
-	/*
-	 * We should go through all existing devices, and see if any of
-	 * them would be acceptable to the new driver.. Let's do that
-	 * in version 2.0.
-	 */
+	usb_scan_devices();
+
 	return 0;
 }
 
-void usb_deregister(struct usb_driver *driver)
+/*
+ * We go through all existing devices, and see if any of them would
+ * be acceptable to the new driver.. This is done using a depth-first
+ * search for devices without a registered driver already, then 
+ * running 'probe' with each of the drivers registered on every one 
+ * of these.
+ */
+void usb_scan_devices(void)
 {
-	list_del(&driver->driver_list);
+	struct list_head *tmp;
+
+	tmp = usb_bus_list.next;
+	while (tmp != &usb_bus_list) {
+		struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list);
+
+		tmp = tmp->next;
+		usb_check_support(bus->root_hub);
+	}
 }
 
 /*
- * This entrypoint gets called for each new device.
- *
- * We now walk the list of registered USB drivers,
- * looking for one that will accept this device as
- * his..
+ * This function is part of a depth-first search down the device tree,
+ * removing any instances of a device driver.
  */
-void usb_device_descriptor(struct usb_device *dev)
+static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
 {
-	struct list_head *tmp = usb_driver_list.next;
+	int i;
 
-	while (tmp != &usb_driver_list) {
-		struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
-		tmp = tmp->next;
-		if (driver->probe(dev))
-			continue;
-		dev->driver = driver;
+	if (!dev) {
+		err("null device being purged!!!");
 		return;
 	}
 
-	/*
-	 * Ok, no driver accepted the device, so show the info
-	 * for debugging..
-	 */
-	printk("Unknown new USB device:\n");
-	usb_show_device(dev);
+	for (i=0; i<USB_MAXCHILDREN; i++)
+		if (dev->children[i])
+			usb_drivers_purge(driver, dev->children[i]);
+
+	if (!dev->actconfig)
+		return;
+			
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+		struct usb_interface *interface = &dev->actconfig->interface[i];
+		
+		if (interface->driver == driver) {
+			down(&driver->serialize);
+			driver->disconnect(dev, interface->private_data);
+			up(&driver->serialize);
+			usb_driver_release_interface(driver, interface);
+			/*
+			 * This will go through the list looking for another
+			 * driver that can handle the device
+			 */
+			usb_find_interface_driver(dev, i);
+		}
+	}
 }
 
 /*
- * Parse the fairly incomprehensible output of
- * the USB configuration data, and build up the
- * USB device database.
+ * Unlink a driver from the driver list when it is unloaded
  */
-static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desctype, unsigned char descindex)
+void usb_deregister(struct usb_driver *driver)
 {
-	int parsed = 0;
-	int n_len;
-	unsigned short n_desc;
+	struct list_head *tmp;
 
-	for (;;) {
-		int i;
+	info("deregistering driver %s", driver->name);
+	if (driver->fops != NULL)
+		usb_minors[driver->minor/16] = NULL;
 
-		if (len < descindex)
-			return -1;
-		n_desc = *(unsigned short *)ptr;
-		n_len = n_desc & 0xff;
+	/*
+	 * first we remove the driver, to be sure it doesn't get used by
+	 * another thread while we are stepping through removing entries
+	 */
+	list_del(&driver->driver_list);
 
-		if (n_desc == ((desctype << 8) + descindex))
-			break;
+	tmp = usb_bus_list.next;
+	while (tmp != &usb_bus_list) {
+		struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
 
-		if (((n_desc >> 8)&0xFF) == desctype &&
-			n_len > descindex)
+		tmp = tmp->next;
+		usb_drivers_purge(driver, bus->root_hub);
+	}
+}
+
+struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
+{
+	int i;
+
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+		if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum)
+			return &dev->actconfig->interface[i];
+
+	return NULL;
+}
+
+/*
+ * usb_calc_bus_time:
+ *
+ * returns (approximate) USB bus time in nanoseconds for a USB transaction.
+ */
+static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount)
+{
+	unsigned long	tmp;
+
+	if (low_speed)		/* no isoc. here */
+	{
+		if (input_dir)
 		{
-			printk("bug: oversized descriptor.\n");
-			break;
+			tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
 		}
-			
-		if (n_len < 2 || n_len > len)
+		else
 		{
-			printk("Short descriptor.\n");
-			return -1;
+			tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
 		}
-		printk(
-		"Expected descriptor %02X/%02X, got %02X/%02X - skipping\n",
-			desctype, descindex,
-			(n_desc >> 8) & 0xFF, n_desc & 0xFF);
-		for (i = 0 ; i < n_len; i++)
-			printk("   %d %02x\n", i, ptr[i]);
-		len -= n_len;
-		ptr += n_len;
-		parsed += n_len;
 	}
+
+	/* for full-speed: */
+
+	if (!isoc)		/* Input or Output */
+	{
+		tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+		return (9107L + BW_HOST_DELAY + tmp);
+	} /* end not Isoc */
+
+	/* for isoc: */
+
+	tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+	return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
+}
+
+/*
+ * usb_check_bandwidth():
+ *
+ * old_alloc is from host_controller->bandwidth_allocated in microseconds;
+ * bustime is from calc_bus_time(), but converted to microseconds.
+ *
+ * returns <bustime in us> if successful,
+ * or USB_ST_BANDWIDTH_ERROR if bandwidth request fails.
+ *
+ * FIXME:
+ * This initial implementation does not use Endpoint.bInterval
+ * in managing bandwidth allocation.
+ * It probably needs to be expanded to use Endpoint.bInterval.
+ * This can be done as a later enhancement (correction).
+ * This will also probably require some kind of
+ * frame allocation tracking...meaning, for example,
+ * that if multiple drivers request interrupts every 10 USB frames,
+ * they don't all have to be allocated at
+ * frame numbers N, N+10, N+20, etc.  Some of them could be at
+ * N+11, N+21, N+31, etc., and others at
+ * N+12, N+22, N+32, etc.
+ * However, this first cut at USB bandwidth allocation does not
+ * contain any frame allocation tracking.
+ */
+int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
+{
+	int		new_alloc;
+	int		old_alloc = dev->bus->bandwidth_allocated;
+	unsigned int	pipe = urb->pipe;
+	long		bustime;
+
+	bustime = usb_calc_bus_time (usb_pipeslow(pipe), usb_pipein(pipe),
+			usb_pipeisoc(pipe), usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
+	if (usb_pipeisoc(pipe))
+		bustime = NS_TO_US(bustime) / urb->number_of_packets;
+	else
+		bustime = NS_TO_US(bustime);
+
+	new_alloc = old_alloc + (int)bustime;
+		/* what new total allocated bus time would be */
+
+	if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC)
+		dbg("usb-check-bandwidth %sFAILED: was %u, would be %u, bustime = %ld us",
+			usb_bandwidth_option ? "" : "would have ",
+			old_alloc, new_alloc, bustime);
+
+	if (!usb_bandwidth_option)	/* don't enforce it */
+		return (bustime);
+	return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? bustime : USB_ST_BANDWIDTH_ERROR;
+}
+
+void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
+{
+	dev->bus->bandwidth_allocated += bustime;
+	if (isoc)
+		dev->bus->bandwidth_isoc_reqs++;
+	else
+		dev->bus->bandwidth_int_reqs++;
+	urb->bandwidth = bustime;
 	
-	printk("Found %02X:%02X\n",
-		desctype, descindex);
-	return parsed;
+	dbg("bw_alloc increased by %d to %d for %d requesters",
+		bustime,
+		dev->bus->bandwidth_allocated,
+		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
 }
 
 /*
- * Parse the even more incomprehensible mess made of the USB spec
- * by USB audio having private magic to go with it.
+ * usb_release_bandwidth():
+ *
+ * called to release a pipe's bandwidth (in microseconds)
  */
- 
-static int usb_check_descriptor(unsigned char *ptr, int len, unsigned char desctype)
+void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc)
 {
-	int n_len = ptr[0];
+	dev->bus->bandwidth_allocated -= urb->bandwidth;
+	if (isoc)
+		dev->bus->bandwidth_isoc_reqs--;
+	else
+		dev->bus->bandwidth_int_reqs--;
+
+	dbg("bw_alloc reduced by %d to %d for %d requesters",
+		urb->bandwidth,
+		dev->bus->bandwidth_allocated,
+		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+	urb->bandwidth = 0;
+}
 
-	if (n_len < 2 || n_len > len)
-	{
-		printk("Short descriptor.\n");
+/*
+ * New functions for (de)registering a controller
+ */
+struct usb_bus *usb_alloc_bus(struct usb_operations *op)
+{
+	struct usb_bus *bus;
+
+	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+
+	memset(&bus->devmap, 0, sizeof(struct usb_devmap));
+
+	bus->op = op;
+	bus->root_hub = NULL;
+	bus->hcpriv = NULL;
+	bus->busnum = -1;
+	bus->bandwidth_allocated = 0;
+	bus->bandwidth_int_reqs  = 0;
+	bus->bandwidth_isoc_reqs = 0;
+
+	INIT_LIST_HEAD(&bus->bus_list);
+	INIT_LIST_HEAD(&bus->inodes);
+
+	return bus;
+}
+
+void usb_free_bus(struct usb_bus *bus)
+{
+	if (!bus)
+		return;
+
+	kfree(bus);
+}
+
+void usb_register_bus(struct usb_bus *bus)
+{
+	int busnum;
+
+	busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1);
+	if (busnum < USB_MAXBUS) {
+		set_bit(busnum, busmap.busmap);
+		bus->busnum = busnum;
+	} else
+		warn("too many buses");
+
+	/* Add it to the list of buses */
+	list_add(&bus->bus_list, &usb_bus_list);
+
+	usbdevfs_add_bus(bus);
+
+	info("new USB bus registered, assigned bus number %d", bus->busnum);
+}
+
+void usb_deregister_bus(struct usb_bus *bus)
+{
+	info("USB bus %d deregistered", bus->busnum);
+
+	/*
+	 * NOTE: make sure that all the devices are removed by the
+	 * controller code, as well as having it call this when cleaning
+	 * itself up
+	 */
+	list_del(&bus->bus_list);
+
+        usbdevfs_remove_bus(bus);
+
+	clear_bit(bus->busnum, busmap.busmap);
+}
+
+/*
+ * This function is for doing a depth-first search for devices which
+ * have support, for dynamic loading of driver modules.
+ */
+static void usb_check_support(struct usb_device *dev)
+{
+	int i;
+
+	if (!dev) {
+		err("null device being checked!!!");
+		return;
+	}
+
+	for (i=0; i<USB_MAXCHILDREN; i++)
+		if (dev->children[i])
+			usb_check_support(dev->children[i]);
+
+	if (!dev->actconfig)
+		return;
+
+	/* now we check this device */
+	if (dev->devnum > 0)
+		for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+			usb_find_interface_driver(dev, i);
+}
+
+
+/*
+ * This is intended to be used by usb device drivers that need to
+ * claim more than one interface on a device at once when probing
+ * (audio and acm are good examples).  No device driver should have
+ * to mess with the internal usb_interface or usb_device structure
+ * members.
+ */
+void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
+{
+	if (!iface || !driver)
+		return;
+
+	dbg("%s driver claimed interface %p", driver->name, iface);
+
+	iface->driver = driver;
+	iface->private_data = priv;
+} /* usb_driver_claim_interface() */
+
+/*
+ * This should be used by drivers to check other interfaces to see if
+ * they are available or not.
+ */
+int usb_interface_claimed(struct usb_interface *iface)
+{
+	if (!iface)
+		return 0;
+
+	return (iface->driver != NULL);
+} /* usb_interface_claimed() */
+
+/*
+ * This should be used by drivers to release their claimed interfaces
+ */
+void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)
+{
+	/* this should never happen, don't release something that's not ours */
+	if (iface->driver != driver || !iface)
+		return;
+
+	iface->driver = NULL;
+	iface->private_data = NULL;
+}
+
+/*
+ * This entrypoint gets called for each new device.
+ *
+ * We now walk the list of registered USB drivers,
+ * looking for one that will accept this interface.
+ *
+ * The probe return value is changed to be a private pointer.  This way
+ * the drivers don't have to dig around in our structures to set the
+ * private pointer if they only need one interface. 
+ *
+ * Returns: 0 if a driver accepted the interface, -1 otherwise
+ */
+static int usb_find_interface_driver(struct usb_device *dev, unsigned ifnum)
+{
+	struct list_head *tmp = usb_driver_list.next;
+	struct usb_interface *interface;
+	
+	if ((!dev) || (ifnum >= dev->actconfig->bNumInterfaces)) {
+		err("bad find_interface_driver params");
 		return -1;
 	}
 
-	if (ptr[1] == desctype)
+	interface = dev->actconfig->interface + ifnum;
+
+	if (usb_interface_claimed(interface))
+		return -1;
+
+	while (tmp != &usb_driver_list) {
+		void *private;
+		struct usb_driver *driver = list_entry(tmp, struct usb_driver,
+		  				       driver_list);
+			
+		tmp = tmp->next;
+		down(&driver->serialize);
+		private = driver->probe(dev, ifnum);
+		up(&driver->serialize);
+		if (!private)
+			continue;
+		usb_driver_claim_interface(driver, interface, private);
+
 		return 0;
-		
+	}
+	
 	return -1;
 }
 
+/*
+ * This entrypoint gets called for each new device.
+ *
+ * All interfaces are scanned for matching drivers.
+ */
+static void usb_find_drivers(struct usb_device *dev)
+{
+	unsigned ifnum;
+	unsigned rejected = 0;
+	unsigned claimed = 0;
+
+	for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
+		/* if this interface hasn't already been claimed */
+		if (!usb_interface_claimed(dev->actconfig->interface + ifnum)) {
+			if (usb_find_interface_driver(dev, ifnum))
+				rejected++;
+			else
+				claimed++;
+		}
+	}
+ 
+	if (rejected)
+		dbg("unhandled interfaces on device");
+
+	if (!claimed) {
+		warn("This device is not recognized by any installed USB driver.");
+#ifdef DEBUG
+		usb_show_device(dev);
+#endif
+	}
+}
 
-static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len)
+/*
+ * Only HC's should call usb_alloc_dev and usb_free_dev directly
+ * Anybody may use usb_inc_dev_use or usb_dec_dev_use
+ */
+struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
 {
-	int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, 7);
-	int i;
+	struct usb_device *dev;
 
-	if (parsed < 0)
-		return parsed;
-	memcpy(endpoint, ptr + parsed, ptr[parsed]);
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
 
-	parsed += ptr[parsed];
-	len -= ptr[parsed];
+	memset(dev, 0, sizeof(*dev));
 
-	while((i = usb_check_descriptor(ptr+parsed, len, 0x25))>=0)
-	{
-		usb_audio_endpoint(endpoint, ptr+parsed+i);
-		len -= ptr[parsed+i];
-		parsed += ptr[parsed+i];
-	}
-	
-	return parsed;// + ptr[parsed];
+	dev->bus = bus;
+	dev->parent = parent;
+	atomic_set(&dev->refcnt, 1);
+	INIT_LIST_HEAD(&dev->inodes);
+	INIT_LIST_HEAD(&dev->filelist);
+
+	dev->bus->op->allocate(dev);
+
+	return dev;
 }
 
-static int usb_parse_interface(struct usb_device *dev, struct usb_interface_descriptor *interface, unsigned char *ptr, int len)
+void usb_free_dev(struct usb_device *dev)
 {
-	int i;
-	int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, 9);
-	int retval;
+	if (atomic_dec_and_test(&dev->refcnt)) {
+		usb_destroy_configuration(dev);
+		dev->bus->op->deallocate(dev);
+		kfree(dev);
+	}
+}
 
-	if (parsed < 0)
-		return parsed;
+void usb_inc_dev_use(struct usb_device *dev)
+{
+	atomic_inc(&dev->refcnt);
+}
+/* ------------------------------------------------------------------------------------- 
+ * New USB Core Functions
+ * -------------------------------------------------------------------------------------*/
 
-	memcpy(interface, ptr + parsed, *ptr);
-	len -= ptr[parsed];
-	parsed += ptr[parsed];
+urb_t *usb_alloc_urb(int iso_packets)
+{
+	urb_t *urb;
 
-	while((i=usb_check_descriptor(ptr+parsed, len, 0x24))>=0)
-	{
-		usb_audio_interface(interface, ptr+parsed+i);
-		len -= ptr[parsed+i];
-		parsed += ptr[parsed+i];
+	urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t),
+	      in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+	if (!urb) {
+		err("alloc_urb: kmalloc failed");
+		return NULL;
 	}
+
+	memset(urb, 0, sizeof(*urb));
+
+	spin_lock_init(&urb->lock);
+
+	return urb;
+}
+
+/*-------------------------------------------------------------------*/
+void usb_free_urb(urb_t* urb)
+{
+	if (urb)
+		kfree(urb);
+}
+/*-------------------------------------------------------------------*/
+int usb_submit_urb(urb_t *urb)
+{
+	if (urb && urb->dev)
+		return urb->dev->bus->op->submit_urb(urb);
+	else
+		return -1;
+}
+
+/*-------------------------------------------------------------------*/
+int usb_unlink_urb(urb_t *urb)
+{
+	if (urb && urb->dev)
+		return urb->dev->bus->op->unlink_urb(urb);
+	else
+		return -1;
+}
+/*-------------------------------------------------------------------*
+ *                     COMPLETION HANDLERS                           *
+ *-------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------*
+ * completion handler for compatibility wrappers (sync control/bulk) *
+ *-------------------------------------------------------------------*/
+static void usb_api_blocking_completion(urb_t *urb)
+{
+	api_wrapper_data *awd = (api_wrapper_data *)urb->context;
+
+	if (waitqueue_active(awd->wakeup))
+		wake_up(awd->wakeup);
+#if 0
+	else
+		dbg("(blocking_completion): waitqueue empty!"); 
+		// even occurs if urb was unlinked by timeout...
+#endif
+}
+
+/*-------------------------------------------------------------------*
+ *                         COMPATIBILITY STUFF                       *
+ *-------------------------------------------------------------------*/
+
+// Starts urb and waits for completion or timeout
+static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+{ 
+	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAIT_QUEUE_HEAD(wqh);
+	api_wrapper_data awd;
+	int status;
+  
+	awd.wakeup = &wqh;
+	awd.handler = 0;
+	init_waitqueue_head(&wqh); 	
+	current->state = TASK_INTERRUPTIBLE;
+	add_wait_queue(&wqh, &wait);
+	urb->context = &awd;
+	status = usb_submit_urb(urb);
+	if (status) {
+		// something went wrong
+		usb_free_urb(urb);
+		remove_wait_queue(&wqh, &wait);
+		return status;
+	}
+
+	if (urb->status == -EINPROGRESS) {
+		while (timeout && urb->status == -EINPROGRESS)
+			status = timeout = schedule_timeout(timeout);
+	} else
+		status = 1;
+
+	remove_wait_queue(&wqh, &wait);
+
+	if (!status) {
+		// timeout
+		printk("usb_control/bulk_msg: timeout\n");
+		usb_unlink_urb(urb);  // remove urb safely
+		status = -ETIMEDOUT;
+	} else
+		status = urb->status;
+
+	if (actual_length)
+		*actual_length = urb->actual_length;
+
+	usb_free_urb(urb);
+  	return status;
+}
+
+/*-------------------------------------------------------------------*/
+// returns status (negative) or length (positive)
+int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, 
+			    devrequest *cmd,  void *data, int len, int timeout)
+{
+	urb_t *urb;
+	int retv;
+	int length;
+
+	urb = usb_alloc_urb(0);
+	if (!urb)
+		return -ENOMEM;
+  
+	FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,    /* build urb */  
+		   (usb_complete_t)usb_api_blocking_completion,0);
+
+	retv = usb_start_wait_urb(urb, timeout, &length);
+	if (retv < 0)
+		return retv;
+	else
+		return length;
 	
-	if (interface->bNumEndpoints > USB_MAXENDPOINTS)
-	{
-		printk(KERN_WARNING "usb: too many endpoints.\n");
+}
+
+/*-------------------------------------------------------------------*/
+int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
+			 __u16 value, __u16 index, void *data, __u16 size, int timeout)
+{
+	devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
+	int ret;
+	
+	if (!dr)
+		return -ENOMEM;
+
+	dr->requesttype = requesttype;
+	dr->request = request;
+	dr->value = cpu_to_le16p(&value);
+	dr->index = cpu_to_le16p(&index);
+	dr->length = cpu_to_le16p(&size);
+
+	//dbg("usb_control_msg");	
+
+	ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+
+	kfree(dr);
+
+	return ret;
+}
+
+/*-------------------------------------------------------------------*/
+/* compatibility wrapper, builds bulk urb, and waits for completion */
+/* synchronous behavior */
+
+int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
+			void *data, int len, int *actual_length, int timeout)
+{
+	urb_t *urb;
+
+	if (len < 0)
+		return -EINVAL;
+
+	urb=usb_alloc_urb(0);
+	if (!urb)
+		return -ENOMEM;
+
+	FILL_BULK_URB(urb,usb_dev,pipe,(unsigned char*)data,len,   /* build urb */
+			(usb_complete_t)usb_api_blocking_completion,0);
+
+	return usb_start_wait_urb(urb,timeout,actual_length);
+}
+
+/*
+ * usb_get_current_frame_number()
+ *
+ * returns the current frame number for the parent USB bus/controller
+ * of the given USB device.
+ */
+int usb_get_current_frame_number(struct usb_device *usb_dev)
+{
+	return usb_dev->bus->op->get_frame_number (usb_dev);
+}
+/*-------------------------------------------------------------------*/
+
+static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
+{
+	struct usb_descriptor_header *header;
+	unsigned char *begin;
+	int parsed = 0, len, numskipped;
+
+	header = (struct usb_descriptor_header *)buffer;
+
+	/* Everything should be fine being passed into here, but we sanity */
+	/*  check JIC */
+	if (header->bLength > size) {
+		err("ran out of descriptors parsing");
 		return -1;
 	}
-
-	interface->endpoint = (struct usb_endpoint_descriptor *)
-		kmalloc(interface->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
-	if(interface->endpoint==NULL)
-	{
-		printk(KERN_WARNING "usb: out of memory.\n");
-		return -1;	
+		
+	if (header->bDescriptorType != USB_DT_ENDPOINT) {
+		warn("unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X",
+			endpoint->bDescriptorType, USB_DT_ENDPOINT);
+		return parsed;
 	}
-	memset(interface->endpoint, 0, interface->bNumEndpoints*sizeof(struct usb_endpoint_descriptor));
+
+	if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE)
+		memcpy(endpoint, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);
+	else
+		memcpy(endpoint, buffer, USB_DT_ENDPOINT_SIZE);
 	
-	for (i = 0; i < interface->bNumEndpoints; i++) {
-//		if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) {
-//			parsed += 9;	/* skip over the HID descriptor for now */
-//			len -= 9;
-//		}
-		retval = usb_parse_endpoint(dev, interface->endpoint + i, ptr + parsed, len);
-		if (retval < 0) return retval;
-		parsed += retval;
-		len -= retval;
+	le16_to_cpus(&endpoint->wMaxPacketSize);
+
+	buffer += header->bLength;
+	size -= header->bLength;
+	parsed += header->bLength;
+
+	/* Skip over the rest of the Class Specific or Vendor Specific */
+	/*  descriptors */
+	begin = buffer;
+	numskipped = 0;
+	while (size >= sizeof(struct usb_descriptor_header)) {
+		header = (struct usb_descriptor_header *)buffer;
+
+		if (header->bLength < 2) {
+			err("invalid descriptor length of %d", header->bLength);
+			return -1;
+		}
+
+		/* If we find another descriptor which is at or below us */
+		/*  in the descriptor heirarchy then we're done  */
+		if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
+		    (header->bDescriptorType == USB_DT_INTERFACE) ||
+		    (header->bDescriptorType == USB_DT_CONFIG) ||
+		    (header->bDescriptorType == USB_DT_DEVICE))
+			break;
+
+		dbg("skipping descriptor 0x%X",
+			header->bDescriptorType);
+		numskipped++;
+
+		buffer += header->bLength;
+		size -= header->bLength;
+		parsed += header->bLength;
+	}
+	if (numskipped)
+		dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
+
+	/* Copy any unknown descriptors into a storage area for drivers */
+	/*  to later parse */
+	len = (int)(buffer - begin);
+	if (!len) {
+		endpoint->extra = NULL;
+		endpoint->extralen = 0;
+		return parsed;
 	}
+
+	endpoint->extra = kmalloc(len, GFP_KERNEL);
+
+	if (!endpoint->extra) {
+		err("couldn't allocate memory for endpoint extra descriptors");
+		endpoint->extralen = 0;
+		return parsed;
+	}
+
+	memcpy(endpoint->extra, begin, len);
+	endpoint->extralen = len;
+
 	return parsed;
 }
 
-static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor *config, unsigned char *ptr, int len)
+static int usb_parse_interface(struct usb_device *dev, struct usb_interface *interface, unsigned char *buffer, int size)
 {
-	int i;
-	int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9);
-
-	if (parsed < 0)
-		return parsed;
+	int i, len, numskipped, retval, parsed = 0;
+	struct usb_descriptor_header *header;
+	struct usb_interface_descriptor *ifp;
+	unsigned char *begin;
 
-	memcpy(config, ptr + parsed, *ptr);
-	len -= *ptr;
-	parsed += *ptr;
+	interface->act_altsetting = 0;
+	interface->num_altsetting = 0;
+	interface->max_altsetting = USB_ALTSETTINGALLOC;
 
-	if (config->bNumInterfaces > USB_MAXINTERFACES)
-	{
-		printk(KERN_WARNING "usb: too many interfaces.\n");
+	interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL);
+	
+	if (!interface->altsetting) {
+		err("couldn't kmalloc interface->altsetting");
 		return -1;
-
 	}
 
-	config->interface = (struct usb_interface_descriptor *)
-		kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
-	if(config->interface==NULL)
-	{
-		printk(KERN_WARNING "usb: out of memory.\n");
-		return -1;	
-	}
-	memset(config->interface, 0, config->bNumInterfaces*sizeof(struct usb_interface_descriptor));
+	while (size > 0) {
+		if (interface->num_altsetting >= interface->max_altsetting) {
+			void *ptr;
+			int oldmas;
+
+			oldmas = interface->max_altsetting;
+			interface->max_altsetting += USB_ALTSETTINGALLOC;
+			if (interface->max_altsetting > USB_MAXALTSETTING) {
+				warn("too many alternate settings (max %d)",
+					USB_MAXALTSETTING);
+				return -1;
+			}
+
+			ptr = interface->altsetting;
+			interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * interface->max_altsetting, GFP_KERNEL);
+			if (!interface->altsetting) {
+				err("couldn't kmalloc interface->altsetting");
+				interface->altsetting = ptr;
+				return -1;
+			}
+			memcpy(interface->altsetting, ptr, sizeof(struct usb_interface_descriptor) * oldmas);
+
+			kfree(ptr);
+		}
+
+		ifp = interface->altsetting + interface->num_altsetting;
+		interface->num_altsetting++;
+
+		memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE);
+
+		/* Skip over the interface */
+		buffer += ifp->bLength;
+		parsed += ifp->bLength;
+		size -= ifp->bLength;
+
+		begin = buffer;
+		numskipped = 0;
+
+		/* Skip over any interface, class or vendor descriptors */
+		while (size >= sizeof(struct usb_descriptor_header)) {
+			header = (struct usb_descriptor_header *)buffer;
+
+			if (header->bLength < 2) {
+				err("invalid descriptor length of %d", header->bLength);
+				return -1;
+			}
+
+			/* If we find another descriptor which is at or below */
+			/*  us in the descriptor heirarchy then return */
+			if ((header->bDescriptorType == USB_DT_INTERFACE) ||
+			    (header->bDescriptorType == USB_DT_ENDPOINT) ||
+			    (header->bDescriptorType == USB_DT_CONFIG) ||
+			    (header->bDescriptorType == USB_DT_DEVICE))
+				break;
+
+			numskipped++;
+
+			buffer += header->bLength;
+			parsed += header->bLength;
+			size -= header->bLength;
+		}
+
+		if (numskipped)
+			dbg("skipped %d class/vendor specific interface descriptors", numskipped);
+
+		/* Copy any unknown descriptors into a storage area for */
+		/*  drivers to later parse */
+		len = (int)(buffer - begin);
+		if (!len) {
+			ifp->extra = NULL;
+			ifp->extralen = 0;
+		} else {
+			ifp->extra = kmalloc(len, GFP_KERNEL);
+
+			if (!ifp->extra) {
+				err("couldn't allocate memory for interface extra descriptors");
+				ifp->extralen = 0;
+				return -1;
+			}
+			memcpy(ifp->extra, begin, len);
+			ifp->extralen = len;
+		}
+
+		/* Did we hit an unexpected descriptor? */
+		header = (struct usb_descriptor_header *)buffer;
+		if ((size >= sizeof(struct usb_descriptor_header)) &&
+		    ((header->bDescriptorType == USB_DT_CONFIG) ||
+		     (header->bDescriptorType == USB_DT_DEVICE)))
+			return parsed;
+
+		if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
+			warn("too many endpoints");
+			return -1;
+		}
+
+		ifp->endpoint = (struct usb_endpoint_descriptor *)
+			kmalloc(ifp->bNumEndpoints *
+			sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
+		if (!ifp->endpoint) {
+			err("out of memory");
+			return -1;	
+		}
+
+		memset(ifp->endpoint, 0, ifp->bNumEndpoints *
+			sizeof(struct usb_endpoint_descriptor));
 	
-	for (i = 0; i < config->bNumInterfaces; i++) {
-		int retval = usb_parse_interface(dev, config->interface + i, ptr + parsed, len);
-		if (retval < 0)
-			return parsed; // HACK
-//			return retval;
-		parsed += retval;
-		len -= retval;
+		for (i = 0; i < ifp->bNumEndpoints; i++) {
+			header = (struct usb_descriptor_header *)buffer;
+
+			if (header->bLength > size) {
+				err("ran out of descriptors parsing");
+				return -1;
+			}
+		
+			retval = usb_parse_endpoint(dev, ifp->endpoint + i, buffer, size);
+			if (retval < 0)
+				return retval;
+
+			buffer += retval;
+			parsed += retval;
+			size -= retval;
+		}
+
+		/* We check to see if it's an alternate to this one */
+		ifp = (struct usb_interface_descriptor *)buffer;
+		if (size < USB_DT_INTERFACE_SIZE ||
+		    ifp->bDescriptorType != USB_DT_INTERFACE ||
+		    !ifp->bAlternateSetting)
+			return parsed;
 	}
+
 	return parsed;
 }
 
-int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes)
+int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor *config, char *buffer)
 {
 	int i;
-	unsigned char *ptr = __buf;
+	int retval;
+	int size;
+	struct usb_descriptor_header *header;
 
-	if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
-	{
-		printk(KERN_WARNING "usb: too many configurations.\n");
+	memcpy(config, buffer, USB_DT_CONFIG_SIZE);
+	le16_to_cpus(&config->wTotalLength);
+	size = config->wTotalLength;
+
+	if (config->bNumInterfaces > USB_MAXINTERFACES) {
+		warn("too many interfaces");
 		return -1;
 	}
 
-	dev->config = (struct usb_config_descriptor *)
-		kmalloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor), GFP_KERNEL);
-	if(dev->config==NULL)
-	{
-		printk(KERN_WARNING "usb: out of memory.\n");
+	config->interface = (struct usb_interface *)
+		kmalloc(config->bNumInterfaces *
+		sizeof(struct usb_interface), GFP_KERNEL);
+	dbg("kmalloc IF %p, numif %i",config->interface,config->bNumInterfaces);
+	if (!config->interface) {
+		err("out of memory");
 		return -1;	
 	}
-	memset(dev->config, 0, dev->descriptor.bNumConfigurations*sizeof(struct usb_config_descriptor));
-	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
-		int retval = usb_parse_config(dev, dev->config + i, ptr, bytes);
+
+	memset(config->interface, 0,
+	       config->bNumInterfaces * sizeof(struct usb_interface));
+
+	buffer += config->bLength;
+	size -= config->bLength;
+	
+	for (i = 0; i < config->bNumInterfaces; i++) {
+		header = (struct usb_descriptor_header *)buffer;
+		if ((header->bLength > size) || (header->bLength <= 2)) {
+			err("ran out of descriptors parsing");
+			return -1;
+		}
+		
+		if (header->bDescriptorType != USB_DT_INTERFACE) {
+			warn("unexpected descriptor 0x%X",
+				header->bDescriptorType);
+
+			buffer += header->bLength;
+			size -= header->bLength;
+			continue;
+		}
+
+		retval = usb_parse_interface(dev, config->interface + i, buffer, size);
 		if (retval < 0)
 			return retval;
-		ptr += retval;
-		bytes += retval;
+
+		buffer += retval;
+		size -= retval;
 	}
-	return 0;
+
+	return size;
 }
 
 void usb_destroy_configuration(struct usb_device *dev)
 {
-	int c, i;
-	struct usb_config_descriptor *cf;
-	struct usb_interface_descriptor *ifp;
+	int c, i, j, k;
 	
-	if(dev->config==NULL)
+	if (!dev->config)
 		return;
-	for(c=0;c<dev->descriptor.bNumConfigurations;c++)
-	{
-		cf=&dev->config[c];
-		if(cf->interface==NULL)
+
+	if (dev->rawdescriptors) {
+		for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+			kfree(dev->rawdescriptors[i]);
+
+		kfree(dev->rawdescriptors);
+	}
+
+	for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
+		struct usb_config_descriptor *cf = &dev->config[c];
+
+		if (!cf->interface)
 			break;
-		for(i=0;i<cf->bNumInterfaces;i++)
-		{
-			ifp=&cf->interface[i];
-			if(ifp->endpoint==NULL)
+
+		for (i = 0; i < cf->bNumInterfaces; i++) {
+			struct usb_interface *ifp =
+				&cf->interface[i];
+				
+			if (!ifp->altsetting)
 				break;
-			kfree(ifp->endpoint);
+
+			for (j = 0; j < ifp->num_altsetting; j++) {
+				struct usb_interface_descriptor *as =
+					&ifp->altsetting[j];
+					
+				if(as->extra) {
+					kfree(as->extra);
+				}
+
+				if (!as->endpoint)
+					break;
+					
+				for(k = 0; k < as->bNumEndpoints; k++) {
+					if(as->endpoint[k].extra) {
+						kfree(as->endpoint[k].extra);
+					}
+				}	
+				kfree(as->endpoint);
+			}
+
+			kfree(ifp->altsetting);
 		}
 		kfree(cf->interface);
 	}
@@ -332,6 +1101,83 @@
 {
 	dev->devnum = -1;
 	dev->slow = 0;
+	dev->actconfig = NULL;
+}
+
+/* for returning string descriptors in UTF-16LE */
+static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
+{
+	int retval;
+
+	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+		*utf++ = *ascii++ & 0x7f;
+		*utf++ = 0;
+	}
+	return retval;
+}
+
+/*
+ * root_hub_string is used by each host controller's root hub code,
+ * so that they're identified consistently throughout the system.
+ */
+int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+{
+	char buf [30];
+
+	// assert (len > (2 * (sizeof (buf) + 1)));
+	// assert (strlen (type) <= 8);
+
+	// language ids
+	if (id == 0) {
+		*data++ = 4; *data++ = 3;	/* 4 bytes data */
+		*data++ = 0; *data++ = 0;	/* some language id */
+		return 4;
+
+	// serial number
+	} else if (id == 1) {
+		sprintf (buf, "%x", serial);
+
+	// product description
+	} else if (id == 2) {
+		sprintf (buf, "USB %s Root Hub", type);
+
+	// id 3 == vendor description
+
+	// unsupported IDs --> "stall"
+	} else
+	    return 0;
+
+	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+	data [1] = 3;
+	return data [0];
+}
+
+/*
+ * __usb_get_extra_descriptor() finds a descriptor of specific type in the
+ * extra field of the interface and endpoint descriptor structs.
+ */
+
+int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
+{
+	struct usb_descriptor_header *header;
+
+	while (size >= sizeof(struct usb_descriptor_header)) {
+		header = (struct usb_descriptor_header *)buffer;
+
+		if (header->bLength < 2) {
+			err("invalid descriptor length of %d", header->bLength);
+			return -1;
+		}
+
+		if (header->bDescriptorType == type) {
+			*ptr = header;
+			return 0;
+		}
+
+		buffer += header->bLength;
+		size -= header->bLength;
+	}
+	return -1;
 }
 
 /*
@@ -340,29 +1186,44 @@
 void usb_disconnect(struct usb_device **pdev)
 {
 	struct usb_device * dev = *pdev;
+	int i;
 
-	if (dev) {
-		int i;
-
-		*pdev = NULL;
+	if (!dev)
+		return;
 
-		printk("USB disconnect on device %d\n", dev->devnum);
+	*pdev = NULL;
 
-		if(dev->driver) dev->driver->disconnect(dev);
+	info("USB disconnect on device %d", dev->devnum);
 
-		/* Free up all the children.. */
-		for (i = 0; i < USB_MAXCHILDREN; i++) {
-			struct usb_device **child = dev->children + i;
-			usb_disconnect(child);
+	if (dev->actconfig) {
+		for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
+			struct usb_interface *interface = &dev->actconfig->interface[i];
+			struct usb_driver *driver = interface->driver;
+			if (driver) {
+				down(&driver->serialize);
+				driver->disconnect(dev, interface->private_data);
+				up(&driver->serialize);
+				usb_driver_release_interface(driver, interface);
+			}
 		}
+	}
 
-		/* Free up the device itself, including its device number */
-		if (dev->devnum > 0)
-			clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
-		dev->bus->op->deallocate(dev);
+	/* Free up all the children.. */
+	for (i = 0; i < USB_MAXCHILDREN; i++) {
+		struct usb_device **child = dev->children + i;
+		if (*child)
+			usb_disconnect(child);
 	}
-}
 
+	/* remove /proc/bus/usb entry */
+	usbdevfs_remove_device(dev);
+
+	/* Free up the device itself, including its device number */
+	if (dev->devnum > 0)
+		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+
+	usb_free_dev(dev);
+}
 
 /*
  * Connect a new USB device. This basically just initializes
@@ -373,9 +1234,11 @@
 void usb_connect(struct usb_device *dev)
 {
 	int devnum;
-
-	dev->descriptor.bMaxPacketSize0 = 8;  /* XXX fixed 8 bytes for now */
-
+	// FIXME needs locking for SMP!!
+	/* why? this is called only from the hub thread, 
+	 * which hopefully doesn't run on multiple CPU's simulatenously 8-)
+	 */
+	dev->descriptor.bMaxPacketSize0 = 8;  /* Start off at 8 bytes  */
 	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
 	if (devnum < 128) {
 		set_bit(devnum, dev->bus->devmap.devicemap);
@@ -387,287 +1250,572 @@
  * These are the actual routines to send
  * and receive control messages.
  */
-int usb_set_address(struct usb_device *dev)
-{
-	devrequest dr;
 
-	dr.requesttype = 0;
-	dr.request = USB_REQ_SET_ADDRESS;
-	dr.value = dev->devnum;
-	dr.index = 0;
-	dr.length = 0;
+#define GET_TIMEOUT 3
+#define SET_TIMEOUT 3
 
-	return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0);
+int usb_set_address(struct usb_device *dev)
+{
+	return usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
+		0, dev->devnum, 0, NULL, 0, HZ * GET_TIMEOUT);
 }
 
 int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
 {
-	devrequest dr;
-
-	dr.requesttype = 0x80;
-	dr.request = USB_REQ_GET_DESCRIPTOR;
-	dr.value = (type << 8) + index;
-	dr.index = 0;
-	dr.length = size;
+	int i = 5;
+	int result;
+	
+	memset(buf,0,size);	// Make sure we parse really received data
 
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size);
+	while (i--) {
+		if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+			(type << 8) + index, 0, buf, size, HZ * GET_TIMEOUT)) >= 0 ||
+		     result == -EPIPE)
+			break;
+	}
+	return result;
 }
 
-int usb_get_device_descriptor(struct usb_device *dev)
+int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
+		unsigned char type, unsigned char id, void *buf, int size)
 {
-	return usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor));
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
+		(type << 8) + id, ifnum, buf, size, HZ * GET_TIMEOUT);
 }
 
-int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
 {
-	devrequest dr;
-
-	dr.requesttype = USB_RT_HUB | 0x80;
-	dr.request = USB_REQ_GET_DESCRIPTOR;
-	dr.value = (USB_DT_HUB << 8);
-	dr.index = 0;
-	dr.length = size;
-
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, size);
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+		(USB_DT_STRING << 8) + index, langid, buf, size, HZ * GET_TIMEOUT);
 }
 
-int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+int usb_get_device_descriptor(struct usb_device *dev)
 {
-	devrequest dr;
-
-	dr.requesttype = USB_RT_PORT;
-	dr.request = USB_REQ_CLEAR_FEATURE;
-	dr.value = feature;
-	dr.index = port;
-	dr.length = 0;
+	int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor,
+				     sizeof(dev->descriptor));
+	if (ret >= 0) {
+		le16_to_cpus(&dev->descriptor.bcdUSB);
+		le16_to_cpus(&dev->descriptor.idVendor);
+		le16_to_cpus(&dev->descriptor.idProduct);
+		le16_to_cpus(&dev->descriptor.bcdDevice);
+	}
+	return ret;
+}
 
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+int usb_get_status(struct usb_device *dev, int type, int target, void *data)
+{
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2, HZ * GET_TIMEOUT);
 }
 
-int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+int usb_get_protocol(struct usb_device *dev, int ifnum)
 {
-	devrequest dr;
+	unsigned char type;
+	int ret;
 
-	dr.requesttype = USB_RT_PORT;
-	dr.request = USB_REQ_SET_FEATURE;
-	dr.value = feature;
-	dr.index = port;
-	dr.length = 0;
+	if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+	    USB_REQ_GET_PROTOCOL, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+	    0, ifnum, &type, 1, HZ * GET_TIMEOUT)) < 0)
+		return ret;
 
-	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+	return type;
 }
 
-int usb_get_hub_status(struct usb_device *dev, void *data)
+int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol)
 {
-	devrequest dr;
-
-	dr.requesttype = USB_RT_HUB | 0x80;
-	dr.request = USB_REQ_GET_STATUS;
-	dr.value = 0;
-	dr.index = 0;
-	dr.length = 4;
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		protocol, ifnum, NULL, 0, HZ * SET_TIMEOUT);
+}
 
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
+int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
+{
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		(duration << 8) | report_id, ifnum, NULL, 0, HZ * SET_TIMEOUT);
 }
 
-int usb_get_port_status(struct usb_device *dev, int port, void *data)
+void usb_set_maxpacket(struct usb_device *dev)
 {
-	devrequest dr;
+	int i, b;
 
-	dr.requesttype = USB_RT_PORT | 0x80;
-	dr.request = USB_REQ_GET_STATUS;
-	dr.value = 0;
-	dr.index = port;
-	dr.length = 4;
+	for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
+		struct usb_interface *ifp = dev->actconfig->interface + i;
+		struct usb_interface_descriptor *as = ifp->altsetting + ifp->act_altsetting;
+		struct usb_endpoint_descriptor *ep = as->endpoint;
+		int e;
 
-	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
+		for (e=0; e<as->bNumEndpoints; e++) {
+			b = ep[e].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+			if ((ep[e].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+				USB_ENDPOINT_XFER_CONTROL) {	/* Control => bidirectional */
+				dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
+				dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
+				}
+			else if (usb_endpoint_out(ep[e].bEndpointAddress)) {
+				if (ep[e].wMaxPacketSize > dev->epmaxpacketout[b])
+					dev->epmaxpacketout[b] = ep[e].wMaxPacketSize;
+			}
+			else {
+				if (ep[e].wMaxPacketSize > dev->epmaxpacketin [b])
+					dev->epmaxpacketin [b] = ep[e].wMaxPacketSize;
+			}
+		}
+	}
 }
 
-int usb_get_protocol(struct usb_device *dev)
+/*
+ * endp: endpoint number in bits 0-3;
+ *	direction flag in bit 7 (1 = IN, 0 = OUT)
+ */
+int usb_clear_halt(struct usb_device *dev, int pipe)
 {
-	unsigned char buf[8];
-	devrequest dr;
+	int result;
+	__u16 status;
+	int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
+
+/*
+	if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp)))
+		return 0;
+*/
 
-	dr.requesttype = USB_RT_HIDD | 0x80;
-	dr.request = USB_REQ_GET_PROTOCOL;
-	dr.value = 0;
-	dr.index = 1;
-	dr.length = 1;
+	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, HZ * SET_TIMEOUT);
 
-	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1))
-		return -1;
+	/* don't clear if failed */
+	if (result < 0)
+		return result;
 
-	return buf[0];
-}
+	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, endp,
+		&status, sizeof(status), HZ * SET_TIMEOUT);
+	if (result < 0)
+		return result;
 
-int usb_set_protocol(struct usb_device *dev, int protocol)
-{
-	devrequest dr;
+	if (status & 1)
+		return -EPIPE;		/* still halted */
 
-	dr.requesttype = USB_RT_HIDD;
-	dr.request = USB_REQ_SET_PROTOCOL;
-	dr.value = protocol;
-	dr.index = 1;
-	dr.length = 0;
+	usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
-		return -1;
+	/* toggle is reset on clear */
+
+	usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
 
 	return 0;
 }
 
-/* keyboards want a nonzero duration according to HID spec, but
-   mice should use infinity (0) -keryan */
-int usb_set_idle(struct usb_device *dev,  int duration, int report_id)
-{
-	devrequest dr;
-
-	dr.requesttype = USB_RT_HIDD;
-	dr.request = USB_REQ_SET_IDLE;
-	dr.value = (duration << 8) | report_id;
-	dr.index = 1;
-	dr.length = 0;
-
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
-		return -1;
+int usb_set_interface(struct usb_device *dev, int interface, int alternate)
+{
+	struct usb_interface *iface;
+	int ret;
 
+	iface = usb_ifnum_to_if(dev, interface);
+	if (!iface) {
+		warn("selecting invalid interface %d", interface);
+		return -EINVAL;
+	}
+
+	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	    USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
+	    interface, NULL, 0, HZ * 5)) < 0)
+		return ret;
+
+	iface->act_altsetting = alternate;
+	dev->toggle[0] = 0;	/* 9.1.1.5 says to do this */
+	dev->toggle[1] = 0;
+	usb_set_maxpacket(dev);
 	return 0;
 }
 
 int usb_set_configuration(struct usb_device *dev, int configuration)
 {
-	devrequest dr;
-
-	dr.requesttype = 0;
-	dr.request = USB_REQ_SET_CONFIGURATION;
-	dr.value = configuration;
-	dr.index = 0;
-	dr.length = 0;
-
-	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+	int i, ret;
+	struct usb_config_descriptor *cp = NULL;
+	
+	for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
+		if (dev->config[i].bConfigurationValue == configuration) {
+			cp = &dev->config[i];
+			break;
+		}
+	}
+	if (!cp) {
+		warn("selecting invalid configuration %d", configuration);
 		return -1;
+	}
+
+	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	    USB_REQ_SET_CONFIGURATION, 0, configuration, 0, NULL, 0, HZ * SET_TIMEOUT)) < 0)
+		return ret;
+
+	dev->actconfig = cp;
+	dev->toggle[0] = 0;
+	dev->toggle[1] = 0;
+	usb_set_maxpacket(dev);
 
 	return 0;
 }
 
-int usb_get_report(struct usb_device *dev)
+int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type, unsigned char id, void *buf, int size)
 {
-	unsigned char buf[8];
-	devrequest dr;
-
-	dr.requesttype = USB_RT_HIDD | 0x80;
-	dr.request = USB_REQ_GET_REPORT;
-	dr.value = 0x100;
-	dr.index = 1;
-	dr.length = 3;
-
-	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 3))
-		return -1;
+	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+		USB_REQ_GET_REPORT, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		(type << 8) + id, ifnum, buf, size, HZ * GET_TIMEOUT);
+}
 
-	return buf[0];
+int usb_set_report(struct usb_device *dev, int ifnum, unsigned char type, unsigned char id, void *buf, int size)
+{
+	return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+		USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+		(type << 8) + id, ifnum, buf, size, HZ);
 }
 
 int usb_get_configuration(struct usb_device *dev)
 {
-	unsigned int cfgno,size;
-	unsigned char buffer[400];
-	unsigned char * bufptr;
-	
-	bufptr=buffer;
-        for (cfgno=0;cfgno<dev->descriptor.bNumConfigurations;cfgno++) {
-  		/* Get the first 8 bytes - guaranteed */
-	  	if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8))
-	    		return -1;
+	int result;
+	unsigned int cfgno, length;
+	unsigned char buffer[8];
+	unsigned char *bigbuffer;
+	struct usb_config_descriptor *desc =
+		(struct usb_config_descriptor *)buffer;
+
+	if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) {
+		warn("too many configurations");
+		return -1;
+	}
+
+	if (dev->descriptor.bNumConfigurations < 1) {
+		warn("not enough configurations");
+		return -1;
+	}
+
+	dev->config = (struct usb_config_descriptor *)
+		kmalloc(dev->descriptor.bNumConfigurations *
+		sizeof(struct usb_config_descriptor), GFP_KERNEL);
+	if (!dev->config) {
+		err("out of memory");
+		return -1;	
+	}
+	memset(dev->config, 0, dev->descriptor.bNumConfigurations *
+		sizeof(struct usb_config_descriptor));
+
+	dev->rawdescriptors = (char **)kmalloc(sizeof(char *) *
+		dev->descriptor.bNumConfigurations, GFP_KERNEL);
+	if (!dev->rawdescriptors) {
+		err("out of memory");
+		return -1;
+	}
+
+	for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) {
+		/* We grab the first 8 bytes so we know how long the whole */
+		/*  configuration is */
+		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
+		if (result < 8) {
+			if (result < 0)
+				err("unable to get descriptor");
+			else
+				err("config descriptor too short (expected %i, got %i)", 8, result);
+			goto err;
+		}
 
   	  	/* Get the full buffer */
-	  	size = *(unsigned short *)(bufptr+2);
-	  	if (bufptr+size > buffer+sizeof(buffer))
-	  	{
-			printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size);
-			size = buffer+sizeof(buffer)-bufptr;
+		length = le16_to_cpu(desc->wTotalLength);
+
+		bigbuffer = kmalloc(length, GFP_KERNEL);
+		if (!bigbuffer) {
+			err("unable to allocate memory for configuration descriptors");
+			result = -ENOMEM;
+			goto err;
+		}
+
+		/* Now that we know the length, get the whole thing */
+		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);
+		if (result < 0) {
+			err("couldn't get all of config descriptors");
+			kfree(bigbuffer);
+			goto err;
+		}	
+	
+		if (result < length) {
+			err("config descriptor too short (expected %i, got %i)", length, result);
+			kfree(bigbuffer);
+			goto err;
+		}
+
+		dev->rawdescriptors[cfgno] = bigbuffer;
+
+		result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
+		if (result > 0)
+			dbg("descriptor data left");
+		else if (result < 0) {
+			result = -1;
+			goto err;
+		}
+	}
+
+	return 0;
+err:
+	dev->descriptor.bNumConfigurations = cfgno;
+	return result;
+}
+
+/*
+ * usb_string:
+ *	returns string length (> 0) or error (< 0)
+ */
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
+{
+	unsigned char *tbuf;
+	int err;
+	unsigned int u, idx;
+
+	if (size <= 0 || !buf || !index)
+		return -EINVAL;
+	buf[0] = 0;
+	tbuf = kmalloc(256, GFP_KERNEL);
+	if (!tbuf)
+		return -ENOMEM;
+
+	/* get langid for strings if it's not yet known */
+	if (!dev->have_langid) {
+		err = usb_get_string(dev, 0, 0, tbuf, 4);
+		if (err < 0) {
+			err("error getting string descriptor 0 (error=%d)", err);
+			goto errout;
+		} else if (tbuf[0] < 4) {
+			err("string descriptor 0 too short");
+			err = -EINVAL;
+			goto errout;
+		} else {
+			dev->have_langid = -1;
+			dev->string_langid = tbuf[2] | (tbuf[3]<< 8);
+				/* always use the first langid listed */
+			dbg("USB device number %d default language ID 0x%x",
+				dev->devnum, dev->string_langid);
 		}
-		if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size))
-			return -1;
-			
-		/* Prepare for next configuration */
-		bufptr+=size;
 	}
-	return usb_parse_configuration(dev, buffer, size);
+
+	/*
+	 * Just ask for a maximum length string and then take the length
+	 * that was returned.
+	 */
+	err = usb_get_string(dev, dev->string_langid, index, tbuf, 255);
+	if (err < 0)
+		goto errout;
+
+	size--;		/* leave room for trailing NULL char in output buffer */
+	for (idx = 0, u = 2; u < err; u += 2) {
+		if (idx >= size)
+			break;
+		if (tbuf[u+1])			/* high byte */
+			buf[idx++] = '?';  /* non-ASCII character */
+		else
+			buf[idx++] = tbuf[u];
+	}
+	buf[idx] = 0;
+	err = idx;
+
+ errout:
+	kfree(tbuf);
+	return err;
 }
 
 /*
  * By the time we get here, the device has gotten a new device ID
  * and is in the default state. We need to identify the thing and
  * get the ball rolling..
+ *
+ * Returns 0 for success, != 0 for error.
  */
-void usb_new_device(struct usb_device *dev)
+int usb_new_device(struct usb_device *dev)
 {
-	int addr, i;
+	int err;
 
-	printk("USB new device connect, assigned device number %d\n",
-		dev->devnum);
-
-	dev->maxpacketsize = 0;		/* Default to 8 byte max packet size */
-
-	addr = dev->devnum;
-	dev->devnum = 0;
+	info("USB new device connect, assigned device number %d", dev->devnum);
+ 
+	/* USB v1.1 5.5.3 */
+	/* We read the first 8 bytes from the device descriptor to get to */
+	/*  the bMaxPacketSize0 field. Then we set the maximum packet size */
+	/*  for the control pipe, and retrieve the rest */
+	dev->epmaxpacketin [0] = 8;
+	dev->epmaxpacketout[0] = 8;
+
+	err = usb_set_address(dev);
+	if (err < 0) {
+		err("USB device not accepting new address (error=%d)", err);
+		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+		dev->devnum = -1;
+		return 1;
+	}
 
-	/* Slow devices */
-	for (i = 0; i < 5; i++) {
-		if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8))
-			break;
+	wait_ms(10);	/* Let the SET_ADDRESS settle */
 
-		printk("get_descriptor failed, waiting\n");
-		wait_ms(200);
+	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
+	if (err < 8) {
+		if (err < 0)
+			err("USB device not responding, giving up (error=%d)", err);
+		else
+			err("USB device descriptor short read (expected %i, got %i)",8,err);
+		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+		dev->devnum = -1;
+		return 1;
+	}
+	dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
+	dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
+
+	err = usb_get_device_descriptor(dev);
+	if (err < sizeof(dev->descriptor)) {
+		if (err < 0)
+			err("unable to get device descriptor (error=%d)", err);
+		else
+			err("USB device descriptor short read (expected %i, got %i)", sizeof(dev->descriptor), err);
+	
+		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+		dev->devnum = -1;
+		return 1;
 	}
-	if (i == 5) {
-		printk("giving up\n");
-		return;
+
+	err = usb_get_configuration(dev);
+	if (err < 0) {
+		err("unable to get configuration (error=%d)", err);
+		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+		dev->devnum = -1;
+		return 1;
 	}
 
-#if 0
-	printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0);
-#endif
-	switch (dev->descriptor.bMaxPacketSize0) {
-		case 8: dev->maxpacketsize = 0; break;
-		case 16: dev->maxpacketsize = 1; break;
-		case 32: dev->maxpacketsize = 2; break;
-		case 64: dev->maxpacketsize = 3; break;
+	dev->actconfig = dev->config;
+	usb_set_maxpacket(dev);
+
+	/* we set the default configuration here */
+	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+		err("failed to set default configuration");
+		return -1;
 	}
-#if 0
-	printk("dev->mps: %d\n", dev->maxpacketsize);
+
+	dbg("new device strings: Mfr=%d, Product=%d, SerialNumber=%d",
+		dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
+#ifdef DEBUG
+	if (dev->descriptor.iManufacturer)
+		usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
+	if (dev->descriptor.iProduct)
+		usb_show_string(dev, "Product", dev->descriptor.iProduct);
+	if (dev->descriptor.iSerialNumber)
+		usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
 #endif
 
-	dev->devnum = addr;
+	/* now that the basic setup is over, add a /proc/bus/usb entry */
+	usbdevfs_add_device(dev);
 
-	if (usb_set_address(dev)) {
-		printk("Unable to set address\n");
-		/* FIXME: We should disable the port */
-		return;
-	}
+	/* find drivers willing to handle this device */
+	usb_find_drivers(dev);
 
-	wait_ms(10);	/* Let the SET_ADDRESS settle */
+	return 0;
+}
 
-	if (usb_get_device_descriptor(dev)) {
-		printk("Unable to get device descriptor\n");
-		return;
-	}
+static int usb_open(struct inode * inode, struct file * file)
+{
+	int minor = MINOR(inode->i_rdev);
+	struct usb_driver *c = usb_minors[minor/16];
+	int err = -ENODEV;
 
-	if (usb_get_configuration(dev)) {
-		printk("Unable to get configuration\n");
-		return;
+	if (!c || !c->fops)
+		return err;
+
+	file->f_op = c->fops;
+
+	return file->f_op->open(inode,file);
+}
+
+static struct file_operations usb_fops = {
+	open:		usb_open,
+};
+
+int usb_major_init(void)
+{
+	if (register_chrdev(USB_MAJOR,"usb",&usb_fops)) {
+		err("unable to get major %d for usb devices", USB_MAJOR);
+		return -EBUSY;
 	}
+	return 0;
+}
 
-#if 0
-	printk("Vendor: %X\n", dev->descriptor.idVendor);
-	printk("Product: %X\n", dev->descriptor.idProduct);
-#endif
+void usb_major_cleanup(void)
+{
+	unregister_chrdev(USB_MAJOR, "usb");
+}
 
-	usb_device_descriptor(dev);
+
+#ifdef CONFIG_PROC_FS
+struct list_head *usb_driver_get_list(void)
+{
+	return &usb_driver_list;
 }
 
-int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+struct list_head *usb_bus_get_list(void)
 {
-	return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
+	return &usb_bus_list;
 }
+#endif
+
+/*
+ * USB may be built into the kernel or be built as modules.
+ * If the USB core [and maybe a host controller driver] is built
+ * into the kernel, and other device drivers are built as modules,
+ * then these symbols need to be exported for the modules to use.
+ */
+EXPORT_SYMBOL(usb_ifnum_to_if);
+
+EXPORT_SYMBOL(usb_register);
+EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL(usb_scan_devices);
+EXPORT_SYMBOL(usb_alloc_bus);
+EXPORT_SYMBOL(usb_free_bus);
+EXPORT_SYMBOL(usb_register_bus);
+EXPORT_SYMBOL(usb_deregister_bus);
+EXPORT_SYMBOL(usb_alloc_dev);
+EXPORT_SYMBOL(usb_free_dev);
+EXPORT_SYMBOL(usb_inc_dev_use);
+
+EXPORT_SYMBOL(usb_driver_claim_interface);
+EXPORT_SYMBOL(usb_interface_claimed);
+EXPORT_SYMBOL(usb_driver_release_interface);
+
+EXPORT_SYMBOL(usb_init_root_hub);
+EXPORT_SYMBOL(usb_root_hub_string);
+EXPORT_SYMBOL(usb_new_device);
+EXPORT_SYMBOL(usb_reset_device);
+EXPORT_SYMBOL(usb_connect);
+EXPORT_SYMBOL(usb_disconnect);
+
+EXPORT_SYMBOL(usb_check_bandwidth);
+EXPORT_SYMBOL(usb_claim_bandwidth);
+EXPORT_SYMBOL(usb_release_bandwidth);
+
+EXPORT_SYMBOL(usb_set_address);
+EXPORT_SYMBOL(usb_get_descriptor);
+EXPORT_SYMBOL(usb_get_class_descriptor);
+EXPORT_SYMBOL(__usb_get_extra_descriptor);
+EXPORT_SYMBOL(usb_get_device_descriptor);
+EXPORT_SYMBOL(usb_get_string);
+EXPORT_SYMBOL(usb_string);
+EXPORT_SYMBOL(usb_get_protocol);
+EXPORT_SYMBOL(usb_set_protocol);
+EXPORT_SYMBOL(usb_get_report);
+EXPORT_SYMBOL(usb_set_report);
+EXPORT_SYMBOL(usb_set_idle);
+EXPORT_SYMBOL(usb_clear_halt);
+EXPORT_SYMBOL(usb_set_interface);
+EXPORT_SYMBOL(usb_get_configuration);
+EXPORT_SYMBOL(usb_set_configuration);
+
+EXPORT_SYMBOL(usb_get_current_frame_number);
+
+EXPORT_SYMBOL(usb_alloc_urb);
+EXPORT_SYMBOL(usb_free_urb);
+EXPORT_SYMBOL(usb_submit_urb);
+EXPORT_SYMBOL(usb_unlink_urb);
 
+EXPORT_SYMBOL(usb_control_msg);
+EXPORT_SYMBOL(usb_bulk_msg);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb.h linux.18p8/drivers/usb/usb.h
--- linux.vanilla/drivers/usb/usb.h	Fri Apr 21 12:46:37 2000
+++ linux.18p8/drivers/usb/usb.h	Thu Jan  1 01:00:00 1970
@@ -1,376 +0,0 @@
-#ifndef __LINUX_USB_H
-#define __LINUX_USB_H
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/sched.h>
-
-static __inline__ void wait_ms(unsigned int ms)
-{
-        current->state = TASK_UNINTERRUPTIBLE;
-        schedule_timeout(1 + ms * HZ / 1000);
-}
-
-
-typedef struct {
-  unsigned char requesttype;
-  unsigned char request;
-  unsigned short value;
-  unsigned short index;
-  unsigned short length;
-} devrequest;
-
-/*
- * Class codes
- */
-#define USB_CLASS_HUB			9
-
-/*
- * Descriptor types
- */
-#define USB_DT_DEVICE			0x01
-#define USB_DT_CONFIG			0x02
-#define USB_DT_STRING			0x03
-#define USB_DT_INTERFACE		0x04
-#define USB_DT_ENDPOINT			0x05
-
-#define USB_DT_HUB			0x29
-#define USB_DT_HID			0x21
-
-/*
- * Standard requests
- */
-#define USB_REQ_GET_STATUS		0x00
-#define USB_REQ_CLEAR_FEATURE		0x01
-/* 0x02 is reserved */
-#define USB_REQ_SET_FEATURE		0x03
-/* 0x04 is reserved */
-#define USB_REQ_SET_ADDRESS		0x05
-#define USB_REQ_GET_DESCRIPTOR		0x06
-#define USB_REQ_SET_DESCRIPTOR		0x07
-#define USB_REQ_GET_CONFIGURATION	0x08
-#define USB_REQ_SET_CONFIGURATION	0x09
-#define USB_REQ_GET_INTERFACE		0x0A
-#define USB_REQ_SET_INTERFACE		0x0B
-#define USB_REQ_SYNCH_FRAME		0x0C
-
-/*
- * HIDD requests
- */
-#define USB_REQ_GET_REPORT		0x01
-#define USB_REQ_GET_IDLE		0x02
-#define USB_REQ_GET_PROTOCOL		0x03
-#define USB_REQ_SET_REPORT		0x09
-#define USB_REQ_SET_IDLE		0x0A
-#define USB_REQ_SET_PROTOCOL		0x0B
-
-#define USB_TYPE_STANDARD		(0x00 << 5)
-#define USB_TYPE_CLASS			(0x01 << 5)
-#define USB_TYPE_VENDOR			(0x02 << 5)
-#define USB_TYPE_RESERVED		(0x03 << 5)
-
-#define USB_RECIP_DEVICE		0x00
-#define USB_RECIP_INTERFACE		0x01
-#define USB_RECIP_ENDPOINT		0x02
-#define USB_RECIP_OTHER			0x03
-
-/*
- * Request target types.
- */
-#define USB_RT_DEVICE			0x00
-#define USB_RT_INTERFACE		0x01
-#define USB_RT_ENDPOINT			0x02
-
-#define USB_RT_HUB			(USB_TYPE_CLASS | USB_RECIP_DEVICE)
-#define USB_RT_PORT			(USB_TYPE_CLASS | USB_RECIP_OTHER)
-
-#define USB_RT_HIDD			(USB_TYPE_CLASS | USB_RECIP_INTERFACE)
-
-/*
- * USB device number allocation bitmap. There's one bitmap
- * per USB tree.
- */
-struct usb_devmap {
-	unsigned long devicemap[128 / (8*sizeof(unsigned long))];
-};
-
-/*
- * This is a USB device descriptor.
- *
- * USB device information
- *
- */
-
-#define USB_MAXCONFIG		8
-#define USB_MAXINTERFACES	32
-#define USB_MAXENDPOINTS	32
-
-struct usb_device_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u16 bcdUSB;
-	__u8  bDeviceClass;
-	__u8  bDeviceSubClass;
-	__u8  bDeviceProtocol;
-	__u8  bMaxPacketSize0;
-	__u16 idVendor;
-	__u16 idProduct;
-	__u16 bcdDevice;
-	__u8  iManufacturer;
-	__u8  iProduct;
-	__u8  iSerialNumber;
-	__u8  bNumConfigurations;
-};
-
-/* Endpoint descriptor */
-struct usb_endpoint_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bEndpointAddress;
-	__u8  bmAttributes;
-	__u16 wMaxPacketSize;
-	__u8  bInterval;
-	void  *audio;
-};
-
-/* Interface descriptor */
-struct usb_interface_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bInterfaceNumber;
-	__u8  bAlternateSetting;
-	__u8  bNumEndpoints;
-	__u8  bInterfaceClass;
-	__u8  bInterfaceSubClass;
-	__u8  bInterfaceProtocol;
-	__u8  iInterface;
-
-	struct usb_endpoint_descriptor *endpoint;
-	void  *audio;
-};
-
-/* Configuration descriptor information.. */
-struct usb_config_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u16 wTotalLength;
-	__u8  bNumInterfaces;
-	__u8  bConfigurationValue;
-	__u8  iConfiguration;
-	__u8  bmAttributes;
-	__u8  MaxPower;
-
-	struct usb_interface_descriptor *interface;
-};
-
-/* String descriptor */
-struct usb_string_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-};
-
-/* Hub descriptor */
-struct usb_hub_descriptor {
-	__u8  bLength;
-	__u8  bDescriptorType;
-	__u8  bNbrPorts;
-	__u16 wHubCharacteristics;
-	__u8  bPwrOn2PwrGood;
-	__u8  bHubContrCurrent;
-	/* DeviceRemovable and PortPwrCtrlMask want to be variable-length 
-	   bitmaps that hold max 256 entries, but for now they're ignored */
-	__u8  filler;
-};
-
-struct usb_device;
-
-struct usb_driver {
-	const char * name;
-	int (*probe)(struct usb_device *);
-	void (*disconnect)(struct usb_device *);
-	struct list_head driver_list;
-};
-
-/*
- * Pointer to a device endpoint interrupt function -greg
- *   Parameters:
- *     int status - This needs to be defined.  Right now each HCD
- *         passes different transfer status bits back.  Don't use it
- *         until we come up with a common meaning.
- *     void *buffer - This is a pointer to the data used in this
- *         USB transfer.
- *     void *dev_id - This is a user defined pointer set when the IRQ
- *         is requested that is passed back.
- */
-typedef int (*usb_device_irq)(int, void *, void *);
-
-struct usb_operations {
-	struct usb_device *(*allocate)(struct usb_device *);
-	int (*deallocate)(struct usb_device *);
-	int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int);
-	int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
-};
-
-/*
- * Allocated per bus we have
- */
-struct usb_bus {
-	struct usb_devmap devmap;       /* Device map */
-	struct usb_operations *op;      /* Operations (specific to the HC) */
-	struct usb_device *root_hub;    /* Root hub */
-	void *hcpriv;                   /* Host Controller private data */
-};
-
-
-#define USB_MAXCHILDREN (8)
-
-struct usb_device {
-	int devnum;						/* Device number on USB bus */
-	int slow;						/* Slow device? */
-	int maxpacketsize;					/* Maximum packet size */
-
-	struct usb_bus *bus;					/* Bus we're apart of */
-	struct usb_driver *driver;				/* Driver */
-	struct usb_device_descriptor descriptor;		/* Descriptor */
-	struct usb_config_descriptor *config;			/* All of the configs */
-	struct usb_device *parent;
-  
-	/*
-	 * Child devices - these can be either new devices
-	 * (if this is a hub device), or different instances
-	 * of this same device.
-	 *
-	 * Each instance needs its own set of data structuctures.
-	 */
-
-	int maxchild;			/* Number of ports if hub */
-	struct usb_device *children[USB_MAXCHILDREN];
-
-	void *hcpriv;			/* Host Controller private data */
-	void *private;			/* Upper layer private data */
-};
-
-extern int usb_register(struct usb_driver *);
-extern void usb_deregister(struct usb_driver *);
-
-extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
-
-extern void usb_init_root_hub(struct usb_device *dev);
-extern void usb_connect(struct usb_device *dev);
-extern void usb_disconnect(struct usb_device **);
-extern void usb_device_descriptor(struct usb_device *dev);
-
-extern int  usb_parse_configuration(struct usb_device *dev, void *buf, int len);
-
-/*
- * Calling this entity a "pipe" is glorifying it. A USB pipe
- * is something embarrassingly simple: it basically consists
- * of the following information:
- *  - device number (7 bits)
- *  - endpoint number (4 bits)
- *  - current Data0/1 state (1 bit)
- *  - direction (1 bit)
- *  - speed (1 bit)
- *  - max packet size (2 bits: 8, 16, 32 or 64)
- *  - pipe type (2 bits: control, interrupt, bulk, isochronous)
- *
- * That's 18 bits. Really. Nothing more. And the USB people have
- * documented these eighteen bits as some kind of glorious
- * virtual data structure.
- *
- * Let's not fall in that trap. We'll just encode it as a simple
- * unsigned int. The encoding is:
- *
- *  - device:		bits 8-14
- *  - endpoint:		bits 15-18
- *  - Data0/1:		bit 19
- *  - direction:	bit 7		(0 = Host-to-Device, 1 = Device-to-Host)
- *  - speed:		bit 26		(0 = High, 1 = Low Speed)
- *  - max size:		bits 0-1	(00 = 8, 01 = 16, 10 = 32, 11 = 64)
- *  - pipe type:	bits 30-31	(00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk)
- *
- * Why? Because it's arbitrary, and whatever encoding we select is really
- * up to us. This one happens to share a lot of bit positions with the UCHI
- * specification, so that much of the uhci driver can just mask the bits
- * appropriately.
- */
-
-#define usb_maxpacket(pipe)	(8 << ((pipe) & 3))
-#define usb_packetid(pipe)	(((pipe) & 0x80) ? 0x69 : 0xE1)
-
-#define usb_pipedevice(pipe)	(((pipe) >> 8) & 0x7f)
-#define usb_pipeendpoint(pipe)	(((pipe) >> 15) & 0xf)
-#define usb_pipedata(pipe)	(((pipe) >> 19) & 1)
-#define usb_pipeout(pipe)	(((pipe) & 0x80) == 0)
-#define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
-
-#define usb_pipetype(pipe)	(((pipe) >> 30) & 3)
-#define usb_pipeisoc(pipe)	(usb_pipetype((pipe)) == 0)
-#define usb_pipeint(pipe)	(usb_pipetype((pipe)) == 1)
-#define usb_pipecontrol(pipe)	(usb_pipetype((pipe)) == 2)
-#define usb_pipebulk(pipe)	(usb_pipetype((pipe)) == 3)
-
-#define usb_pipe_endpdev(pipe)	(((pipe) >> 8) & 0x7ff)
-
-static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
-{
-	return (dev->devnum << 8) | (endpoint << 15) | (dev->slow << 26) | dev->maxpacketsize;
-}
-
-static inline unsigned int __default_pipe(struct usb_device *dev)
-{
-	return (dev->slow << 26);
-}
-
-/* Create control pipes.. */
-#define usb_sndctrlpipe(dev,endpoint)	((2 << 30) | __create_pipe(dev,endpoint))
-#define usb_rcvctrlpipe(dev,endpoint)	((2 << 30) | __create_pipe(dev,endpoint) | 0x80)
-#define usb_snddefctrl(dev)		((2 << 30) | __default_pipe(dev))
-#define usb_rcvdefctrl(dev)		((2 << 30) | __default_pipe(dev) | 0x80)
-
-/* Create .. */
-
-/*
- * Send and receive control messages..
- */
-void usb_new_device(struct usb_device *dev);
-int usb_set_address(struct usb_device *dev);
-int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned
-char descindex, void *buf, int size);
-int usb_get_device_descriptor(struct usb_device *dev);
-int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size);
-int usb_clear_port_feature(struct usb_device *dev, int port, int feature);
-int usb_set_port_feature(struct usb_device *dev, int port, int feature);
-int usb_get_hub_status(struct usb_device *dev, void *data);
-int usb_get_port_status(struct usb_device *dev, int port, void *data);
-int usb_get_protocol(struct usb_device *dev);
-int usb_set_protocol(struct usb_device *dev, int protocol);
-int usb_set_idle(struct usb_device *dev, int duration, int report_id);
-int usb_set_configuration(struct usb_device *dev, int configuration);
-int usb_get_report(struct usb_device *dev);
-
-/*
- * Debugging helpers..
- */
-void usb_show_device_descriptor(struct usb_device_descriptor *);
-void usb_show_config_descriptor(struct usb_config_descriptor *);
-void usb_show_interface_descriptor(struct usb_interface_descriptor *);
-void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *);
-void usb_show_hub_descriptor(struct usb_hub_descriptor *);
-void usb_show_device(struct usb_device *);
-
-/*
- * Audio parsing helpers
- */
-
-#ifdef CONFIG_USB_AUDIO
-void usb_audio_interface(struct usb_interface_descriptor *, u8 *);
-void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *);
-#else
-extern inline void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) {}
-extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) {}
-#endif
-
-#endif
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usbkbd.c linux.18p8/drivers/usb/usbkbd.c
--- linux.vanilla/drivers/usb/usbkbd.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usbkbd.c	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,262 @@
+/*
+ * $Id: usbkbd.c,v 1.11 2000/05/29 09:01:52 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  USB HIDBP Keyboard support
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+static unsigned char usb_kbd_keycode[256] = {
+	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+	 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+	 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95,
+	120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,
+	115,114,  0,  0,  0,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+	150,158,159,128,136,177,178,176,142,152,173,140
+};
+
+struct usb_kbd {
+	struct input_dev dev;
+	unsigned char new[8];
+	unsigned char old[8];
+	struct urb irq, led;
+	devrequest dr;
+	unsigned char leds;
+	char name[128];
+	int open;
+};
+
+static void usb_kbd_irq(struct urb *urb)
+{
+	struct usb_kbd *kbd = urb->context;
+	int i;
+
+	if (urb->status) return;
+
+	for (i = 0; i < 8; i++)
+		input_report_key(&kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
+
+	for (i = 2; i < 8; i++) {
+
+		if (kbd->old[i] > 3 && memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) {
+			if (usb_kbd_keycode[kbd->old[i]])
+				input_report_key(&kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
+			else
+				info("Unknown key (scancode %#x) released.", kbd->old[i]);
+		}
+
+		if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
+			if (usb_kbd_keycode[kbd->new[i]])
+				input_report_key(&kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
+			else
+				info("Unknown key (scancode %#x) pressed.", kbd->new[i]);
+		}
+	}
+
+	memcpy(kbd->old, kbd->new, 8);
+}
+
+int usb_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct usb_kbd *kbd = dev->private;
+
+	if (type != EV_LED) return -1;
+
+	if (kbd->led.status == -EINPROGRESS) {
+		warn("had to kill led urb");
+		usb_unlink_urb(&kbd->led);
+	}
+
+	kbd->leds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
+		    (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
+		    (!!test_bit(LED_NUML,    dev->led));
+
+
+	if (usb_submit_urb(&kbd->led)) {
+		err("usb_submit_urb(leds) failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void usb_kbd_led(struct urb *urb)
+{
+	if (urb->status)
+		warn("led urb status %d received", urb->status);
+}
+
+static int usb_kbd_open(struct input_dev *dev)
+{
+	struct usb_kbd *kbd = dev->private;
+
+	if (kbd->open++)
+		return 0;
+
+	if (usb_submit_urb(&kbd->irq))
+		return -EIO;
+
+	return 0;
+}
+
+static void usb_kbd_close(struct input_dev *dev)
+{
+	struct usb_kbd *kbd = dev->private;
+
+	if (!--kbd->open)
+		usb_unlink_urb(&kbd->irq);
+}
+
+static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_kbd *kbd;
+	int i, pipe, maxp;
+	char *buf;
+
+	if (dev->descriptor.bNumConfigurations != 1) return NULL;
+	interface = dev->config[0].interface[ifnum].altsetting + 0;
+
+	if (interface->bInterfaceClass != 3) return NULL;
+	if (interface->bInterfaceSubClass != 1) return NULL;
+	if (interface->bInterfaceProtocol != 1) return NULL;
+	if (interface->bNumEndpoints != 1) return NULL;
+
+	endpoint = interface->endpoint + 0;
+	if (!(endpoint->bEndpointAddress & 0x80)) return NULL;
+	if ((endpoint->bmAttributes & 3) != 3) return NULL;
+
+	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	usb_set_protocol(dev, interface->bInterfaceNumber, 0);
+	usb_set_idle(dev, interface->bInterfaceNumber, 0, 0);
+
+	if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
+	memset(kbd, 0, sizeof(struct usb_kbd));
+
+	kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+	kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
+
+	for (i = 0; i < 255; i++)
+		set_bit(usb_kbd_keycode[i], kbd->dev.keybit);
+	clear_bit(0, kbd->dev.keybit);
+	
+	kbd->dev.private = kbd;
+	kbd->dev.event = usb_kbd_event;
+	kbd->dev.open = usb_kbd_open;
+	kbd->dev.close = usb_kbd_close;
+
+	FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
+		usb_kbd_irq, kbd, endpoint->bInterval);
+
+	kbd->dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	kbd->dr.request = USB_REQ_SET_REPORT;
+	kbd->dr.value = 0x200;
+	kbd->dr.index = interface->bInterfaceNumber;
+	kbd->dr.length = 1;
+
+	kbd->dev.name = kbd->name;
+	kbd->dev.idbus = BUS_USB;
+	kbd->dev.idvendor = dev->descriptor.idVendor;
+	kbd->dev.idproduct = dev->descriptor.idProduct;
+	kbd->dev.idversion = dev->descriptor.bcdDevice;
+
+	if (!(buf = kmalloc(63, GFP_KERNEL))) {
+		kfree(kbd);
+		return NULL;
+	}
+
+	if (dev->descriptor.iManufacturer &&
+		usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
+			strcat(kbd->name, buf);
+	if (dev->descriptor.iProduct &&
+		usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
+			sprintf(kbd->name, "%s %s", kbd->name, buf);
+
+	if (!strlen(kbd->name))
+		sprintf(kbd->name, "USB HIDBP Keyboard %04x:%04x",
+			kbd->dev.idvendor, kbd->dev.idproduct);
+
+	kfree(buf);
+
+	FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, 0),
+		(void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd);
+			
+	input_register_device(&kbd->dev);
+
+	printk(KERN_INFO "input%d: %s on on usb%d:%d.%d\n",
+		 kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum);
+
+	return kbd;
+}
+
+static void usb_kbd_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_kbd *kbd = ptr;
+	usb_unlink_urb(&kbd->irq);
+	input_unregister_device(&kbd->dev);
+	kfree(kbd);
+}
+
+static struct usb_driver usb_kbd_driver = {
+	name:		"keyboard",
+	probe:		usb_kbd_probe,
+	disconnect:	usb_kbd_disconnect
+};
+
+static int __init usb_kbd_init(void)
+{
+	usb_register(&usb_kbd_driver);
+	return 0;
+}
+
+static void __exit usb_kbd_exit(void)
+{
+	usb_deregister(&usb_kbd_driver);
+}
+
+module_init(usb_kbd_init);
+module_exit(usb_kbd_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usbmouse.c linux.18p8/drivers/usb/usbmouse.c
--- linux.vanilla/drivers/usb/usbmouse.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/usbmouse.c	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,187 @@
+/*
+ * $Id: usbmouse.c,v 1.5 2000/05/29 09:01:52 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  USB HIDBP Mouse support
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+struct usb_mouse {
+	signed char data[8];
+	char name[128];
+	struct input_dev dev;
+	struct urb irq;
+	int open;
+};
+
+static void usb_mouse_irq(struct urb *urb)
+{
+	struct usb_mouse *mouse = urb->context;
+	signed char *data = mouse->data;
+	struct input_dev *dev = &mouse->dev;
+
+	if (urb->status) return;
+
+	input_report_key(dev, BTN_LEFT,   data[0] & 0x01);
+	input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);
+	input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
+	input_report_key(dev, BTN_SIDE,   data[0] & 0x08);
+	input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);
+
+	input_report_rel(dev, REL_X,     data[1]);
+	input_report_rel(dev, REL_Y,     data[2]);
+	input_report_rel(dev, REL_WHEEL, data[3]);
+}
+
+static int usb_mouse_open(struct input_dev *dev)
+{
+	struct usb_mouse *mouse = dev->private;
+
+	if (mouse->open++)
+		return 0;
+
+	if (usb_submit_urb(&mouse->irq))
+		return -EIO;
+
+	return 0;
+}
+
+static void usb_mouse_close(struct input_dev *dev)
+{
+	struct usb_mouse *mouse = dev->private;
+
+	if (!--mouse->open)
+		usb_unlink_urb(&mouse->irq);
+}
+
+static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_mouse *mouse;
+	int pipe, maxp;
+	char *buf;
+
+	if (dev->descriptor.bNumConfigurations != 1) return NULL;
+	interface = dev->config[0].interface[ifnum].altsetting + 0;
+
+	if (interface->bInterfaceClass != 3) return NULL;
+	if (interface->bInterfaceSubClass != 1) return NULL;
+	if (interface->bInterfaceProtocol != 2) return NULL;
+	if (interface->bNumEndpoints != 1) return NULL;
+
+	endpoint = interface->endpoint + 0;
+	if (!(endpoint->bEndpointAddress & 0x80)) return NULL;
+	if ((endpoint->bmAttributes & 3) != 3) return NULL;
+
+	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	usb_set_idle(dev, interface->bInterfaceNumber, 0, 0);
+
+	if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL;
+	memset(mouse, 0, sizeof(struct usb_mouse));
+
+	mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+	mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+	mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+	mouse->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+	mouse->dev.relbit[0] |= BIT(REL_WHEEL);
+
+	mouse->dev.private = mouse;
+	mouse->dev.open = usb_mouse_open;
+	mouse->dev.close = usb_mouse_close;
+
+	mouse->dev.name = mouse->name;
+	mouse->dev.idbus = BUS_USB;
+	mouse->dev.idvendor = dev->descriptor.idVendor;
+	mouse->dev.idproduct = dev->descriptor.idProduct;
+	mouse->dev.idversion = dev->descriptor.bcdDevice;
+
+	if (!(buf = kmalloc(63, GFP_KERNEL))) {
+		kfree(mouse);
+		return NULL;
+	}
+
+	if (dev->descriptor.iManufacturer &&
+		usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
+			strcat(mouse->name, buf);
+	if (dev->descriptor.iProduct &&
+		usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
+			sprintf(mouse->name, "%s %s", mouse->name, buf);
+
+	if (!strlen(mouse->name))
+		sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x",
+			mouse->dev.idvendor, mouse->dev.idproduct);
+
+	kfree(buf);
+
+	FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
+		usb_mouse_irq, mouse, endpoint->bInterval);
+
+	input_register_device(&mouse->dev);
+
+	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
+		 mouse->dev.number, mouse->name, dev->bus->busnum, dev->devnum, ifnum);
+
+	return mouse;
+}
+
+static void usb_mouse_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_mouse *mouse = ptr;
+	usb_unlink_urb(&mouse->irq);
+	input_unregister_device(&mouse->dev);
+	kfree(mouse);
+}
+
+static struct usb_driver usb_mouse_driver = {
+	name:		"usb_mouse",
+	probe:		usb_mouse_probe,
+	disconnect:	usb_mouse_disconnect,
+};
+
+static int __init usb_mouse_init(void)
+{
+	usb_register(&usb_mouse_driver);
+	return 0;
+}
+
+static void __exit usb_mouse_exit(void)
+{
+	usb_deregister(&usb_mouse_driver);
+}
+
+module_init(usb_mouse_init);
+module_exit(usb_mouse_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/uss720.c linux.18p8/drivers/usb/uss720.c
--- linux.vanilla/drivers/usb/uss720.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/uss720.c	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,663 @@
+/*****************************************************************************/
+
+/*
+ *	uss720.c  --  USS720 USB Parport Cable.
+ *
+ *	Copyright (C) 1999
+ *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Based on parport_pc.c
+ *
+ *  History:
+ *   0.1  04.08.99  Created
+ *   0.2  07.08.99  Some fixes mainly suggested by Tim Waugh
+ *		    Interrupt handling currently disabled because
+ *		    usb_request_irq crashes somewhere within ohci.c
+ *		    for no apparent reason (that is for me, anyway)
+ *		    ECP currently untested
+ *   0.3  10.08.99  fixing merge errors
+ *   0.4  13.08.99  Added Vendor/Product ID of Brad Hard's cable
+ *   0.5  20.09.99  usb_control_msg wrapper used
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/parport.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/* --------------------------------------------------------------------- */
+
+struct parport_uss720_private {
+	struct usb_device *usbdev;
+	void *irqhandle;
+	unsigned int irqpipe;
+	unsigned char reg[7];  /* USB registers */
+};
+
+/* --------------------------------------------------------------------- */
+
+static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	static const unsigned char regindex[9] = {
+		4, 0, 1, 5, 5, 0, 2, 3, 6
+	};
+	int ret;
+
+	if (!usbdev)
+		return -1;
+	ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev,0), 3, 0xc0, ((unsigned int)reg) << 8, 0, priv->reg, 7, HZ);
+	if (ret) {
+		printk(KERN_DEBUG "uss720: get_1284_register(%d) failed, status 0x%x\n",
+		       (unsigned int)reg, ret);
+	} else {
+#if 0
+		printk(KERN_DEBUG "uss720: get_1284_register(%d) return %02x %02x %02x %02x %02x %02x %02x\n",
+		       (unsigned int)reg, (unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
+		       (unsigned int)priv->reg[2], (unsigned int)priv->reg[3], (unsigned int)priv->reg[4],
+		       (unsigned int)priv->reg[5], (unsigned int)priv->reg[6]);
+#endif
+		/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
+		if (priv->reg[2] & priv->reg[1] & 0x10)
+			parport_generic_irq(0, pp, NULL);
+	}
+	if (val)
+		*val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
+	return ret;
+}
+
+static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	int ret;
+
+	if (!usbdev)
+		return -1;
+	ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev,0), 4, 0x40, (((unsigned int)reg) << 8) | val, 0, NULL, 0, HZ);
+	if (ret) {
+		printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x) failed, status 0x%x\n", 
+		       (unsigned int)reg, (unsigned int)val, ret);
+	} else {
+#if 0
+		printk(KERN_DEBUG "uss720: set_1284_register(%u,0x%02x)\n", 
+		       (unsigned int)reg, (unsigned int)val);
+#endif
+	}
+	return ret;
+}
+
+/* --------------------------------------------------------------------- */
+
+/* ECR modes */
+#define ECR_SPP 00
+#define ECR_PS2 01
+#define ECR_PPF 02
+#define ECR_ECP 03
+#define ECR_EPP 04
+
+/* Safely change the mode bits in the ECR */
+static int change_mode(struct parport *pp, int m)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	int mode;
+
+	if (get_1284_register(pp, 6, NULL))
+		return -EIO;
+	/* Bits <7:5> contain the mode. */
+	mode = (priv->reg[2] >> 5) & 0x7;
+	if (mode == m)
+		return 0;
+	/* We have to go through mode 000 or 001 */
+	if (mode > ECR_PS2 && m > ECR_PS2)
+		if (change_mode(pp, ECR_PS2))
+			return -EIO;
+
+	if (m <= ECR_PS2 && !(priv->reg[1] & 0x20)) {
+		/* This mode resets the FIFO, so we may
+		 * have to wait for it to drain first. */
+		long expire = jiffies + pp->physport->cad->timeout;
+		switch (mode) {
+		case ECR_PPF: /* Parallel Port FIFO mode */
+		case ECR_ECP: /* ECP Parallel Port mode */
+			/* Poll slowly. */
+			for (;;) {
+				if (get_1284_register(pp, 6, NULL))
+					return -EIO;
+				if (priv->reg[2] & 0x01)
+					break;
+				if (time_after_eq (jiffies, expire))
+					/* The FIFO is stuck. */
+					return -EBUSY;
+				current->state = TASK_INTERRUPTIBLE;
+				schedule_timeout((HZ + 99) / 100);
+				if (signal_pending (current))
+					break;
+			}
+		}
+	}
+	/* Set the mode. */
+	if (set_1284_register(pp, 6, m << 5))
+		return -EIO;
+	return 0;
+}
+
+/*
+ * Clear TIMEOUT BIT in EPP MODE
+ */
+static int clear_epp_timeout(struct parport *pp)
+{
+	unsigned char stat;
+
+	if (get_1284_register(pp, 1, &stat))
+		return 1;
+	return stat & 1;
+}
+
+/*
+ * Access functions.
+ */
+#if 0
+static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id)
+{
+	struct parport *pp = (struct parport *)dev_id;
+	struct parport_uss720_private *priv = pp->private_data;	
+
+	if (usbstatus != USB_ST_NOERROR || len < 4 || !buffer)
+		return 1;
+	memcpy(priv->reg, buffer, 4);
+	/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
+	if (priv->reg[2] & priv->reg[1] & 0x10)
+		parport_generic_irq(0, pp, NULL);
+	return 1;
+}
+#endif
+
+static void parport_uss720_write_data(struct parport *pp, unsigned char d)
+{
+	set_1284_register(pp, 0, d);
+}
+
+static unsigned char parport_uss720_read_data(struct parport *pp)
+{
+	unsigned char ret;
+
+	if (get_1284_register(pp, 0, &ret))
+		return 0;
+	return ret;
+}
+
+static void parport_uss720_write_control(struct parport *pp, unsigned char d)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+
+	d = (d & 0xf) | (priv->reg[1] & 0xf0);
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static unsigned char parport_uss720_read_control(struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	return priv->reg[1] & 0xf; /* Use soft copy */
+}
+
+static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned char mask, unsigned char val)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	mask &= 0x0f;
+	val &= 0x0f;
+	d = (priv->reg[1] & (~mask)) ^ val;
+	if (set_1284_register(pp, 2, d))
+		return 0;
+	priv->reg[1] = d;
+	return d & 0xf;
+}
+
+static unsigned char parport_uss720_read_status(struct parport *pp)
+{
+	unsigned char ret;
+
+	if (get_1284_register(pp, 1, &ret))
+		return 0;
+	return ret & 0xf8;
+}
+
+static void parport_uss720_disable_irq(struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	d = priv->reg[1] & ~0x10;
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static void parport_uss720_enable_irq(struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	d = priv->reg[1] | 0x10;
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static void parport_uss720_data_forward (struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	d = priv->reg[1] & ~0x20;
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static void parport_uss720_data_reverse (struct parport *pp)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	unsigned char d;
+
+	d = priv->reg[1] | 0x20;
+	if (set_1284_register(pp, 2, d))
+		return;
+	priv->reg[1] = d;
+}
+
+static void parport_uss720_init_state(struct pardevice *dev, struct parport_state *s)
+{
+	s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+	s->u.pc.ecr = 0x24;
+}
+
+static void parport_uss720_save_state(struct parport *pp, struct parport_state *s)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+
+	if (get_1284_register(pp, 2, NULL))
+		return;
+	s->u.pc.ctr = priv->reg[1];
+	s->u.pc.ecr = priv->reg[2];
+}
+
+static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s)
+{
+	set_1284_register(pp, 2, s->u.pc.ctr);
+	set_1284_register(pp, 6, s->u.pc.ecr);
+	get_1284_register(pp, 2, NULL);
+}
+
+static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	size_t got = 0;
+
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	for (; got < length; got++) {
+		if (get_1284_register(pp, 4, (char *)buf))
+			break;
+		((char*)buf)++;
+		if (priv->reg[0] & 0x01) {
+			clear_epp_timeout(pp);
+			break;
+		}
+	}
+	change_mode(pp, ECR_PS2);
+	return got;
+}
+
+static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf, size_t length, int flags)
+{
+#if 0
+	struct parport_uss720_private *priv = pp->private_data;	
+	size_t written = 0;
+
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	for (; written < length; written++) {
+		if (set_1284_register(pp, 4, (char *)buf))
+			break;
+		((char*)buf)++;
+		if (get_1284_register(pp, 1, NULL))
+			break;
+		if (priv->reg[0] & 0x01) {
+			clear_epp_timeout(pp);
+			break;
+		}
+	}
+	change_mode(pp, ECR_PS2);
+	return written;
+#else
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	int rlen;
+	int i;
+
+	if (!usbdev)
+		return 0;
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, HZ*20);
+	if (i)
+		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %u\n", buf, length, rlen);
+	change_mode(pp, ECR_PS2);
+	return rlen;
+#endif
+}
+
+static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t length, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	size_t got = 0;
+
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	for (; got < length; got++) {
+		if (get_1284_register(pp, 3, (char *)buf))
+			break;
+		((char*)buf)++;
+		if (priv->reg[0] & 0x01) {
+			clear_epp_timeout(pp);
+			break;
+		}
+	}
+	change_mode(pp, ECR_PS2);
+	return got;
+}
+
+static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf, size_t length, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;	
+	size_t written = 0;
+
+	if (change_mode(pp, ECR_EPP))
+		return 0;
+	for (; written < length; written++) {
+		if (set_1284_register(pp, 3, *(char *)buf))
+			break;
+		((char*)buf)++;
+		if (get_1284_register(pp, 1, NULL))
+			break;
+		if (priv->reg[0] & 0x01) {
+			clear_epp_timeout(pp);
+			break;
+		}
+	}
+	change_mode(pp, ECR_PS2);
+	return written;
+}
+
+static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buffer, size_t len, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	int rlen;
+	int i;
+
+	if (!usbdev)
+		return 0;
+	if (change_mode(pp, ECR_ECP))
+		return 0;
+	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, HZ*20);
+	if (i)
+		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %u\n", buffer, len, rlen);
+	change_mode(pp, ECR_PS2);
+	return rlen;
+}
+
+static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, size_t len, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	int rlen;
+	int i;
+
+	if (!usbdev)
+		return 0;
+	if (change_mode(pp, ECR_ECP))
+		return 0;
+	i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, HZ*20);
+	if (i)
+		printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %u rlen %u\n", buffer, len, rlen);
+	change_mode(pp, ECR_PS2);
+	return rlen;
+}
+
+static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags)
+{
+	size_t written = 0;
+
+	if (change_mode(pp, ECR_ECP))
+		return 0;
+	for (; written < len; written++) {
+		if (set_1284_register(pp, 5, *(char *)buffer))
+			break;
+		((char*)buffer)++;
+	}
+	change_mode(pp, ECR_PS2);
+	return written;
+}
+
+static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer, size_t len, int flags)
+{
+	struct parport_uss720_private *priv = pp->private_data;
+	struct usb_device *usbdev = priv->usbdev;
+	int rlen;
+	int i;
+
+	if (!usbdev)
+		return 0;
+	if (change_mode(pp, ECR_PPF))
+		return 0;
+	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, HZ*20);
+	if (i)
+		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %u rlen %u\n", buffer, len, rlen);
+	change_mode(pp, ECR_PS2);
+	return rlen;
+}
+
+void parport_uss720_inc_use_count(void)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+void parport_uss720_dec_use_count(void)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct parport_operations parport_uss720_ops = 
+{
+	parport_uss720_write_data,
+	parport_uss720_read_data,
+
+	parport_uss720_write_control,
+	parport_uss720_read_control,
+	parport_uss720_frob_control,
+
+	parport_uss720_read_status,
+
+	parport_uss720_enable_irq,
+	parport_uss720_disable_irq,
+
+	parport_uss720_data_forward,
+	parport_uss720_data_reverse,
+
+	parport_uss720_init_state,
+	parport_uss720_save_state,
+	parport_uss720_restore_state,
+
+	parport_uss720_inc_use_count,
+	parport_uss720_dec_use_count,
+
+	parport_uss720_epp_write_data,
+	parport_uss720_epp_read_data,
+	parport_uss720_epp_write_addr,
+	parport_uss720_epp_read_addr,
+
+	parport_uss720_ecp_write_data,
+	parport_uss720_ecp_read_data,
+	parport_uss720_ecp_write_addr,
+
+	parport_uss720_write_compat,
+	parport_ieee1284_read_nibble,
+	parport_ieee1284_read_byte,
+};
+
+/* --------------------------------------------------------------------- */
+
+static void * uss720_probe(struct usb_device *usbdev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct parport_uss720_private *priv;
+	struct parport *pp;
+	int i;
+
+	if ((usbdev->descriptor.idVendor != 0x047e || usbdev->descriptor.idProduct != 0x1001) &&
+	    (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001) &&
+	    (usbdev->descriptor.idVendor != 0x0729 || usbdev->descriptor.idProduct != 0x1284))
+		return NULL;
+
+	printk(KERN_DEBUG "uss720: probe: vendor id 0x%x, device id 0x%x\n",
+	       usbdev->descriptor.idVendor, usbdev->descriptor.idProduct);
+
+	/* our known interfaces have 3 alternate settings */
+	if (usbdev->actconfig->interface[ifnum].num_altsetting != 3)
+		return NULL;
+
+	i = usb_set_interface(usbdev, ifnum, 2);
+	printk(KERN_DEBUG "uss720: set inteface result %d\n", i);
+
+	interface = &usbdev->actconfig->interface[ifnum].altsetting[2];
+
+	/*
+	 * Allocate parport interface 
+	 */
+	printk(KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
+
+	if (!(priv = kmalloc(sizeof(struct parport_uss720_private), GFP_KERNEL)))
+		return NULL;
+	if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) {
+		printk(KERN_WARNING "usb-uss720: could not register parport\n");
+		goto probe_abort;
+	}
+
+	pp->private_data = priv;
+	priv->usbdev = usbdev;
+	pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
+
+	/* set the USS720 control register to manual mode, no ECP compression, enable all ints */
+	set_1284_register(pp, 7, 0x00);
+	set_1284_register(pp, 6, 0x30);  /* PS/2 mode */
+	set_1284_register(pp, 2, 0x0c);
+	/* debugging */
+	get_1284_register(pp, 0, NULL);
+	printk("uss720: reg: %02x %02x %02x %02x %02x %02x %02x\n",
+	       priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
+
+	endpoint = &interface->endpoint[2];
+	printk(KERN_DEBUG "uss720: epaddr %d interval %d\n", endpoint->bEndpointAddress, endpoint->bInterval);
+#if 0
+	priv->irqpipe = usb_rcvctrlpipe(usbdev, endpoint->bEndpointAddress);
+	i = usb_request_irq(usbdev, priv->irqpipe,
+				  uss720_irq, endpoint->bInterval,
+				  pp, &priv->irqhandle);
+	if (i) {
+		printk (KERN_WARNING "usb-uss720: usb_request_irq failed (0x%x)\n", i);
+		goto probe_abort_port;
+	}
+#endif
+	parport_proc_register(pp);
+	parport_announce_port(pp);
+
+	MOD_INC_USE_COUNT;
+	return pp;
+
+#if 0
+probe_abort_port:
+	parport_unregister_port(pp);
+#endif
+probe_abort:
+	kfree(priv);
+	return NULL;
+}
+
+static void uss720_disconnect(struct usb_device *usbdev, void *ptr)
+{
+	struct parport *pp = (struct parport *)ptr;
+	struct parport_uss720_private *priv = pp->private_data;
+
+#if 0
+	usb_release_irq(usbdev, priv->irqhandle, priv->irqpipe);
+#endif
+	priv->usbdev = NULL;
+	parport_proc_unregister(pp);
+	parport_unregister_port(pp);
+	kfree(priv);
+	MOD_DEC_USE_COUNT;
+}
+
+static struct usb_driver uss720_driver = {
+	"uss720",
+	uss720_probe,
+	uss720_disconnect,
+	{ NULL, NULL }
+};
+
+/* --------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch");
+MODULE_DESCRIPTION("USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip");
+
+static int __init uss720_init(void)
+{
+	if (usb_register(&uss720_driver) < 0)
+		return -1;
+
+	printk(KERN_INFO "uss720: USB<->IEEE1284 cable driver v0.4 registered.\n"
+	       KERN_INFO "uss720: (C) 1999 by Thomas Sailer, <sailer@ife.ee.ethz.ch>\n");
+	return 0;
+}
+
+static void __exit uss720_cleanup(void)
+{
+	usb_deregister(&uss720_driver);
+}
+
+module_init(uss720_init);
+module_exit(uss720_cleanup);
+
+/* --------------------------------------------------------------------- */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/wacom.c linux.18p8/drivers/usb/wacom.c
--- linux.vanilla/drivers/usb/wacom.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/wacom.c	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,333 @@
+/*
+ * $Id: wacom.c,v 1.9 2000/05/29 09:01:52 vojtech Exp $
+ *
+ *  Copyright (c) 2000 Vojtech Pavlik		<vojtech@suse.cz>
+ *  Copyright (c) 2000 Andreas Bach Aaen	<abach@stofanet.dk>
+ *  Copyright (c) 2000 Clifford Wolf		<clifford@clifford.at>
+ *  Copyright (c) 2000 Sam Mosel		<sam.mosel@computer.org>
+ *
+ *  USB Wacom Graphire and Wacom Intuos tablet support
+ *
+ *  Sponsored by SuSE
+ *
+ *  ChangeLog:
+ *      v0.1 (vp)  - Initial release
+ *      v0.2 (aba) - Support for all buttons / combinations
+ *      v0.3 (vp)  - Support for Intuos added
+ *	v0.4 (sm)  - Support for more Intuos models, menustrip
+ *			relative mode, proximity.
+ *	v0.5 (vp)  - Big cleanup, nifty features removed,
+ * 			they belong in userspace
+ *	v1.8 (vp)  - Submit URB only when operating, moved to CVS,
+ *			use input_report_key instead of report_btn and
+ *			other cleanups
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+/*
+ * Wacom Graphire packet:
+ *
+ * byte 0: report ID (2)
+ * byte 1: bit7		pointer in range
+ *	   bit5-6	pointer type 0 - pen, 1 - rubber, 2 - mouse
+ *	   bit4		1 ?
+ *	   bit3		0 ?
+ *	   bit2		mouse middle button / pen button2
+ *	   bit1		mouse right button / pen button1
+ *	   bit0		mouse left button / touch
+ * byte 2: X low bits
+ * byte 3: X high bits
+ * byte 4: Y low bits
+ * byte 5: Y high bits
+ * byte 6: pen pressure low bits / mouse wheel
+ * byte 7: pen presure high bits / mouse distance
+ * 
+ * There are also two single-byte feature reports (2 and 3).
+ *
+ * Wacom Intuos status packet:
+ *
+ * byte 0: report ID (2)
+ * byte 1: bit7		1 - sync bit 
+ *	   bit6		pointer in range
+ *	   bit5		pointer type report
+ *	   bit4		0 ?
+ *	   bit3		0 ?
+ *	   bit2		pen button2
+ *	   bit1		pen button1
+ *	   bit0		0 ?
+ * byte 2: X high bits
+ * byte 3: X low bits
+ * byte 4: Y high bits
+ * byte 5: Y low bits
+ * byte 6: bits 0-7: pressure	(bits 2-9)
+ * byte 7: bits 6-7: pressure	(bits 0-1)
+ * byte 7: bits 0-5: X tilt	(bits 1-6)
+ * byte 8: bit    7: X tilt	(bit  0)
+ * byte 8: bits 0-6: Y tilt	(bits 0-6)
+ * byte 9: bits 4-7: distance
+ */
+
+#define USB_VENDOR_ID_WACOM	0x056a
+
+struct wacom_features {
+	char *name;
+	int idProduct;
+	int pktlen;
+	int x_max;
+	int y_max;
+	int pressure_max;
+	int distance_max;
+	void (*irq)(struct urb *urb);
+	unsigned long evbit;
+	unsigned long absbit;
+	unsigned long relbit;
+	unsigned long btnbit;
+	unsigned long digibit;
+};
+
+struct wacom {
+	signed char data[10];
+	struct input_dev dev;
+	struct urb irq;
+	struct wacom_features *features;
+	int tool;
+	int open;
+};
+
+static void wacom_graphire_irq(struct urb *urb)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+
+	if (urb->status) return;
+
+	if (data[0] != 2)
+		dbg("received unknown report #%d", data[0]);
+
+	if ( data[1] & 0x80 ) {
+		input_report_abs(dev, ABS_X, data[2] | ((__u32)data[3] << 8));
+		input_report_abs(dev, ABS_Y, data[4] | ((__u32)data[5] << 8));
+	}
+
+	switch ((data[1] >> 5) & 3) {
+
+		case 0:	/* Pen */
+			input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x80);
+			break;
+
+		case 1: /* Rubber */
+			input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
+			break;
+
+		case 2: /* Mouse */
+			input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24);
+			input_report_key(dev, BTN_LEFT, data[1] & 0x01);
+			input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
+			input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
+			input_report_abs(dev, ABS_DISTANCE, data[7]);
+			input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+			return;
+	}
+
+	input_report_abs(dev, ABS_PRESSURE, data[6] | ((__u32)data[7] << 8));
+
+	input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
+	input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
+	input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
+}
+
+static void wacom_intuos_irq(struct urb *urb)
+{
+	struct wacom *wacom = urb->context;
+	unsigned char *data = wacom->data;
+	struct input_dev *dev = &wacom->dev;
+	unsigned int t;
+
+	if (urb->status) return;
+
+	if (data[0] != 2)
+		dbg("received unknown report #%d", data[0]);
+
+	if (((data[1] >> 5) & 0x3) == 0x2) {				/* Enter report */
+
+		switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
+			case 0x012: wacom->tool = BTN_TOOL_PENCIL;	break;	/* Inking pen */
+			case 0x822:
+			case 0x022: wacom->tool = BTN_TOOL_PEN;		break;	/* Pen */
+			case 0x032: wacom->tool = BTN_TOOL_BRUSH;	break;	/* Stroke pen */
+			case 0x094: wacom->tool = BTN_TOOL_MOUSE;	break;	/* Mouse 4D */
+			case 0x096: wacom->tool = BTN_TOOL_LENS;	break;	/* Lens cursor */
+			case 0x82a:
+			case 0x0fa: wacom->tool = BTN_TOOL_RUBBER;	break;	/* Eraser */
+			case 0x112: wacom->tool = BTN_TOOL_AIRBRUSH;	break;	/* Airbrush */
+			default:    wacom->tool = BTN_TOOL_PEN;		break;	/* Unknown tool */
+		}			
+		input_report_key(dev, wacom->tool, 1);
+		return;
+	}
+
+	if ((data[1] | data[2] | data[3] | data[4] | data[5] |
+	     data[6] | data[7] | data[8] | data[9]) == 0x80) {		/* Exit report */
+		input_report_key(dev, wacom->tool, 0);
+		return;
+	}
+
+	input_report_abs(dev, ABS_X, ((__u32)data[2] << 8) | data[3]);
+	input_report_abs(dev, ABS_Y, ((__u32)data[4] << 8) | data[5]);
+	input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+	input_report_abs(dev, ABS_DISTANCE, data[9] >> 4);
+	input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+	input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
+
+	input_report_key(dev, BTN_STYLUS, data[1] & 2);
+	input_report_key(dev, BTN_STYLUS2, data[1] & 4);
+	input_report_key(dev, BTN_TOUCH, t > 10);
+}
+
+#define WACOM_INTUOS_TOOLS	(BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS))
+
+struct wacom_features wacom_features[] = {
+	{ "Wacom Graphire",     0x10,  8, 10206,  7422,  511, 32, wacom_graphire_irq,
+		BIT(EV_REL), 0, BIT(REL_WHEEL), BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE), 0 },
+	{ "Wacom Intuos 4x5",   0x20, 10, 12700, 10360, 1023, 15, wacom_intuos_irq,
+		0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+	{ "Wacom Intuos 6x8",   0x21, 10, 20320, 15040, 1023, 15, wacom_intuos_irq,
+		0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+	{ "Wacom Intuos 9x12",  0x22, 10, 30480, 23060, 1023, 15, wacom_intuos_irq,
+		0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+	{ "Wacom Intuos 12x12", 0x23, 10, 30480, 30480, 1023, 15, wacom_intuos_irq,
+		0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+	{ "Wacom Intuos 12x18", 0x24, 10, 47720, 30480, 1023, 15, wacom_intuos_irq,
+		0, BIT(ABS_TILT_X) | BIT(ABS_TILT_Y), 0, 0, WACOM_INTUOS_TOOLS },
+	{ NULL , 0 }
+};
+
+static int wacom_open(struct input_dev *dev)
+{
+	struct wacom *wacom = dev->private;
+
+	if (wacom->open++)
+		return 0;
+
+	if (usb_submit_urb(&wacom->irq))
+		return -EIO;
+
+	return 0;
+}
+
+static void wacom_close(struct input_dev *dev)
+{
+	struct wacom *wacom = dev->private;
+
+	if (!--wacom->open)
+		usb_unlink_urb(&wacom->irq);
+}
+
+static void *wacom_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_endpoint_descriptor *endpoint;
+	struct wacom *wacom;
+	int i;
+
+	if (dev->descriptor.idVendor != USB_VENDOR_ID_WACOM) return NULL;
+	for (i = 0; wacom_features[i].idProduct && wacom_features[i].idProduct != dev->descriptor.idProduct; i++);
+	if (!wacom_features[i].idProduct) return NULL;
+
+	endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+
+	if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
+	memset(wacom, 0, sizeof(struct wacom));
+
+	wacom->features = wacom_features + i;
+
+	wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | wacom->features->evbit;
+	wacom->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE) | wacom->features->absbit;
+	wacom->dev.relbit[0] |= wacom->features->relbit;
+	wacom->dev.keybit[LONG(BTN_LEFT)] |= wacom->features->btnbit;
+	wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) |
+		BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2) | wacom->features->digibit;
+
+	wacom->dev.absmax[ABS_X] = wacom->features->x_max;
+	wacom->dev.absmax[ABS_Y] = wacom->features->y_max;
+	wacom->dev.absmax[ABS_PRESSURE] = wacom->features->pressure_max;
+	wacom->dev.absmax[ABS_DISTANCE] = wacom->features->distance_max;
+	wacom->dev.absmax[ABS_TILT_X] = 127;
+	wacom->dev.absmax[ABS_TILT_Y] = 127;
+
+	wacom->dev.private = wacom;
+	wacom->dev.open = wacom_open;
+	wacom->dev.close = wacom_close;
+
+	wacom->dev.name = wacom->features->name;
+	wacom->dev.idbus = BUS_USB;
+	wacom->dev.idvendor = dev->descriptor.idVendor;
+	wacom->dev.idproduct = dev->descriptor.idProduct;
+	wacom->dev.idversion = dev->descriptor.bcdDevice;
+
+	FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+		     wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval);
+
+	input_register_device(&wacom->dev);
+
+	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
+		 wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum);
+
+	return wacom;
+}
+
+static void wacom_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct wacom *wacom = ptr;
+	usb_unlink_urb(&wacom->irq);
+	input_unregister_device(&wacom->dev);
+	kfree(wacom);
+}
+
+static struct usb_driver wacom_driver = {
+	name:		"wacom",
+	probe:		wacom_probe,
+	disconnect:	wacom_disconnect,
+};
+
+static int __init wacom_init(void)
+{
+	usb_register(&wacom_driver);
+	return 0;
+}
+
+static void __exit wacom_exit(void)
+{
+	usb_deregister(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/wmforce.c linux.18p8/drivers/usb/wmforce.c
--- linux.vanilla/drivers/usb/wmforce.c	Thu Jan  1 01:00:00 1970
+++ linux.18p8/drivers/usb/wmforce.c	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,190 @@
+/*
+ * $Id: wmforce.c,v 1.6 2000/05/29 09:01:52 vojtech Exp $
+ *
+ *  Copyright (c) 2000 Vojtech Pavlik
+ *
+ *  USB Logitech WingMan Force joystick support
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+#define USB_VENDOR_ID_LOGITECH		0x046d
+#define USB_DEVICE_ID_LOGITECH_WMFORCE	0xc281
+
+struct wmforce {
+	signed char data[8];
+	struct input_dev dev;
+	struct urb irq;
+	int open;
+};
+
+static struct {
+        __s32 x;
+        __s32 y;
+} wmforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+static char *wmforce_name = "Logitech WingMan Force";
+
+static void wmforce_irq(struct urb *urb)
+{
+	struct wmforce *wmforce = urb->context;
+	unsigned char *data = wmforce->data;
+	struct input_dev *dev = &wmforce->dev;
+
+	if (urb->status) return;
+
+	if (data[0] != 1) {
+		if (data[0] != 2)
+			warn("received unknown report #%d", data[0]);
+		return;
+	}
+
+	input_report_abs(dev, ABS_X, (__s16) (((__s16)data[2] << 8) | data[1]));
+	input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[4] << 8) | data[3]));
+	input_report_abs(dev, ABS_THROTTLE, data[5]);
+	input_report_abs(dev, ABS_HAT0X, wmforce_hat_to_axis[data[7] >> 4].x);
+	input_report_abs(dev, ABS_HAT0Y, wmforce_hat_to_axis[data[7] >> 4].y);
+
+	input_report_key(dev, BTN_TRIGGER, data[6] & 0x01);
+	input_report_key(dev, BTN_TOP,     data[6] & 0x02);
+	input_report_key(dev, BTN_THUMB,   data[6] & 0x04);
+	input_report_key(dev, BTN_TOP2,    data[6] & 0x08);
+	input_report_key(dev, BTN_BASE,    data[6] & 0x10);
+	input_report_key(dev, BTN_BASE2,   data[6] & 0x20);
+	input_report_key(dev, BTN_BASE3,   data[6] & 0x40);
+	input_report_key(dev, BTN_BASE4,   data[6] & 0x80);
+	input_report_key(dev, BTN_BASE5,   data[7] & 0x01);
+}
+
+static int wmforce_open(struct input_dev *dev)
+{
+	struct wmforce *wmforce = dev->private;
+
+	if (wmforce->open++)
+		return 0;
+
+	if (usb_submit_urb(&wmforce->irq))
+		return -EIO;
+
+	return 0;
+}
+
+static void wmforce_close(struct input_dev *dev)
+{
+	struct wmforce *wmforce = dev->private;
+
+	if (!--wmforce->open)
+		usb_unlink_urb(&wmforce->irq);
+}
+
+static void *wmforce_probe(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_endpoint_descriptor *endpoint;
+	struct wmforce *wmforce;
+	int i;
+
+	if (dev->descriptor.idVendor != USB_VENDOR_ID_LOGITECH ||
+	    dev->descriptor.idProduct != USB_DEVICE_ID_LOGITECH_WMFORCE)
+		return NULL;
+
+	endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+
+	if (!(wmforce = kmalloc(sizeof(struct wmforce), GFP_KERNEL))) return NULL;
+	memset(wmforce, 0, sizeof(struct wmforce));
+
+	wmforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+	wmforce->dev.keybit[LONG(BTN_JOYSTICK)] = BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) |
+					BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5);
+	wmforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
+
+	for (i = ABS_X; i <= ABS_Y; i++) {
+		wmforce->dev.absmax[i] =  1920;
+		wmforce->dev.absmin[i] = -1920;
+		wmforce->dev.absflat[i] = 128;
+	}
+
+	wmforce->dev.absmax[ABS_THROTTLE] = 255;
+	wmforce->dev.absmin[ABS_THROTTLE] = 0;
+
+	for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) {
+		wmforce->dev.absmax[i] =  1;
+		wmforce->dev.absmin[i] = -1;
+	}
+
+	wmforce->dev.private = wmforce;
+	wmforce->dev.open = wmforce_open;
+	wmforce->dev.close = wmforce_close;
+
+	wmforce->dev.name = wmforce_name;
+	wmforce->dev.idbus = BUS_USB;
+	wmforce->dev.idvendor = dev->descriptor.idVendor;
+	wmforce->dev.idproduct = dev->descriptor.idProduct;
+	wmforce->dev.idversion = dev->descriptor.bcdDevice;
+
+	FILL_INT_URB(&wmforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+			wmforce->data, 8, wmforce_irq, wmforce, endpoint->bInterval);
+
+	input_register_device(&wmforce->dev);
+
+	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
+		 wmforce->dev.number, wmforce_name, dev->bus->busnum, dev->devnum, ifnum);
+
+	return wmforce;
+}
+
+static void wmforce_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct wmforce *wmforce = ptr;
+	usb_unlink_urb(&wmforce->irq);
+	input_unregister_device(&wmforce->dev);
+	kfree(wmforce);
+}
+
+static struct usb_driver wmforce_driver = {
+	name:		"wmforce",
+	probe:		wmforce_probe,
+	disconnect:	wmforce_disconnect,
+};
+
+static int __init wmforce_init(void)
+{
+	usb_register(&wmforce_driver);
+	return 0;
+}
+
+static void __exit wmforce_exit(void)
+{
+	usb_deregister(&wmforce_driver);
+}
+
+module_init(wmforce_init);
+module_exit(wmforce_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/Config.in linux.18p8/drivers/video/Config.in
--- linux.vanilla/drivers/video/Config.in	Sat Sep  9 18:42:46 2000
+++ linux.18p8/drivers/video/Config.in	Tue Sep  5 22:01:37 2000
@@ -6,7 +6,7 @@
   define_bool CONFIG_DUMMY_CONSOLE y
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then
-      bool 'Permedia2 support (experimental)' CONFIG_FB_PM2
+      tristate 'Permedia2 support (experimental)' CONFIG_FB_PM2
       if [ "$CONFIG_FB_PM2" = "y" ]; then
         if [ "$CONFIG_PCI" = "y" ]; then
           bool '  enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT
@@ -51,7 +51,7 @@
     bool 'Atari native chipset support' CONFIG_FB_ATARI
   fi
   if [ "$CONFIG_ATARI" = "y" -o "$CONFIG_PCI" != "n" ]; then
-    bool 'ATI Mach64 display support' CONFIG_FB_ATY
+    tristate 'ATI Mach64 display support' CONFIG_FB_ATY
   fi
   if [ "$CONFIG_PPC" = "y" ]; then
     bool 'Open Firmware frame buffer device support' CONFIG_FB_OF
@@ -84,7 +84,7 @@
     define_bool CONFIG_BUS_I2C y
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    if [ "$CONFIG_PCI" != "n" ]; then
+    if [ "$CONFIG_PCI" != "n" -a "$ARCH" != "sparc" -a "$ARCH" != "sparc64" ]; then
       tristate 'Matrox acceleration' CONFIG_FB_MATROX
       if  [ "$CONFIG_FB_MATROX" != "n" ]; then
         bool '  Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
@@ -92,7 +92,7 @@
         bool '  G100/G200 support' CONFIG_FB_MATROX_G100
         bool '  Multihead support' CONFIG_FB_MATROX_MULTIHEAD
       fi
-      bool 'ATI Rage128 display support' CONFIG_FB_ATY128
+      tristate 'ATI Rage128 display support' CONFIG_FB_ATY128
     fi
   fi
   if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty128fb.c linux.18p8/drivers/video/aty128fb.c
--- linux.vanilla/drivers/video/aty128fb.c	Sat Sep  9 18:42:46 2000
+++ linux.18p8/drivers/video/aty128fb.c	Tue Sep  5 22:01:37 2000
@@ -2614,14 +2614,14 @@
 MODULE_AUTHOR("(c)1999-2000 Brad Douglas <brad@neruo.com>");
 MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards");
 
-int __init
+int
 init_module(void)
 {
     aty128fb_init();
     return 0;
 }
 
-void __exit
+void
 cleanup_module(void)
 {
     struct fb_info_aty128 *info = board_list;
@@ -2636,9 +2636,9 @@
             mtrr_del(info->mtrr.vram, info->frame_buffer_phys,
                      info->vram_size);
 #endif /* CONFIG_MTRR */
-        iounmap (tmp->regbase);
-        iounmap (tmp->frame_buffer);
-        kfree (tmp);
+        iounmap (info->regbase);
+        iounmap (&info->frame_buffer);
+        kfree (info);
     }
 }
 #endif /* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/atyfb.c linux.18p8/drivers/video/atyfb.c
--- linux.vanilla/drivers/video/atyfb.c	Sat Sep  9 18:42:46 2000
+++ linux.18p8/drivers/video/atyfb.c	Fri Sep  1 13:39:05 2000
@@ -394,7 +394,7 @@
      *  Interface used by the world
      */
 
-void atyfb_init(void);
+int atyfb_init(void);
 #ifdef CONFIG_FB_OF
 void atyfb_of_init(struct device_node *dp);
 #endif
@@ -2880,7 +2880,7 @@
     return 1;
 }
 
-__initfunc(void atyfb_init(void))
+int __init atyfb_init(void)
 {
 #if defined(CONFIG_FB_OF)
     /* We don't want to be called like this. */
@@ -2900,7 +2900,7 @@
 
     /* Do not attach when we have a serial console. */
     if (!con_is_present())
-	return;
+	return 0;
 #else
     u16 tmp;
 #endif
@@ -2912,7 +2912,7 @@
 	    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
 	    if (!info) {
 		printk("atyfb_init: can't alloc fb_info_aty\n");
-		return;
+		return 0;
 	    }
 	    memset(info, 0, sizeof(struct fb_info_aty));
 
@@ -2948,7 +2948,7 @@
 	    if (!info->mmap_map) {
 		printk("atyfb_init: can't alloc mmap_map\n");
 		kfree(info);
-		return;
+		return 0;
 	    }
 	    memset(info->mmap_map, 0, j * sizeof(*info->mmap_map));
 
@@ -3133,7 +3133,7 @@
 
 	    if(!info->ati_regbase) {
 		    kfree(info);
-		    return;
+		    return 0;
 	    }
 
 	    info->ati_regbase_phys += 0xc00;
@@ -3160,7 +3160,7 @@
 
 	    if(!info->frame_buffer) {
 		    kfree(info);
-		    return;
+		    return 0;
 	    }
 
 #endif /* __sparc__ */
@@ -3169,7 +3169,7 @@
 		if (info->mmap_map)
 		    kfree(info->mmap_map);
 		kfree(info);
-		return;
+		return 0;
 	    }
 
 #ifdef __sparc__
@@ -3207,7 +3207,7 @@
 	info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
 	if (!info) {
 	    printk("atyfb_init: can't alloc fb_info_aty\n");
-	    return;
+	    return 0;
 	}
 	memset(info, 0, sizeof(struct fb_info_aty));
 
@@ -3223,10 +3223,11 @@
 	if (!aty_init(info, "ISA bus")) {
 	    kfree(info);
 	    /* This is insufficient! kernel_map has added two large chunks!! */
-	    return;
+	    return 0;
 	}
     }
 #endif
+    return 1;
 }
 
 #ifdef CONFIG_FB_OF
@@ -4213,3 +4214,46 @@
 	return result;
 }
 #endif /* CONFIG_PMAC_PBOOK */
+
+#ifdef MODULE
+
+int blink = 1;
+static u32 vram = 0;
+static int pll = 0;
+static int mclk = 0;
+#if defined(CONFIG_PPC)
+static int vmode = VMODE_NVRAM;
+static int cmode = CMODE_NVRAM;
+#endif
+
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel, "Do not use accelerating engine (0 or 1=disabled) (default=0)");
+MODULE_PARM(blink, "i");
+MODULE_PARM_DESC(blink, "Enables hardware cursor blinking (0 or 1) (default=1)");
+#ifdef CONFIG_PPC
+MODULE_PARM(vmode, "i");
+MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
+MODULE_PARM(cmode, "i");
+MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
+#endif
+
+int init_module(void)
+{
+	curblink = blink;
+	default_vram = vram;
+	default_pll = pll;
+	default_mclk = mclk;
+#ifdef CONFIG_PPC
+	default_vmode = vmode;
+	default_cmode = cmode;
+#endif
+	if (!atyfb_init())
+		return -ENXIO;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif	/* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/fbcon-mac.c linux.18p8/drivers/video/fbcon-mac.c
--- linux.vanilla/drivers/video/fbcon-mac.c	Fri Apr 21 12:46:39 2000
+++ linux.18p8/drivers/video/fbcon-mac.c	Mon Sep 11 17:49:08 2000
@@ -455,7 +455,7 @@
   u8 *dest, bit;
   u16 *dest16;
   u32 *dest32;
-  u8 pixel;
+  u8 pixel = 0x5a;
 
   switch (p->var.bits_per_pixel) {
   case 1:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/pm2fb.c linux.18p8/drivers/video/pm2fb.c
--- linux.vanilla/drivers/video/pm2fb.c	Sat Sep  9 18:42:46 2000
+++ linux.18p8/drivers/video/pm2fb.c	Fri Sep  1 13:39:05 2000
@@ -2041,12 +2041,12 @@
 		board_table[i->board].cleanup(i);
 }
 
-__initfunc(void pm2fb_init(void)) {
+int __init pm2fb_init(void) {
 
 	memset(&fb_info, 0, sizeof(fb_info));
 	memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
 	if (!pm2fb_conf(&fb_info))
-		return;
+		return 0;
 	pm2fb_reset(&fb_info);
 	fb_info.disp.scrollmode=SCROLL_YNOMOVE;
 	fb_info.gen.parsize=sizeof(struct pm2fb_par);
@@ -2065,7 +2065,7 @@
 	fbgen_install_cmap(0, &fb_info.gen);
 	if (register_framebuffer(&fb_info.gen.info)<0) {
 		printk("pm2fb: unable to register.\n");
-		return;
+		return 0;
 	}
 	printk("fb%d: %s (%s), using %uK of video memory.\n",
 				GET_FB_IDX(fb_info.gen.info.node),
@@ -2073,6 +2073,7 @@
 				permedia2_name,
 				(u32 )(fb_info.regions.fb_size>>10));
 	MOD_INC_USE_COUNT;
+	return 1;
 }
 
 static void __init pm2fb_mode_setup(char* options) {
@@ -2127,7 +2128,8 @@
 
 int init_module(void) {
 	if (mode) pm2fb_mode_setup(mode);
-  	pm2fb_init();
+	if (!pm2fb_init())
+		return -ENXIO;
 }
 
 void cleanup_module(void) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/Config.in linux.18p8/fs/Config.in
--- linux.vanilla/fs/Config.in	Fri Apr 21 12:46:41 2000
+++ linux.18p8/fs/Config.in	Mon Sep 11 17:07:03 2000
@@ -91,6 +91,12 @@
     fi
   fi
   tristate 'SMB filesystem support (to mount WfW shares etc.)' CONFIG_SMB_FS
+  if [ "$CONFIG_SMB_FS" != "n" ]; then
+     bool '   Use a default NLS' CONFIG_SMB_NLS_DEFAULT
+     if [ "$CONFIG_SMB_NLS_DEFAULT" = "y" ]; then
+        string '  Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "cp437"
+     fi
+  fi   
 fi
 if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then
   tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/adfs/file.c linux.18p8/fs/adfs/file.c
--- linux.vanilla/fs/adfs/file.c	Fri Apr 21 12:46:40 2000
+++ linux.18p8/fs/adfs/file.c	Mon Sep 11 17:08:19 2000
@@ -22,7 +22,6 @@
 
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/ext2_fs.h>
 #include <linux/fcntl.h>
 #include <linux/sched.h>
 #include <linux/stat.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/block_dev.c linux.18p8/fs/block_dev.c
--- linux.vanilla/fs/block_dev.c	Fri Apr 21 12:46:41 2000
+++ linux.18p8/fs/block_dev.c	Thu Sep 14 15:44:52 2000
@@ -24,7 +24,7 @@
 	ssize_t block, blocks;
 	loff_t offset;
 	ssize_t chars;
-	ssize_t written = 0;
+	ssize_t written = 0, retval = 0;
 	struct buffer_head * bhlist[NBUF];
 	size_t size;
 	kdev_t dev;
@@ -54,8 +54,10 @@
 	else
 		size = INT_MAX;
 	while (count>0) {
-		if (block >= size)
-			return written ? written : -ENOSPC;
+		if (block >= size) {
+			retval = -ENOSPC;
+			goto cleanup;
+		}
 		chars = blocksize - offset;
 		if (chars > count)
 			chars=count;
@@ -67,15 +69,19 @@
 			if (chars != blocksize)
 				fn = bread;
 			bh = fn(dev, block, blocksize);
-			if (!bh)
-				return written ? written : -EIO;
+			if (!bh) {
+				retval = -EIO;
+				goto cleanup;
+			}
 			if (!buffer_uptodate(bh))
 				wait_on_buffer(bh);
 		}
 #else
 		bh = getblk(dev, block, blocksize);
-		if (!bh)
-			return written ? written : -EIO;
+		if (!bh) {
+			retval = -EIO;
+			goto cleanup;
+		}
 
 		if (!buffer_uptodate(bh))
 		{
@@ -99,7 +105,8 @@
 		        if (!bhlist[i])
 			{
 			  while(i >= 0) brelse(bhlist[i--]);
-			  return written ? written : -EIO;
+			  retval = -EIO;
+			  goto cleanup;
 		        }
 		      }
 		    }
@@ -108,7 +115,8 @@
 		    wait_on_buffer(bh);
 		    if (!buffer_uptodate(bh)) {
 			  brelse(bh);
-			  return written ? written : -EIO;
+			  retval = -EIO;
+			  goto cleanup;
 		    }
 		  };
 		};
@@ -141,6 +149,7 @@
 		if(write_error)
 			break;
 	}
+	cleanup:
 	if ( buffercount ){
 		ll_rw_block(WRITE, buffercount, bufferlist);
 		for(i=0; i<buffercount; i++){
@@ -150,10 +159,11 @@
 			brelse(bufferlist[i]);
 		}
 	}		
-	filp->f_reada = 1;
+	if(!retval)
+		filp->f_reada = 1;
 	if(write_error)
 		return -EIO;
-	return written;
+	return written ? written : retval;
 }
 
 ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/dquot.c linux.18p8/fs/dquot.c
--- linux.vanilla/fs/dquot.c	Fri Apr 21 12:46:41 2000
+++ linux.18p8/fs/dquot.c	Mon Sep 11 17:18:30 2000
@@ -1265,14 +1265,6 @@
 	if (!inode)
 		return -ENOENT;
 	/*
-	 * Find out if this filesystem uses i_blocks.
-	 */
-	if (inode->i_blksize == 0)
-		blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE);
-	else
-		blocks = (inode->i_blocks / 2);
-
-	/*
 	 * Build the transfer_from and transfer_to lists and check quotas to see
 	 * if operation is permitted.
 	 */
@@ -1331,14 +1323,29 @@
 		 * dqget() could block and so the first structure might got
 		 * invalidated or locked...
 		 */
-		if (!transfer_to[cnt]->dq_mnt || !transfer_from[cnt]->dq_mnt ||
-		    check_idq(transfer_to[cnt], cnt, 1, initiator, tty) == NO_QUOTA ||
-		    check_bdq(transfer_to[cnt], cnt, blocks, initiator, tty, 0) == NO_QUOTA) {
+		if (!transfer_to[cnt]->dq_mnt || !transfer_from[cnt]->dq_mnt) {
 			cnt++;
 			goto put_all;
 		}
 	}
 
+	/*
+	 * Find out if this filesystem uses i_blocks.
+	 */
+	if (inode->i_blksize == 0)
+		blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE);
+	else
+		blocks = (inode->i_blocks / 2);
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+	{
+		if (transfer_to[cnt] == NODQUOT)
+			continue;
+		if (check_idq(transfer_to[cnt], cnt, 1, initiator, tty) == NO_QUOTA ||
+		    check_bdq(transfer_to[cnt], cnt, blocks, initiator, tty, 0) == NO_QUOTA) {
+			cnt = MAXQUOTAS;
+			goto put_all;
+		}
+}
 	if ((error = notify_change(dentry, iattr)))
 		goto put_all; 
 	/*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/balloc.c linux.18p8/fs/ext2/balloc.c
--- linux.vanilla/fs/ext2/balloc.c	Sun Jun 11 21:44:18 2000
+++ linux.18p8/fs/ext2/balloc.c	Sat Sep  2 23:23:43 2000
@@ -553,20 +553,21 @@
 	 * Do block preallocation now if required.
 	 */
 #ifdef EXT2_PREALLOCATE
-	if (prealloc_block) {
+	if (prealloc_count && !*prealloc_count) {
 		int	prealloc_goal;
+		unsigned long	next_block = tmp + 1;
 
 		prealloc_goal = es->s_prealloc_blocks ?
 			es->s_prealloc_blocks : EXT2_DEFAULT_PREALLOC_BLOCKS;
 
-		*prealloc_count = 0;
-		*prealloc_block = tmp + 1;
+		*prealloc_block = next_block;
 		for (k = 1;
 		     k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb);
-		     k++) {
+		     k++, next_block++) {
 			if (DQUOT_PREALLOC_BLOCK(sb, inode, 1))
 				break;
-			if (ext2_set_bit (j + k, bh->b_data)) {
+			if (*prealloc_block + *prealloc_count != next_block ||
+			    ext2_set_bit (j + k, bh->b_data)) {
 				DQUOT_FREE_BLOCK(sb, inode, 1);
  				break;
 			}
@@ -574,12 +575,12 @@
 		}	
 		gdp->bg_free_blocks_count =
 			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) -
-			       *prealloc_count);
+			       (k - 1));
 		es->s_free_blocks_count =
 			cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) -
-			       *prealloc_count);
+			       (k - 1));
 		ext2_debug ("Preallocated a further %lu bits.\n",
-			    *prealloc_count);
+			       (k - 1));
 	}
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/file.c linux.18p8/fs/ext2/file.c
--- linux.vanilla/fs/ext2/file.c	Fri Apr 21 12:46:42 2000
+++ linux.18p8/fs/ext2/file.c	Mon Sep 11 17:37:18 2000
@@ -136,7 +136,7 @@
 	return offset;
 }
 
-static inline void remove_suid(struct inode *inode)
+inline void ext2_remove_suid(struct inode *inode)
 {
 	unsigned int mode;
 
@@ -190,7 +190,7 @@
 			      inode->i_mode);
 		return -EINVAL;
 	}
-	remove_suid(inode);
+	ext2_remove_suid(inode);
 
 	if (filp->f_flags & O_APPEND)
 		pos = inode->i_size;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/fsync.c linux.18p8/fs/ext2/fsync.c
--- linux.vanilla/fs/ext2/fsync.c	Fri Apr 21 12:46:42 2000
+++ linux.18p8/fs/ext2/fsync.c	Tue Sep  5 22:00:39 2000
@@ -39,40 +39,6 @@
 {
 	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)) {
-		/* There can be a parallell read(2) that started read-I/O
-		   on the buffer so we can't assume that there's been
-		   an I/O error without first waiting I/O completation. */
-		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh))
-		{
-			brelse (bh);
-			return -1;
-		}
-	}
-	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
-		if (wait)
-			/* when we return from fsync all the blocks
-			   must be _just_ stored on disk */
-			wait_on_buffer(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);
@@ -101,10 +67,6 @@
 	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) 
@@ -112,29 +74,10 @@
 	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);
+	rc = sync_block (inode, iblock, wait);
 	if (rc)
 		return rc;
 	*bh = bread (inode->i_dev, tmp, blocksize);
@@ -142,9 +85,6 @@
 		return -1;
 	return 0;
 }
-#else
-#define sync_iblock_swab32 sync_iblock
-#endif
 
 static int sync_direct (struct inode * inode, int wait)
 {
@@ -170,9 +110,7 @@
 		return rc;
 	
 	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_block_swab32 (inode, 
-					((u32 *) ind_bh->b_data) + i,
-					wait);
+		rc = sync_block (inode, ((u32 *) ind_bh->b_data) + i, wait);
 		if (rc)
 			err = rc;
 	}
@@ -180,31 +118,6 @@
 	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;
@@ -216,40 +129,13 @@
 		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);
+		rc = sync_indirect(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)
 {
@@ -262,9 +148,7 @@
 		return rc;
 	
 	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_dindirect_swab32 (inode,
-					    ((u32 *) tind_bh->b_data) + i,
-					    wait);
+		rc = sync_dindirect(inode, ((u32 *)tind_bh->b_data) + i, wait);
 		if (rc)
 			err = rc;
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/inode.c linux.18p8/fs/ext2/inode.c
--- linux.vanilla/fs/ext2/inode.c	Fri Apr 21 12:46:42 2000
+++ linux.18p8/fs/ext2/inode.c	Tue Sep  5 22:00:39 2000
@@ -63,18 +63,7 @@
 	ext2_free_inode (inode);
 }
 
-#define inode_bmap(inode, nr) ((inode)->u.ext2_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;
-}
+#define inode_bmap(inode, nr) le32_to_cpu((inode)->u.ext2_i.i_data[(nr)])
 
 /* 
  * ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the
@@ -149,61 +138,89 @@
 	return result;
 }
 
+/**
+ *	ext2_block_to_path - parse the block number into array of offsets
+ *	@inode: inode in question (we are only interested in its superblock)
+ *	@i_block: block number to be parsed
+ *	@offsets: array to store the offsets in
+ *
+ *	To store the locations of file's data ext2 uses a data structure common
+ *	for UNIX filesystems - tree of pointers anchored in the inode, with
+ *	data blocks at leaves and indirect blocks in intermediate nodes.
+ *	This function translates the block number into path in that tree -
+ *	return value is the path length and @offsets[n] is the offset of
+ *	pointer to (n+1)th node in the nth one. If @block is out of range
+ *	(negative or too large) warning is printed and zero returned.
+ *
+ *	Note: function doesn't find node addresses, so no IO is needed. All
+ *	we need to know is the capacity of indirect blocks (taken from the
+ *	inode->i_sb).
+ */
+
+/*
+ * Portability note: the last comparison (check that we fit into triple
+ * indirect block) is spelled differently, because otherwise on an
+ * architecture with 32-bit longs and 8Kb pages we might get into trouble
+ * if our filesystem had 8Kb blocks. We might use long long, but that would
+ * kill us on x86. Oh, well, at least the sign propagation does not matter -
+ * i_block would have to be negative in the very beginning, so we would not
+ * get there at all.
+ */
+
+static int ext2_block_to_path(struct inode *inode, long i_block, int offsets[4])
+{
+	int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+	const long direct_blocks = EXT2_NDIR_BLOCKS,
+		indirect_blocks = ptrs,
+		double_blocks = (1 << (ptrs_bits * 2));
+	int n = 0;
+
+	if (i_block < 0) {
+		ext2_warning (inode->i_sb, "ext2_block_to_path", "block < 0");
+	} else if (i_block < direct_blocks) {
+		offsets[n++] = i_block;
+	} else if ( (i_block -= direct_blocks) < indirect_blocks) {
+		offsets[n++] = EXT2_IND_BLOCK;
+		offsets[n++] = i_block;
+	} else if ((i_block -= indirect_blocks) < double_blocks) {
+		offsets[n++] = EXT2_DIND_BLOCK;
+		offsets[n++] = i_block >> ptrs_bits;
+		offsets[n++] = i_block & (ptrs - 1);
+	} else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
+		offsets[n++] = EXT2_TIND_BLOCK;
+		offsets[n++] = i_block >> (ptrs_bits * 2);
+		offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
+		offsets[n++] = i_block & (ptrs - 1);
+	} else {
+		ext2_warning (inode->i_sb, "ext2_block_to_path", "block > big");
+	}
+	return n;
+}
+
 
 int ext2_bmap (struct inode * inode, int block)
 {
+	int offsets[4], *p;
+	int depth = ext2_block_to_path(inode, block, offsets);
+	struct buffer_head *bh;
 	int i;
-	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
-	int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
 
-	if (block < 0) {
-		ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
-		return 0;
-	}
-	if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
-		(1 << (addr_per_block_bits * 2)) +
-		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
-		ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
-		return 0;
-	}
-	if (block < EXT2_NDIR_BLOCKS)
-		return inode_bmap (inode, block);
-	block -= EXT2_NDIR_BLOCKS;
-	if (block < addr_per_block) {
-		i = inode_bmap (inode, EXT2_IND_BLOCK);
+	if (depth == 0)
+		goto fail;
+	i = inode_bmap (inode, *(p=offsets));
+	while (--depth) {
 		if (!i)
-			return 0;
-		return block_bmap (bread (inode->i_dev, i,
-					  inode->i_sb->s_blocksize), block);
+			break;
+		bh = bread (inode->i_dev, i, inode->i_sb->s_blocksize);
+		if (!bh)
+			goto fail;
+		i = le32_to_cpu(((u32 *) bh->b_data)[*++p]);
+		brelse (bh);
 	}
-	block -= addr_per_block;
-	if (block < (1 << (addr_per_block_bits * 2))) {
-		i = inode_bmap (inode, EXT2_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, EXT2_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));
+	return i;
+fail:
+	return 0;
 }
 
 static struct buffer_head * inode_getblk (struct inode * inode, int nr,
@@ -218,7 +235,8 @@
 repeat:
 	tmp = *p;
 	if (tmp) {
-		struct buffer_head * result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+		struct buffer_head * result;
+		result = getblk (inode->i_dev, le32_to_cpu(tmp), inode->i_sb->s_blocksize);
 		if (tmp == *p)
 			return result;
 		brelse (result);
@@ -236,7 +254,7 @@
 	if (!goal) {
 		for (tmp = nr - 1; tmp >= 0; tmp--) {
 			if (inode->u.ext2_i.i_data[tmp]) {
-				goal = inode->u.ext2_i.i_data[tmp];
+				goal = le32_to_cpu(inode->u.ext2_i.i_data[tmp]);
 				break;
 			}
 		}
@@ -257,7 +275,7 @@
 		brelse (result);
 		goto repeat;
 	}
-	*p = tmp;
+	*p = cpu_to_le32(tmp);
 	inode->u.ext2_i.i_next_alloc_block = new_block;
 	inode->u.ext2_i.i_next_alloc_goal = tmp;
 	inode->i_ctime = CURRENT_TIME;
@@ -349,21 +367,12 @@
 				  int create, int * err)
 {
 	struct buffer_head * bh;
-	unsigned long b;
-	unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
-	int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+	int offsets[4], *p;
+	int depth = ext2_block_to_path(inode, block, offsets);
 
 	*err = -EIO;
-	if (block < 0) {
-		ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
-		return NULL;
-	}
-	if (block > EXT2_NDIR_BLOCKS + addr_per_block +
-		(1 << (addr_per_block_bits * 2)) +
-		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
-		ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
-		return NULL;
-	}
+	if (depth == 0)
+		goto fail;
 	/*
 	 * If this is a sequential block allocation, set the next_alloc_block
 	 * to this block now so that all the indblock and data block
@@ -380,31 +389,14 @@
 	}
 
 	*err = -ENOSPC;
-	b = block;
-	if (block < EXT2_NDIR_BLOCKS)
-		return inode_getblk (inode, block, create, b, err);
-	block -= EXT2_NDIR_BLOCKS;
-	if (block < addr_per_block) {
-		bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err);
-		return block_getblk (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 (inode, EXT2_DIND_BLOCK, create, b, err);
-		bh = block_getblk (inode, bh, block >> addr_per_block_bits,
-				   create, inode->i_sb->s_blocksize, b, err);
-		return block_getblk (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 (inode, EXT2_TIND_BLOCK, create, b, err);
-	bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2),
-			   create, inode->i_sb->s_blocksize, b, err);
-	bh = block_getblk (inode, bh, (block >> addr_per_block_bits) & (addr_per_block - 1),
-			   create, inode->i_sb->s_blocksize, b, err);
-	return block_getblk (inode, bh, block & (addr_per_block - 1), create,
-			     inode->i_sb->s_blocksize, b, err);
+	bh = inode_getblk (inode, *(p=offsets), create, block, err);
+	while (--depth) {
+		bh = block_getblk (inode, bh, *++p, create,
+				     inode->i_sb->s_blocksize, block, err);
+	}
+	return bh;
+fail:
+	return NULL;
 }
 
 struct buffer_head * ext2_bread (struct inode * inode, int block, 
@@ -553,11 +545,8 @@
 			    "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(raw_inode->i_block[0]));
-	else if (S_ISLNK(inode->i_mode) && !inode->i_blocks)
-		for (block = 0; block < EXT2_N_BLOCKS; block++)
-			inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
 	else for (block = 0; block < EXT2_N_BLOCKS; block++)
-		inode->u.ext2_i.i_data[block] = le32_to_cpu(raw_inode->i_block[block]);
+		inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
 	brelse (bh);
 	inode->i_op = NULL;
 	if (inode->i_ino == EXT2_ACL_IDX_INO ||
@@ -677,11 +666,8 @@
 	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)
-		for (block = 0; block < EXT2_N_BLOCKS; block++)
-			raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
 	else for (block = 0; block < EXT2_N_BLOCKS; block++)
-		raw_inode->i_block[block] = cpu_to_le32(inode->u.ext2_i.i_data[block]);
+		raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
 	mark_buffer_dirty(bh, 1);
 	if (do_sync) {
 		ll_rw_block (WRITE, 1, &bh);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ext2/truncate.c linux.18p8/fs/ext2/truncate.c
--- linux.vanilla/fs/ext2/truncate.c	Fri Apr 21 12:46:42 2000
+++ linux.18p8/fs/ext2/truncate.c	Mon Sep 11 17:37:18 2000
@@ -130,11 +130,7 @@
 			goto in_use;
 
 	if (bh->b_count == 1) {
-		int tmp;
-		if (ind_bh)
-			tmp = le32_to_cpu(*p);
-		else
-			tmp = *p;
+		int tmp = le32_to_cpu(*p);
 		*p = 0;
 		inode->i_blocks -= (inode->i_sb->s_blocksize / 512);
 		mark_inode_dirty(inode);
@@ -170,7 +166,7 @@
 
 	for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
 		u32 * p = inode->u.ext2_i.i_data + i;
-		int tmp = *p;
+		int tmp = le32_to_cpu(*p);
 
 		if (!tmp)
 			continue;
@@ -215,11 +211,11 @@
 	unsigned long block_to_free = 0, free_count = 0;
 	int indirect_block, addr_per_block, blocks;
 
-	tmp = dind_bh ? le32_to_cpu(*p) : *p;
+	tmp = le32_to_cpu(*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)) {
+	if (tmp != le32_to_cpu(*p)) {
 		brelse (ind_bh);
 		return 1;
 	}
@@ -297,11 +293,11 @@
 	int i, tmp, retry = 0;
 	int dindirect_block, addr_per_block;
 
-	tmp = tind_bh ? le32_to_cpu(*p) : *p;
+	tmp = le32_to_cpu(*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)) {
+	if (tmp != le32_to_cpu(*p)) {
 		brelse (dind_bh);
 		return 1;
 	}
@@ -346,7 +342,8 @@
 
 	if (!(tmp = *p))
 		return 0;
-	tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+	tind_bh = bread (inode->i_dev, le32_to_cpu(tmp),
+						inode->i_sb->s_blocksize);
 	if (tmp != *p) {
 		brelse (tind_bh);
 		return 1;
@@ -355,7 +352,7 @@
 	if (!tind_bh) {
 		ext2_error(inode->i_sb, "trunc_tindirect",
 			"Read failure, inode=%ld, block=%d",
-			inode->i_ino, tmp);
+			inode->i_ino, le32_to_cpu(tmp));
 		*p = 0;
 		mark_inode_dirty(inode);
 		return 0;
@@ -391,6 +388,8 @@
 		return;
 	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
 		return;
+	
+	ext2_remove_suid(inode); 
 	ext2_discard_prealloc(inode);
 	while (1) {
 		retry = trunc_direct(inode);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/fat/dir.c linux.18p8/fs/fat/dir.c
--- linux.vanilla/fs/fat/dir.c	Sun Jun 11 21:44:18 2000
+++ linux.18p8/fs/fat/dir.c	Thu Aug 31 14:33:07 2000
@@ -139,6 +139,7 @@
 	unsigned char long_slots;
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
+	int small_letter = MSDOS_SB(sb)->options.small_letter;
 	unsigned char *unicode = NULL;
 	struct nls_table *nls = MSDOS_SB(sb)->nls_io;
 	int res = 0;
@@ -226,7 +227,7 @@
 
 		for (i = 0, last = 0; i < 8;) {
 			if (!(c = de->name[i])) break;
-			if (c >= 'A' && c <= 'Z') c += 32;
+			if (small_letter) c = tolower(c);
 			if (c == 0x05) c = 0xE5;
 			if ((bufname[i++] = c) != ' ')
 				last = i;
@@ -235,7 +236,7 @@
 		bufname[i++] = '.';
 		for (i2 = 0; i2 < 3; i2++) {
 			if (!(c = de->ext[i2])) break;
-			if (c >= 'A' && c <= 'Z') c += 32;
+			if (small_letter) c = tolower(c);
 			if ((bufname[i++] = c) != ' ')
 				last = i;
 		}
@@ -301,6 +302,7 @@
 	unsigned char long_slots;
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
+	int small_letter = MSDOS_SB(sb)->options.small_letter;
 	unsigned char *unicode = NULL;
 	struct nls_table *nls = MSDOS_SB(sb)->nls_io;
 	char bufname[14];
@@ -419,7 +421,7 @@
 	}
 	for (i = 0, last = 0; i < 8;) {
 		if (!(c = de->name[i])) break;
-		if (c >= 'A' && c <= 'Z') c += 32;
+		if (small_letter) c = tolower(c);
 		/* see namei.c, msdos_format_name */
 		if (c == 0x05) c = 0xE5;
 		if ((ptname[i++] = c) != ' ')
@@ -429,7 +431,7 @@
 	ptname[i++] = '.';
 	for (i2 = 0; i2 < 3; i2++) {
 		if (!(c = de->ext[i2])) break;
-		if (c >= 'A' && c <= 'Z') c += 32;
+		if (small_letter) c = tolower(c);
 		if ((ptname[i++] = c) != ' ')
 			last = i;
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/fat/inode.c linux.18p8/fs/fat/inode.c
--- linux.vanilla/fs/fat/inode.c	Sun Jun 11 21:44:18 2000
+++ linux.18p8/fs/fat/inode.c	Thu Aug 31 14:33:07 2000
@@ -216,6 +216,7 @@
 	opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = 0;
 	opts->codepage = 0;
 	opts->utf8 = 0;
+	opts->small_letter = 0;
 	opts->iocharset = NULL;
 	*debug = *fat = 0;
 
@@ -260,6 +261,9 @@
 		}
 		else if (!strcmp(this_char,"showexec")) {
 			opts->showexec = 1;
+		}
+		else if (!strcmp(this_char,"small")) {
+			opts->small_letter = 1;
 		}
 		else if (!strcmp(this_char,"dotsOK") && value) {
 			if (!strcmp(value,"yes")) opts->dotsOK = 1;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ioctl.c linux.18p8/fs/ioctl.c
--- linux.vanilla/fs/ioctl.c	Fri Apr 21 12:46:43 2000
+++ linux.18p8/fs/ioctl.c	Thu Aug 31 15:57:50 2000
@@ -84,8 +84,12 @@
 			/* Did FASYNC state change ? */
 			if ((flag ^ filp->f_flags) & FASYNC) {
 				if (filp->f_op && filp->f_op->fasync)
-					filp->f_op->fasync(fd, filp, on); 
+					error = filp->f_op->fasync(fd, filp, on);
+				else error = -ENOTTY;
 			}
+			if (error != 0)
+				break;
+
 			if (on)
 				filp->f_flags |= FASYNC;
 			else
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/locks.c linux.18p8/fs/locks.c
--- linux.vanilla/fs/locks.c	Fri Apr 21 12:46:44 2000
+++ linux.18p8/fs/locks.c	Wed Sep 13 16:48:19 2000
@@ -415,13 +415,9 @@
 	 */
 	if (IS_MANDLOCK(inode) &&
 	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
-	    inode->i_mmap) {
-		struct vm_area_struct *vma = inode->i_mmap;
+	    inode->i_mmap_shared) {
 		error = -EAGAIN;
-		do {
-			if (vma->vm_flags & VM_MAYSHARE)
-				goto out_putf;
-		} while ((vma = vma->vm_next_share) != NULL);
+		goto out_putf;
 	}
 
 	error = -EINVAL;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ncpfs/file.c linux.18p8/fs/ncpfs/file.c
--- linux.vanilla/fs/ncpfs/file.c	Fri Apr 21 12:46:44 2000
+++ linux.18p8/fs/ncpfs/file.c	Mon Sep 11 18:56:51 2000
@@ -252,7 +252,7 @@
 		}
 		if (ncp_write_kernel(NCP_SERVER(inode), 
 		    NCP_FINFO(inode)->file_handle,
-		    pos, to_write, buf, &written_this_time) != 0) {
+		    pos, to_write, bouncebuffer, &written_this_time) != 0) {
 			errno = -EIO;
 			break;
 		}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/dir.c linux.18p8/fs/nfs/dir.c
--- linux.vanilla/fs/nfs/dir.c	Fri Apr 21 12:46:44 2000
+++ linux.18p8/fs/nfs/dir.c	Thu Aug 31 15:00:38 2000
@@ -309,6 +309,8 @@
 			continue;
 		if (cache->dev != dev)
 			continue;
+		if (!cache->valid)
+			continue;
 		if (cache->locked) {
 			printk("NFS: cache locked for %s/%ld\n",
 				kdevname(dev), (long) ino);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/Config.in linux.18p8/fs/nls/Config.in
--- linux.vanilla/fs/nls/Config.in	Sun Jun 11 21:44:19 2000
+++ linux.18p8/fs/nls/Config.in	Mon Sep 11 17:07:03 2000
@@ -4,7 +4,8 @@
 
 # msdos and Joliet want NLS
 if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
-	-o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" ]; then
+	-o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
+	-o "$CONFIG_SMB_FS" != "n" ]; then
   define_bool CONFIG_NLS y
 else
   define_bool CONFIG_NLS n
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_cp932.c linux.18p8/fs/nls/nls_cp932.c
--- linux.vanilla/fs/nls/nls_cp932.c	Sat Sep  9 18:42:48 2000
+++ linux.18p8/fs/nls/nls_cp932.c	Fri Sep  8 16:55:43 2000
@@ -9812,24 +9812,35 @@
 
 	if (boundlen <= 0)
 		return;
-	if (ch == 0xFF && 0x61 <= cl && cl <= 0x9F){
+	if (ch == 0 && cl < 0x80) {
+		out[0] = cl;
+		*outlen = 1;
+		return;
+	}
+	else if (ch == 0xFF && 0x61 <= cl && cl <= 0x9F) {
 		out[0] = cl + 0x40;
 		*outlen = 1;
 		return;
 	}
+
 	uni2charset = page_uni2charset[ch];
-	*outlen = 0;
-	if (uni2charset){
+	if (uni2charset) {
 		if (boundlen <= 1)
 			return;
 		out[0] = uni2charset[cl*2];
 		out[1] = uni2charset[cl*2+1];
-		*outlen = 1;
-	} else if (ch==0 && cl)
+		*outlen = 2;
+	}
+	/*
+	else if (ch == 0 && cl) {
 		out[0] = cl;
-	else
+		*outlen = 1;
+	}
+	*/
+	else {
 		out[0] = '?';
-	(*outlen)++;
+		*outlen = 1;
+	}
 	return;
 }
 
@@ -9840,21 +9851,29 @@
 
 	ch = rawstring[0];
 	cl = rawstring[1];
-	if (0xA1 <= ch && ch <= 0xDF){
+	if (ch < 0x80) {
+		*uni1 = ch;
+		*uni2 = 0x00;
+		*offset = 1;
+		return;
+	}
+	else if (0xA1 <= ch && ch <= 0xDF) {
 		*uni1 = ch - 0x40;
 		*uni2 = 0xFF;
 		*offset = 1;
 		return;
 	}
+
 	charset2uni = page_charset2uni[ch];
-	if (charset2uni && cl){
+	*offset = 2;
+	if (charset2uni) {
 		*uni1 = charset2uni[cl].uni2;
 		*uni2 = charset2uni[cl].uni1;
-		*offset = 2;
-	} else{
-		*uni1 = ch;
+	}
+	else {
+		/* *uni1 = ch; */
+		*uni1 = '?';
 		*uni2 = 0x00;
-		*offset = 1;
 	}
 	return;
 }
@@ -9891,7 +9910,12 @@
 {
 	if (boundlen <= 0)
 		return;
-	if (ch == 0xFF && 0x61 <= cl && cl <= 0x9F){
+	if (ch == 0 && cl < 0x80) {
+		out[0] = cl;
+		*outlen = 1;
+		return;
+	}
+	else if (ch == 0xFF && 0x61 <= cl && cl <= 0x9F) {
 		if (boundlen <= 1)
 			return;
 		out[0] = 0x8E; /* EUCHANKAKU */
@@ -9899,6 +9923,8 @@
 		*outlen = 2;
 		return;
 	}
+
+	*outlen = 0;
 	uni2char(ch, cl, out, boundlen, outlen);
 	if (*outlen == 2) {
 		/* translate SJIS into EUC-JP */ 
@@ -9913,30 +9939,46 @@
 		else
 			out[1] = out[1] + 0x02;
 	}
+	return;
 }
 
 static void char2uni_euc_jp(unsigned char *rawstring, int *offset, unsigned char *uni1, unsigned char *uni2)
 {
+	unsigned char ch, cl;
 	unsigned char sjis_temp[2];
 
-	if (rawstring[0] == 0x8E) {
-		if (0xA1 <= rawstring[1] && rawstring[1] <= 0xDF){
-			*uni1 = rawstring[1] - 0x40;
+	ch = rawstring[0];
+	cl = rawstring[1];
+	if (ch < 0x80) {
+		*uni1 = ch;
+		*uni2 = 0x00;
+		*offset = 1;
+		return;
+	}
+	else if (ch == 0x8E) {
+		if (0xA1 <= cl && cl <= 0xDF){
+			*uni1 = cl - 0x40;
 			*uni2 = 0xFF;
-			*offset = 2;
-			return;
 		}
+		else {
+			*uni1 = '?';
+			*uni2 = 0x00;
+		}
+		*offset = 2;
+		return;
 	}
+
 	/* translate EUC-JP into SJIS */
-	sjis_temp[0] = ((rawstring[0]-0x5f)/2) ^ 0xA0;
-	if (!(rawstring[0]&1))
-		sjis_temp[1] = rawstring[1] - 0x02;
-	else if (rawstring[1] < 0xE0)
-		sjis_temp[1] = rawstring[1] - 0x61;
+	sjis_temp[0] = ((ch-0x5f)/2) ^ 0xA0;
+	if (!(ch&1))
+		sjis_temp[1] = cl - 0x02;
+	else if (cl < 0xE0)
+		sjis_temp[1] = cl - 0x61;
 	else
-		sjis_temp[1] = rawstring[1] - 0x60;
+		sjis_temp[1] = cl - 0x60;
 
 	char2uni(sjis_temp, offset, uni1, uni2);
+	return;
 }
 
 static struct nls_table euc_jp_table = {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ntfs/support.c linux.18p8/fs/ntfs/support.c
--- linux.vanilla/fs/ntfs/support.c	Sun Jun 11 21:44:22 2000
+++ linux.18p8/fs/ntfs/support.c	Mon Sep 11 17:49:08 2000
@@ -298,7 +298,7 @@
 	if(!result)return ENOMEM;
 	*out_len=in_len;
 	for(i=o=0;i<in_len;i++, o++){
-		unsigned short cl,ch;
+		unsigned short cl=0,ch=0;
 		if(in[i]!=':' || (vol->nct & nct_uni_xlate)==0){
 			int len;
 			unsigned char clc=cl, chc=ch;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/ChangeLog linux.18p8/fs/smbfs/ChangeLog
--- linux.vanilla/fs/smbfs/ChangeLog	Sat Sep  9 18:42:49 2000
+++ linux.18p8/fs/smbfs/ChangeLog	Sat Sep  2 23:33:56 2000
@@ -1,5 +1,15 @@
 ChangeLog for smbfs.
 
+2000-09-01 Urban Widmark <urban@svenskatest.se>
+
+	* proc.c: add back lanman2 support (OS/2 and others)
+	* proc.c: check length of paths to avoid buffer overflow
+	* proc.c: don't do interruptable_sleep in smb_retry to avoid signal
+	  problem/race.
+	* proc.c: O_RDONLY & smb_revalidate_inode fix (tail -f)
+	* proc.c: add nls support
+	* sock.c: attempt to fix smb_data_callback (avoid infinite loop)
+
 2000-07-20 Urban Widmark <urban@svenskatest.se>
 
 	* proc.c: fix 2 places where bad server responses could cause an Oops.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/dir.c linux.18p8/fs/smbfs/dir.c
--- linux.vanilla/fs/smbfs/dir.c	Sat Sep  9 18:42:49 2000
+++ linux.18p8/fs/smbfs/dir.c	Sat Sep  2 23:33:56 2000
@@ -167,7 +167,7 @@
 }
 
 /*
- * Note: in order to allow the smbclient process to open the
+ * Note: in order to allow the smbmount process to open the
  * mount point, we don't revalidate if conn_pid is NULL.
  */
 static int
@@ -194,10 +194,10 @@
 
 static struct dentry_operations smbfs_dentry_operations =
 {
-	smb_lookup_validate,	/* d_revalidate(struct dentry *) */
-	smb_hash_dentry,	/* d_hash */
-	smb_compare_dentry,	/* d_compare */
-	smb_delete_dentry	/* d_delete(struct dentry *) */
+	d_revalidate:	smb_lookup_validate,
+	d_hash:		smb_hash_dentry,
+	d_compare:	smb_compare_dentry,
+	d_delete:	smb_delete_dentry
 };
 
 /*
@@ -256,8 +256,7 @@
 
 	if (a->len != b->len)
 		goto out;
-	for (i=0; i < a->len; i++)
-	{
+	for (i=0; i < a->len; i++) {
 		if (tolower(a->name[i]) != tolower(b->name[i]))
 			goto out;
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/inode.c linux.18p8/fs/smbfs/inode.c
--- linux.vanilla/fs/smbfs/inode.c	Sat Sep  9 18:42:50 2000
+++ linux.18p8/fs/smbfs/inode.c	Mon Sep 11 17:07:03 2000
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/dcache.h>
+#include <linux/nls.h>
 
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
@@ -31,6 +32,13 @@
 
 #include "smb_debug.h"
 
+/* Always pick a default string */
+#ifdef CONFIG_SMB_NLS_REMOTE
+#define SMB_NLS_REMOTE CONFIG_SMB_NLS_REMOTE
+#else
+#define SMB_NLS_REMOTE ""
+#endif
+
 static void smb_read_inode(struct inode *);
 static void smb_put_inode(struct inode *);
 static void smb_delete_inode(struct inode *);
@@ -320,13 +328,22 @@
 	if (server->packet)
 		smb_vfree(server->packet);
 
+	if(sb->u.smbfs_sb.remote_nls) {
+		unload_nls(sb->u.smbfs_sb.remote_nls);
+		sb->u.smbfs_sb.remote_nls = NULL;
+	}
+	if(sb->u.smbfs_sb.local_nls) {
+		unload_nls(sb->u.smbfs_sb.local_nls);
+		sb->u.smbfs_sb.local_nls = NULL;
+	}
+
 	MOD_DEC_USE_COUNT;
 }
 
 struct super_block *
 smb_read_super(struct super_block *sb, void *raw_data, int silent)
 {
-	struct smb_mount_data *mnt;
+	struct smb_mount_data_kernel *mnt;
 	struct inode *root_inode;
 	struct smb_fattr root;
 
@@ -357,22 +374,36 @@
 		goto out_no_mem;
 
 	/* Allocate the global temp buffer */
-	sb->u.smbfs_sb.temp_buf = kmalloc(SMB_MAXPATHLEN + 20, GFP_KERNEL);
+	sb->u.smbfs_sb.temp_buf = kmalloc(2*SMB_MAXPATHLEN + 20, GFP_KERNEL);
 	if (!sb->u.smbfs_sb.temp_buf)
 		goto out_no_temp;
 
+	/* Setup NLS stuff */
+	sb->u.smbfs_sb.remote_nls = NULL;
+	sb->u.smbfs_sb.local_nls = NULL;
+	sb->u.smbfs_sb.name_buf = sb->u.smbfs_sb.temp_buf + SMB_MAXPATHLEN + 20;
+
 	/* Allocate the mount data structure */
-	mnt = kmalloc(sizeof(struct smb_mount_data), GFP_KERNEL);
+	mnt = kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
 	if (!mnt)
 		goto out_no_mount;
-	*mnt = *((struct smb_mount_data *) raw_data);
+	memcpy(mnt, raw_data, sizeof(struct smb_mount_data));
+	strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
+		SMB_NLS_MAXNAMELEN);
+	strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE,
+		SMB_NLS_MAXNAMELEN);
+
 	/* FIXME: ** temp ** pass config flags in file mode */
-	mnt->version = (mnt->file_mode >> 9);
+	mnt->flags = (mnt->file_mode >> 9);
 	mnt->file_mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
 	mnt->file_mode |= S_IFREG;
 	mnt->dir_mode  &= (S_IRWXU | S_IRWXG | S_IRWXO);
 	mnt->dir_mode  |= S_IFDIR;
 	sb->u.smbfs_sb.mnt = mnt;
+
+	smb_setcodepage(&sb->u.smbfs_sb, &mnt->codepage);
+	if (!sb->u.smbfs_sb.convert)
+		PARANOIA("convert funcptr was NULL!\n");
 
 	/*
 	 * Keep the super block locked while we get the root inode.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/proc.c linux.18p8/fs/smbfs/proc.c
--- linux.vanilla/fs/smbfs/proc.c	Sat Sep  9 18:42:50 2000
+++ linux.18p8/fs/smbfs/proc.c	Sat Sep  2 23:33:56 2000
@@ -16,6 +16,7 @@
 #include <linux/fcntl.h>
 #include <linux/dcache.h>
 #include <linux/dirent.h>
+#include <linux/nls.h>
 
 #include <linux/smb_fs.h>
 #include <linux/smbno.h>
@@ -48,6 +49,19 @@
 		    struct smb_sb_info *server);
 
 
+static inline void
+smb_lock_server(struct smb_sb_info *server)
+{
+	down(&(server->sem));
+}
+
+static inline void
+smb_unlock_server(struct smb_sb_info *server)
+{
+	up(&(server->sem));
+}
+
+
 /* reverse a string inline. This is used by the dircache walking routines */
 static void reverse_string(char *buf, int len) {
 	char c;
@@ -60,6 +74,100 @@
 	}
 }
 
+/* no conversion, just a wrapper for memcpy. */
+static int convert_memcpy(char *output, int olen,
+			  const char *input, int ilen,
+			  struct nls_table *nls_from,
+			  struct nls_table *nls_to)
+{
+	memcpy(output, input, ilen);
+	return ilen;
+}
+
+/* convert from one "codepage" to another (possibly being utf8). */
+static int convert_cp(char *output, int olen,
+		      const char *input, int ilen,
+		      struct nls_table *nls_from,
+		      struct nls_table *nls_to)
+{
+	int len = 0;
+	int n;
+	unsigned char ch;
+	unsigned char cl;
+
+	/* we don't need this, but we are a bit paranoid ... */
+	if (!nls_from || !nls_to) {
+		PARANOIA("nls_from=%p, nls_to=%p\n", nls_from, nls_to);
+		return convert_memcpy(output, olen, input, ilen, NULL, NULL);
+	}
+
+	while (ilen > 0) {
+		/* convert by changing to unicode and back to the new cp */
+		n = -1;
+		nls_from->char2uni((unsigned char *)input, &n, &cl, &ch);
+		if (n < 0)
+			goto out;
+		input += n;
+		ilen -= n;
+
+		n = -1;
+		nls_to->uni2char(ch, cl, output, olen, &n);
+		if (n < 0)
+			goto out;
+		output += n;
+		olen -= n;
+
+		len += n;
+	}
+out:
+	return len;
+}
+
+static int setcodepage(struct smb_sb_info *server,
+		       struct nls_table **p, char *name)
+{
+	struct nls_table *nls;
+
+	if (!name || !*name) {
+		nls = NULL;
+	} else if ( (nls = load_nls(name)) == NULL) {
+		printk (KERN_ERR "smbfs: failed to load nls '%s'\n", name);
+		return -EINVAL;
+	}
+
+	/* if already set, unload the previous one. */
+	if (*p)
+		unload_nls(*p);
+	*p = nls;
+
+	return 0;
+}
+
+/* Handles all changes to codepage settings. */
+int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp)
+{
+	int n;
+
+	smb_lock_server(server);
+
+	n = setcodepage(server, &server->local_nls, cp->local_name);
+	if (n != 0)
+		goto out;
+	n = setcodepage(server, &server->remote_nls, cp->remote_name);
+	if (n != 0)
+		setcodepage(server, &server->local_nls, NULL);
+
+out:
+	if (server->local_nls != NULL && server->remote_nls != NULL)
+		server->convert = convert_cp;
+	else
+		server->convert = convert_memcpy;
+
+	smb_unlock_server(server);
+	return n;
+}
+
+
 /*****************************************************************************/
 /*                                                                           */
 /*  Encoding/Decoding section                                                */
@@ -81,12 +189,14 @@
 }
 
 /*
- * smb_build_path: build the path to entry and name storing it in buf.
+ * smb_encode_path: build the path to entry and name storing it in buf.
  * The path returned will have the trailing '\0'.
  */
-static int smb_build_path(struct dentry * entry, struct qstr * name, char * buf)
+static int smb_encode_path(struct smb_sb_info *server, char * buf,
+			   struct dentry * entry, struct qstr * name)
 {
 	char *path = buf;
+	int len;
 
 	if (entry == NULL)
 		goto test_name_and_out;
@@ -106,9 +216,16 @@
 	 * and store it in reversed order [see reverse_string()]
 	 */
 	for (;;) {
-		memcpy(path, entry->d_name.name, entry->d_name.len);
-		reverse_string(path, entry->d_name.len);
-		path += entry->d_name.len;
+		if (entry->d_name.len > SMB_MAXNAMELEN)
+			return -ENAMETOOLONG;
+		if (path - buf + entry->d_name.len > SMB_MAXPATHLEN)
+			return -ENAMETOOLONG;
+
+		len = server->convert(path, SMB_MAXNAMELEN, 
+				      entry->d_name.name, entry->d_name.len,
+				      server->local_nls, server->remote_nls);
+		reverse_string(path, len);
+		path += len;
 
 		*(path++) = '\\';
 
@@ -124,22 +241,16 @@
 	if (name != NULL) {
 		*(path++) = '\\';
 name_and_out:
-		memcpy(path, name->name, name->len);
-		path += name->len;
+		len = server->convert(path, SMB_MAXNAMELEN, 
+				      name->name, name->len,
+				      server->local_nls, server->remote_nls);
+		path += len;
 	}
 out:
 	*(path++) = '\0';
 	return (path-buf);
 }
 
-static char *smb_encode_path(struct smb_sb_info *server, char *buf,
-			     struct dentry *dir, struct qstr *name)
-{
-	buf += smb_build_path(dir, name, buf);
-
-	return buf;
-}
-
 /* The following are taken directly from msdos-fs */
 
 /* Linear day numbers of the respective 1sts in non-leap years. */
@@ -434,24 +545,12 @@
 	return EIO;
 }
 
-static inline void
-smb_lock_server(struct smb_sb_info *server)
-{
-	down(&(server->sem));
-}
-
-static inline void
-smb_unlock_server(struct smb_sb_info *server)
-{
-	up(&(server->sem));
-}
-
 /*
  * smb_retry: This function should be called when smb_request_ok has
-   indicated an error. If the error was indicated because the
-   connection was killed, we try to reconnect. If smb_retry returns 0,
-   the error was indicated for another reason, so a retry would not be
-   of any use.
+ * indicated an error. If the error was indicated because the
+ * connection was killed, we try to reconnect. If smb_retry returns 0,
+ * the error was indicated for another reason, so a retry would not be
+ * of any use.
  * N.B. The server must be locked for this call.
  */
 static int
@@ -465,8 +564,7 @@
 
 	smb_close_socket(server);
 
-	if (pid == 0)
-	{
+	if (pid == 0) {
 		printk(KERN_ERR "smb_retry: no connection process\n");
 		server->state = CONN_RETRIED;
 		goto out;
@@ -481,26 +579,35 @@
 	 * Note: use the "priv" flag, as a user process may need to reconnect.
 	 */
 	error = kill_proc(pid, SIGUSR1, 1);
-	if (error)
-	{
+	if (error) {
 		printk(KERN_ERR "smb_retry: signal failed, error=%d\n", error);
 		goto out_restore;
 	}
-	VERBOSE("signalled pid %d, waiting for new connection\n",
-		server->conn_pid);
+	VERBOSE("signalled pid %d, waiting for new connection\n", pid);
 
 	/*
 	 * Wait for the new connection.
 	 */
+#ifdef SMB_RETRY_INTR
 	interruptible_sleep_on_timeout(&server->wait,  5*HZ);
 	if (signal_pending(current))
 		printk(KERN_INFO "caught signal\n");
+#else
+	/*
+	 * We don't want to be interrupted. For example, what if 'current'
+	 * already has recieved a signal? sleep_on would terminate immediately
+	 * and smbmount would not be able to re-establish connection.
+	 *
+	 * smbmount should be able to reconnect later, but it can't because
+	 * it will get an -EIO on attempts to open the mountpoint!
+	 */
+	sleep_on_timeout(&server->wait, 5*HZ);
+#endif
 
 	/*
 	 * Check for a valid connection.
 	 */
-	if (server->state == CONN_VALID)
-	{
+	if (server->state == CONN_VALID) {
 		PARANOIA("sucessful, new pid=%d, generation=%d\n",
 			 server->conn_pid, server->generation);
 		result = 1;
@@ -599,8 +706,13 @@
 	    !capable(CAP_SYS_ADMIN))
 		goto out;
 
-	if (opt->protocol < SMB_PROTOCOL_NT1) {
-		printk(KERN_NOTICE "smbfs: protocols older than NT1 are not suppported\n");
+	/*
+	 * Support NT1 & LANMAN2, they are not that different and
+	 * some people are still using LANMAN2 (OS/2)
+	 */
+	if (opt->protocol < SMB_PROTOCOL_LANMAN2) {
+		printk(KERN_NOTICE "smbfs: protocols older than LANMAN2 are not"
+		       " suppported [%d]\n", opt->protocol);
 		goto out;
 	}
 
@@ -626,9 +738,10 @@
 
 	/* now that we have an established connection we can detect the server
 	   type and enable bug workarounds */
-	if ((server->opt.max_xmit < 0x1000) &&
+	if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
+	    (server->opt.max_xmit < 0x1000) &&
 	    !(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
-		server->mnt->version |= SMB_FIX_WIN95;
+		server->mnt->flags |= SMB_MOUNT_WIN95;
 #ifdef SMBFS_DEBUG_VERBOSE
 		printk(KERN_NOTICE "smb_newconn: detected WIN95 server\n");
 #endif
@@ -639,7 +752,11 @@
 		server->opt.capabilities);
 
 out:
+#ifdef SMB_RETRY_INTR
 	wake_up_interruptible(&server->wait);
+#else
+	wake_up(&server->wait);
+#endif
 	return error;
 
 out_putf:
@@ -706,7 +823,7 @@
 {
 	struct inode *ino = dentry->d_inode;
 	int mode, read_write = 0x42, read_only = 0x40;
-	int error;
+	int res;
 	char *p;
 
 	/*
@@ -716,29 +833,33 @@
 	if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
 		mode = read_only;
 #if 0
+	/* FIXME: why is this code not in? below we fix it so that a caller
+	   wanting RO doesn't get RW. smb_revalidate_inode does some 
+	   optimization based on access mode. tail -f needs it to be correct. */
 	if (!(wish & (O_WRONLY | O_RDWR)))
 		mode = read_only;
 #endif
 
-      retry:
+retry:
 	p = smb_setup_header(server, SMBopen, 2, 0);
 	WSET(server->packet, smb_vwv0, mode);
 	WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dentry, NULL);
+	res = smb_encode_path(server, p, dentry, NULL);
+	if (res < 0)
+		goto out;
+	p += res;
 	smb_setup_bcc(server, p);
 
-	error = smb_request_ok(server, SMBopen, 7, 0);
-	if (error != 0)
-	{
+	res = smb_request_ok(server, SMBopen, 7, 0);
+	if (res != 0) {
 		if (smb_retry(server))
 			goto retry;
 
 		if (mode == read_write &&
-		    (error == -EACCES || error == -ETXTBSY || error == -EROFS))
-		{
+		    (res == -EACCES || res == -ETXTBSY || res == -EROFS)) {
 			VERBOSE("%s/%s R/W failed, error=%d, retrying R/O\n",
-				DENTRY_PATH(dentry), error);
+				DENTRY_PATH(dentry), res);
 			mode = read_only;
 			goto retry;
 		}
@@ -751,10 +872,12 @@
 	/* smb_vwv2 has mtime */
 	/* smb_vwv4 has size  */
 	ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK);
+	if (!(wish & (O_WRONLY | O_RDWR)))
+		ino->u.smbfs_i.access = SMB_O_RDONLY;
 	ino->u.smbfs_i.open = server->generation;
 
 out:
-	return error;
+	return res;
 }
 
 /*
@@ -768,8 +891,7 @@
 	int result;
 
 	result = -ENOENT;
-	if (!inode)
-	{
+	if (!inode) {
 		printk(KERN_ERR "smb_open: no inode for dentry %s/%s\n",
 		       DENTRY_PATH(dentry));
 		goto out;
@@ -780,16 +902,14 @@
 	 * currently open, we can be sure that the file isn't about
 	 * to be closed. (See smb_close_dentry() below.)
 	 */
-	if (!smb_is_open(inode))
-	{
+	if (!smb_is_open(inode)) {
 		struct smb_sb_info *server = SMB_SERVER(inode);
 		smb_lock_server(server);
 		result = 0;
 		if (!smb_is_open(inode))
 			result = smb_proc_open(server, dentry, wish);
 		smb_unlock_server(server);
-		if (result)
-		{
+		if (result) {
 			PARANOIA("%s/%s open failed, result=%d\n",
 				 DENTRY_PATH(dentry), result);
 			goto out;
@@ -805,8 +925,7 @@
 	 */
 	result = 0;
 	if (inode->u.smbfs_i.access != wish && 
-	    inode->u.smbfs_i.access != SMB_O_RDWR)
-	{
+	    inode->u.smbfs_i.access != SMB_O_RDWR) {
 		PARANOIA("%s/%s access denied, access=%x, wish=%x\n",
 			 DENTRY_PATH(dentry), inode->u.smbfs_i.access, wish);
 		result = -EACCES;
@@ -871,6 +990,8 @@
 		/*
 		 * Force a revalidation after closing 
 		 */
+		if (server->opt.protocol < SMB_PROTOCOL_NT1)
+			ino->u.smbfs_i.oldmtime = 0;
 		ino->u.smbfs_i.closed = jiffies;
 	}
 	return result;
@@ -1029,31 +1150,33 @@
 {
 	struct smb_sb_info *server = server_from_dentry(dentry);
 	char *p;
-	int error;
+	int result;
 
 	smb_lock_server(server);
 
-      retry:
+retry:
 	p = smb_setup_header(server, SMBcreate, 3, 0);
 	WSET(server->packet, smb_vwv0, attr);
 	DSET(server->packet, smb_vwv1, utc2local(server, ctime));
 	*p++ = 4;
-	p = smb_encode_path(server, p, dentry, NULL);
+	result = smb_encode_path(server, p, dentry, NULL);
+	if (result < 0)
+		goto out;
+	p += result;
 	smb_setup_bcc(server, p);
 
-	error = smb_request_ok(server, SMBcreate, 1, 0);
-	if (error < 0)
-	{
+	result = smb_request_ok(server, SMBcreate, 1, 0);
+	if (result < 0) {
 		if (smb_retry(server))
 			goto retry;
 		goto out;
 	}
 	*fileid = WVAL(server->packet, smb_vwv0);
-	error = 0;
+	result = 0;
 
 out:
 	smb_unlock_server(server);
-	return error;
+	return result;
 }
 
 int
@@ -1065,17 +1188,22 @@
 
 	smb_lock_server(server);
 
-      retry:
+retry:
 	p = smb_setup_header(server, SMBmv, 1, 0);
 	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN | aDIR);
 	*p++ = 4;
-	p = smb_encode_path(server, p, old_dentry, NULL);
+	result = smb_encode_path(server, p, old_dentry, NULL);
+	if (result < 0)
+		goto out;
+	p += result;
 	*p++ = 4;
-	p = smb_encode_path(server, p, new_dentry, NULL);
+	result = smb_encode_path(server, p, new_dentry, NULL);
+	if (result < 0)
+		goto out;
+	p += result;
 	smb_setup_bcc(server, p);
 
-	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
-	{
+	if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) {
 		if (smb_retry(server))
 			goto retry;
 		goto out;
@@ -1098,15 +1226,17 @@
 
 	smb_lock_server(server);
 
-      retry:
+retry:
 	p = smb_setup_header(server, command, 0, 0);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dentry, NULL);
+	result = smb_encode_path(server, p, dentry, NULL);
+	if (result < 0)
+		goto out;
+	p += result;
 	smb_setup_bcc(server, p);
 
 	result = smb_request_ok(server, command, 0, 0);
-	if (result < 0)
-	{
+	if (result < 0) {
 		if (smb_retry(server))
 			goto retry;
 		goto out;
@@ -1165,15 +1295,17 @@
 
 	smb_lock_server(server);
 
-      retry:
+retry:
 	p = smb_setup_header(server, SMBunlink, 1, 0);
 	WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dentry, NULL);
+	result = smb_encode_path(server, p, dentry, NULL);
+	if (result < 0)
+		goto out;
+	p += result;
 	smb_setup_bcc(server, p);
 
-	if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
-	{
+	if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) {
 #if SMBFS_POSIX_UNLINK
                 if (result == -EACCES && !flag) {
 			/* Posix semantics is for the read-only state
@@ -1292,7 +1424,7 @@
  */
 static char *
 smb_decode_long_dirent(struct smb_sb_info *server, char *p,
-		       struct cache_dirent *entry)
+		       struct cache_dirent *entry, int level)
 {
 	char *result;
 	unsigned int len = 0;
@@ -1302,19 +1434,39 @@
 	 */
 	entry->ino = 0;
 
-	result = p + WVAL(p, 0);
-	len = DVAL(p, 60);
-	if (len > SMB_MAXNAMELEN)
-		len = SMB_MAXNAMELEN;
-	/* NT4 null terminates */
-	entry->name = p + 94;
-	if (len && entry->name[len-1] == '\0')
-		len--;
-	entry->len = len;
-
-	VERBOSE("info 260 at %p, len=%d, name=%.*s\n",
-		p, entry->len, entry->len, entry->name);
+	switch (level) {
+	case 1:
+		len = *((unsigned char *) p + 22);
+		entry->name = p + 23;
+		result = p + 24 + len;
+
+		VERBOSE("info 1 at %p, len=%d, name=%.*s\n",
+			p, len, len, entry->name);
+		break;
+	case 260:
+		result = p + WVAL(p, 0);
+		len = DVAL(p, 60);
+		if (len > SMB_MAXNAMELEN)
+			len = SMB_MAXNAMELEN;
+		/* NT4 null terminates */
+		entry->name = p + 94;
+		if (len && entry->name[len-1] == '\0')
+			len--;
+
+		VERBOSE("info 260 at %p, len=%d, name=%.*s\n",
+			p, len, len, entry->name);
+		break;
+	default:
+		PARANOIA("Unknown info level %d\n", level);
+		result = p + WVAL(p, 0);
+		goto out;
+	}
 
+	entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
+				     entry->name, len,
+				     server->remote_nls, server->local_nls);
+	entry->name = server->name_buf;
+out:
 	return result;
 }
 
@@ -1336,9 +1488,11 @@
 		      void *cachep)
 {
 	unsigned char *p;
-	char *mask, *param = server->temp_buf;
+	char *mask, *lastname, *param = server->temp_buf;
 	__u16 command;
 	int first, entries, entries_seen;
+
+	/* Both NT and OS/2 accept info level 1 (but see note below). */
 	int info_level = 260;
 	const int max_matches = 512;
 
@@ -1348,19 +1502,30 @@
 	int resp_param_len = 0;
 	int ff_searchcount = 0;
 	int ff_eos = 0;
+	int ff_lastname = 0;
 	int ff_dir_handle = 0;
 	int loop_count = 0;
 	int mask_len, i, result;
 	static struct qstr star = { "*", 1, 0 };
 
+	/*
+	 * use info level 1 for older servers that don't do 260
+	 */
+	if (server->opt.protocol < SMB_PROTOCOL_NT1)
+		info_level = 1;
+
 	smb_lock_server(server);
 
-      retry:
+retry:
 	/*
 	 * Encode the initial path
 	 */
 	mask = param + 12;
-	mask_len = smb_encode_path(server, mask, dir, &star) - mask;
+	mask_len = smb_encode_path(server, mask, dir, &star);
+	if (mask_len < 0) {
+		entries = mask_len;
+		goto unlock_return;
+	}
 	first = 1;
 
 	VERBOSE("starting fpos=%d, mask=%s\n", fpos, mask);
@@ -1386,15 +1551,10 @@
 			command = TRANSACT2_FINDFIRST;
 			WSET(param, 0, aSYSTEM | aHIDDEN | aDIR);
 			WSET(param, 2, max_matches);	/* max count */
-			WSET(param, 4, 
-			     SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); 
+			WSET(param, 4, SMB_CLOSE_IF_END); 
 			WSET(param, 6, info_level);
 			DSET(param, 8, 0);
 		} else {
-			/* we don't need the mask after the first bit */
-			mask_len = 0;
-			mask[0] = 0;
-
 			command = TRANSACT2_FINDNEXT;
 
 			VERBOSE("handle=0x%X, mask=%s\n",
@@ -1404,8 +1564,7 @@
 			WSET(param, 2, max_matches);	/* max count */
 			WSET(param, 4, info_level);
 			DSET(param, 6, 0);       	/* ff_resume_key */
-			WSET(param, 10,
-			     SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); 
+			WSET(param, 10, SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); 
 		}
 
 		result = smb_trans2_request(server, command,
@@ -1444,14 +1603,42 @@
 			ff_dir_handle = WVAL(resp_param, 0);
 			ff_searchcount = WVAL(resp_param, 2);
 			ff_eos = WVAL(resp_param, 4);
+			ff_lastname = WVAL(resp_param, 8);
 		} else {
 			ff_searchcount = WVAL(resp_param, 0);
 			ff_eos = WVAL(resp_param, 2);
+			ff_lastname = WVAL(resp_param, 6);
 		}
 
 		if (ff_searchcount == 0)
 			break;
 
+		/* we might need the lastname for continuations */
+		mask_len = 0;
+		if (ff_lastname > 0) {
+			lastname = resp_data + ff_lastname;
+			switch (info_level) {
+			case 260:
+				if (ff_lastname < resp_data_len)
+					mask_len = resp_data_len - ff_lastname;
+				break;
+			case 1:
+				/* Win NT 4.0 doesn't set the length byte */
+				lastname++;
+				if (ff_lastname + 2 < resp_data_len)
+					mask_len = strlen(lastname);
+				break;
+			}
+			/*
+			 * Update the mask string for the next message.
+			 */
+			if (mask_len > 255)
+				mask_len = 255;
+			if (mask_len)
+				strncpy(mask, lastname, mask_len);
+		}
+		mask[mask_len] = 0;
+
 		/* Now we are ready to parse smb directory entries. */
 
 		/* point to the data bytes */
@@ -1470,7 +1657,7 @@
 				goto unlock_return;
 			}
 
-			p = smb_decode_long_dirent(server, p, entry);
+			p = smb_decode_long_dirent(server, p, entry,info_level);
 
 			/* ignore . and .. from the server */
 			if (entries_seen == 2 && entry->name[0] == '.') {
@@ -1517,10 +1704,13 @@
 	int result;
 	char *p;
 
-      retry:
+retry:
 	p = smb_setup_header(server, SMBgetatr, 0, 0);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dir, NULL);
+	result = smb_encode_path(server, p, dir, NULL);
+	if (result < 0)
+		goto out;
+	p += result;
 	smb_setup_bcc(server, p);
 
 	if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) {
@@ -1571,31 +1761,32 @@
 	int resp_param_len = 0;
 	int result;
 
-      retry:
+retry:
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	p = smb_encode_path(server, param + 6, dir, NULL);
+	p = param + 6;
+	result = smb_encode_path(server, p, dir, NULL);
+	if (result < 0)
+		goto out;
+	p += result;
 
 	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
 				    0, NULL, p - param, param,
 				    &resp_data_len, &resp_data,
 				    &resp_param_len, &resp_param);
-	if (result < 0)
-	{
+	if (result < 0) {
 		if (smb_retry(server))
 			goto retry;
 		goto out;
 	}
-	if (server->rcls != 0)
-	{
+	if (server->rcls != 0) {
 		VERBOSE("for %s: result=%d, rcls=%d, err=%d\n",
 			&param[6], result, server->rcls, server->err);
 		result = -smb_errno(server);
 		goto out;
 	}
 	result = -ENOENT;
-	if (resp_data_len < 22)
-	{
+	if (resp_data_len < 22) {
 		PARANOIA("not enough data for %s, len=%d\n",
 			 &param[6], resp_data_len);
 		goto out;
@@ -1605,7 +1796,7 @@
 	 * Kludge alert: Win 95 swaps the date and time field,
 	 * contrary to the CIFS docs and Win NT practice.
 	 */
-	if (server->mnt->version & SMB_FIX_WIN95) {
+	if (server->mnt->flags & SMB_MOUNT_WIN95) {
 		off_date = 2;
 		off_time = 0;
 	}
@@ -1649,7 +1840,7 @@
 	 * Select whether to use core or trans2 getattr.
 	 * Win 95 appears to break with the trans2 getattr.
 	 */
-	if (server->mnt->version & SMB_FIX_WIN95) {
+	if (server->mnt->flags & SMB_MOUNT_WIN95) {
 		result = smb_proc_getattr_core(server, dir, fattr);
 	} else {
 		result = smb_proc_getattr_trans2(server, dir, fattr);
@@ -1702,7 +1893,10 @@
 	WSET(server->packet, smb_vwv6, 0);
 	WSET(server->packet, smb_vwv7, 0);
 	*p++ = 4;
-	p = smb_encode_path(server, p, dentry, NULL);
+	result = smb_encode_path(server, p, dentry, NULL);
+	if (result < 0)
+		goto out;
+	p += result;
 	*p++ = 4;
 	*p++ = 0;
 	smb_setup_bcc(server, p);
@@ -1803,7 +1997,11 @@
       retry:
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	p = smb_encode_path(server, param + 6, dir, NULL);
+	p = param + 6;
+	result = smb_encode_path(server, p, dir, NULL);
+	if (result < 0)
+		goto out;
+	p += result;
 
 	WSET(data, 0, 0); /* creation time */
 	WSET(data, 2, 0);
@@ -1867,7 +2065,7 @@
 
 	smb_lock_server(server);
 	/* setting the time on a Win95 server fails (tridge) */
-	if (!(server->mnt->version & SMB_FIX_WIN95)) {
+	if (!(server->mnt->flags & SMB_MOUNT_WIN95)) {
 		if (smb_is_open(inode) &&
 		    inode->u.smbfs_i.access != SMB_O_RDONLY)
 			result = smb_proc_setattr_ext(server, inode, fattr);
@@ -1907,7 +2105,7 @@
 
 	smb_lock_server(server);
 
-      retry:
+retry:
 	smb_setup_header(server, SMBdskattr, 0, 0);
 
 	if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/sock.c linux.18p8/fs/smbfs/sock.c
--- linux.vanilla/fs/smbfs/sock.c	Sat Sep  9 18:42:50 2000
+++ linux.18p8/fs/smbfs/sock.c	Sat Sep  2 23:33:56 2000
@@ -108,23 +108,24 @@
 	unsigned char peek_buf[4];
 	int result;
 	mm_segment_t fs;
+	int count = 100;   /* this is a lot, we should have some data waiting */
+	int found = 0;
 
 	fs = get_fs();
 	set_fs(get_ds());
 
 	lock_kernel();
-	while (1)
-	{
+	while (count-- > 0) {
+		peek_buf[0] = 0;
 		result = -EIO;
-		if (job->sk->dead)
-		{
+		if (job->sk->dead) {
 			PARANOIA("sock dead!\n");
 			break;
 		}
 
 		result = _recvfrom(socket, (void *) peek_buf, 1,
 				   MSG_PEEK | MSG_DONTWAIT);
-		if (result == -EAGAIN)
+		if (result < 0)
 			break;
 		if (peek_buf[0] != 0x85)
 			break;
@@ -135,13 +136,15 @@
 
 		DEBUG1("got SESSION KEEPALIVE\n");
 
-		if (result == -EAGAIN)
+		if (result < 0)
 			break;
+		found = 1;
 	}
 	unlock_kernel();
 	set_fs(fs);
 
-	if (result != -EAGAIN)
+	DEBUG1("found=%d, count=%d, result=%d\n", found, count, result);
+	if (found)
 		found_data(job->sk);
 	kfree(ptr);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/super.c linux.18p8/fs/super.c
--- linux.vanilla/fs/super.c	Fri Apr 21 12:46:45 2000
+++ linux.18p8/fs/super.c	Wed Sep 13 17:56:34 2000
@@ -187,9 +187,9 @@
         return 0;
 }
 
-#ifdef CONFIG_MODULES
 int unregister_filesystem(struct file_system_type * fs)
 {
+#ifdef CONFIG_MODULES
 	struct file_system_type ** tmp;
 
 	tmp = &file_systems;
@@ -201,9 +201,9 @@
 		}
 		tmp = &(*tmp)->next;
 	}
+#endif
 	return -EINVAL;
 }
-#endif
 
 static int fs_index(const char * __name)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/ufs/ialloc.c linux.18p8/fs/ufs/ialloc.c
--- linux.vanilla/fs/ufs/ialloc.c	Fri Apr 21 12:46:45 2000
+++ linux.18p8/fs/ufs/ialloc.c	Tue Sep 12 12:55:12 2000
@@ -275,9 +275,7 @@
 	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) {
+	if (dir->i_mode & S_ISGID) {
 		inode->i_gid = dir->i_gid;
 		if (S_ISDIR(mode))
 			mode |= S_ISGID;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/vfat/namei.c linux.18p8/fs/vfat/namei.c
--- linux.vanilla/fs/vfat/namei.c	Sun Jun 11 21:44:22 2000
+++ linux.18p8/fs/vfat/namei.c	Thu Aug 31 14:33:07 2000
@@ -120,6 +120,7 @@
 	opts->unicode_xlate = opts->posixfs = 0;
 	opts->numtail = 1;
 	opts->utf8 = 0;
+	opts->force_long = 0;
 
 	if (!options) return 1;
 	save = 0;
@@ -142,9 +143,10 @@
 			if (ret) opts->posixfs = val;
 		} else if (!strcmp(this_char,"nonumtail")) {
 			ret = simple_getbool(value, &val);
-			if (ret) {
-				opts->numtail = !val;
-			}
+			if (ret) opts->numtail = !val;
+		} else if (!strcmp(this_char,"forcelong") ||
+			   !strcmp(this_char,"force_long")) {
+			opts->force_long = 1;
 		}
 		if (this_char != options)
 			*(this_char-1) = ',';
@@ -383,7 +385,7 @@
 		len--;
 		if (utf8 && (c & 0x80)) return -EINVAL;
 		if (strchr(replace_chars,c)) return -EINVAL;
-  		if (c >= 'A' && c <= 'Z') return -EINVAL;
+  		if (islower(c)) return -EINVAL;
 		if (c < ' '|| c==':') return -EINVAL;
 		if (c == '.') break;
 		space = c == ' ';
@@ -406,7 +408,7 @@
 				return -EINVAL;
 			if (c < ' ' || c == '.'|| c==':')
 				return -EINVAL;
-			if (c >= 'A' && c <= 'Z') return -EINVAL;
+			if (islower(c)) return -EINVAL;
 			space = c == ' ';
 		}
 		if (space) return -EINVAL;
@@ -428,6 +430,16 @@
 	return 0;
 }
 
+static void vfat_format_name_fast(const char *name,int len,char *res)
+{
+	char *walk = res;
+
+	while (len-- && *name != '.') *walk++ = *name++;
+	while (walk-res < 8) *walk++ = ' ';
+	while (--len >= 0) *walk++ = *++name;
+	while (walk-res < MSDOS_NAME) *walk++ = ' ';
+}
+
 static int vfat_format_name(const char *name,int len,char *res,int utf8)
 {
 	char *walk;
@@ -439,10 +451,10 @@
 		if (walk-res == 8) return -EINVAL;
 		if (utf8 && (c & 0x80)) return -EINVAL;
 		if (strchr(replace_chars,c)) return -EINVAL;
-		if (c >= 'A' && c <= 'Z') return -EINVAL;
+		if (islower(c)) return -EINVAL;
 		if (c < ' '|| c==':') return -EINVAL;
 		space = c == ' ';
-		*walk = c >= 'a' && c <= 'z' ? c-32 : c;
+		*walk = c;
 	}
 	if (space) return -EINVAL;
 	if (len >= 0) {
@@ -455,9 +467,9 @@
 				return -EINVAL;
 			if (c < ' ' || c == '.'|| c==':')
 				return -EINVAL;
-			if (c >= 'A' && c <= 'Z') return -EINVAL;
+			if (islower(c)) return -EINVAL;
 			space = c == ' ';
-			*walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
+			*walk++ = c;
 		}
 		if (space) return -EINVAL;
 		if (len) return -EINVAL;
@@ -505,11 +517,7 @@
 
 			if (*ip == ' ')
 				break;
-			if (*ip >= 'A' && *ip <= 'Z') {
-				*p = *ip + 32;
-			} else {
-				*p = *ip;
-			}
+			*p = toupper(*ip);
 		}
 	}
 
@@ -555,11 +563,7 @@
 			*p++ = '_';
 			baselen++;
 		} else if (!strchr(skip_chars, *ip)) {
-			if (*ip >= 'a' && *ip <= 'z') {
-				*p = *ip - 32;
-			} else {
-				*p = *ip;
-			}
+			*p = toupper(*ip);
 			if (strchr(replace_chars, *p)) *p='_';
 			p++; baselen++;
 		}
@@ -576,11 +580,7 @@
 				*p++ = '_';
 				extlen++;
 			} else if (!strchr(skip_chars, *ip)) {
-				if (*ip >= 'a' && *ip <= 'z') {
-					*p = *ip - 32;
-				} else {
-					*p = *ip;
-				}
+				*p = toupper(*ip);
 				if (strchr(replace_chars, *p)) *p='_';
 				extlen++;
 				p++;
@@ -774,25 +774,30 @@
 {
 	struct msdos_dir_entry *de;
 	char msdos_name[MSDOS_NAME];
-	int res, xlate, utf8;
+	int res, xlate, utf8, force_long;
 	struct nls_table *nls;
 
 	de = (struct msdos_dir_entry *) ds;
 	xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
 	utf8 = MSDOS_SB(dir->i_sb)->options.utf8;
+	force_long = MSDOS_SB(dir->i_sb)->options.force_long;
 	nls = MSDOS_SB(dir->i_sb)->nls_io;
 
 	*slots = 1;
-	res = vfat_valid_longname(name, len, xlate);
-	if (res < 0)
-		return res;
 	if (vfat_valid_shortname(name, len, utf8) >= 0) {
-		vfat_format_name(name, len, de->name, utf8);
-		return 0;
+		if (!force_long) {
+			vfat_format_name_fast(name, len, de->name);
+			return 0;
+		}
+		vfat_format_name_fast(name, len, msdos_name);
+	} else {
+		res = vfat_valid_longname(name, len, xlate);
+		if (res < 0)
+			return res;
+		res = vfat_create_shortname(dir, name, len, msdos_name, utf8);
+		if (res < 0)
+			return res;
 	}
-	res = vfat_create_shortname(dir, name, len, msdos_name, utf8);
-	if (res < 0)
-		return res;
 	return vfat_fill_long_slots(ds, name, len, msdos_name, slots, xlate,
 					utf8, nls);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/page.h linux.18p8/include/asm-alpha/page.h
--- linux.vanilla/include/asm-alpha/page.h	Fri Apr 21 12:46:47 2000
+++ linux.18p8/include/asm-alpha/page.h	Sun Sep  3 00:05:00 2000
@@ -68,6 +68,19 @@
 	} while (count);
 }
 
+extern __inline__ int get_order(unsigned long size)
+{
+        int order;
+
+        size = (size-1) >> (PAGE_SHIFT-1);
+        order = -1;
+        do {
+                size >>= 1;
+                order++;
+        } while (size);
+        return order;
+}
+
 #ifdef STRICT_MM_TYPECHECKS
 /*
  * These are used to make use of C type-checking..
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/semaphore.h linux.18p8/include/asm-alpha/semaphore.h
--- linux.vanilla/include/asm-alpha/semaphore.h	Fri Apr 21 12:46:47 2000
+++ linux.18p8/include/asm-alpha/semaphore.h	Fri Sep  1 21:38:57 2000
@@ -26,6 +26,11 @@
 
 #define sema_init(sem, val)	atomic_set(&((sem)->count), val)
 
+#define init_MUTEX(x)				*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)			*(x)=MUTEX_LOCKED
+#define DECLARE_MUTEX(name)			struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)		struct semaphore name=MUTEX_LOCKED
+
 extern void __down(struct semaphore * sem);
 extern int  __down_interruptible(struct semaphore * sem);
 extern int  __down_trylock(struct semaphore * sem);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/smplock.h linux.18p8/include/asm-alpha/smplock.h
--- linux.vanilla/include/asm-alpha/smplock.h	Fri Apr 21 12:46:47 2000
+++ linux.18p8/include/asm-alpha/smplock.h	Thu Aug 31 15:37:12 2000
@@ -17,8 +17,6 @@
 {
 	if (task->lock_depth >= 0)
 		spin_unlock(&kernel_flag);
-	release_irqlock(cpu);
-	__sti();
 }
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/types.h linux.18p8/include/asm-alpha/types.h
--- linux.vanilla/include/asm-alpha/types.h	Fri Apr 21 12:46:47 2000
+++ linux.18p8/include/asm-alpha/types.h	Sat Sep  2 19:28:07 2000
@@ -73,5 +73,7 @@
 
 #endif
 
+typedef u32 dma_addr_t;
+
 #endif /* __KERNEL__ */
 #endif /* _ALPHA_TYPES_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/page.h linux.18p8/include/asm-arm/page.h
--- linux.vanilla/include/asm-arm/page.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-arm/page.h	Sat Sep  2 19:32:21 2000
@@ -19,4 +19,17 @@
 /* void *__va(unsigned long x) */
 #define __va(x)			((void *)(__phys_to_virt((unsigned long)(x))))
 
+extern __inline__ int get_order(unsigned long size)
+{
+        int order;
+
+        size = (size-1) >> (PAGE_SHIFT-1);
+        order = -1;
+        do {
+                size >>= 1;
+                order++;
+        } while (size);
+        return order;
+}
+
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/semaphore.h linux.18p8/include/asm-arm/semaphore.h
--- linux.vanilla/include/asm-arm/semaphore.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-arm/semaphore.h	Fri Sep  1 21:39:22 2000
@@ -16,6 +16,11 @@
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL })
 #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, NULL })
 
+#define init_MUTEX(x)				*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)			*(x)=MUTEX_LOCKED
+#define DECLARE_MUTEX(name)			struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)		struct semaphore name=MUTEX_LOCKED
+
 asmlinkage void __down_failed (void /* special register calling convention */);
 asmlinkage int  __down_interruptible_failed (void /* special register calling convention */);
 asmlinkage int  __down_failed_trylock(void  /* params in registers */);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/smplock.h linux.18p8/include/asm-arm/smplock.h
--- linux.vanilla/include/asm-arm/smplock.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-arm/smplock.h	Thu Aug 31 15:37:12 2000
@@ -15,8 +15,6 @@
 do { \
 	if (task->lock_depth >= 0) \
 		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
 } while (0)
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/types.h linux.18p8/include/asm-arm/types.h
--- linux.vanilla/include/asm-arm/types.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-arm/types.h	Sat Sep  2 19:28:18 2000
@@ -41,6 +41,8 @@
 
 #define BITS_PER_LONG 32
 
+typedef u32 dma_addr_t;
+
 #endif /* __KERNEL__ */
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-generic/smplock.h linux.18p8/include/asm-generic/smplock.h
--- linux.vanilla/include/asm-generic/smplock.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-generic/smplock.h	Thu Aug 31 15:37:12 2000
@@ -15,8 +15,6 @@
 do { \
 	if (task->lock_depth >= 0) \
 		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
 } while (0)
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/page.h linux.18p8/include/asm-i386/page.h
--- linux.vanilla/include/asm-i386/page.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/asm-i386/page.h	Sun Sep  3 00:04:06 2000
@@ -53,6 +53,25 @@
 #define __pgprot(x)	(x)
 
 #endif
+
+#define BUG() do { \
+        printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+        __asm__ __volatile__(".byte 0x0f,0x0b"); \
+} while (0)
+
+extern __inline__ int get_order(unsigned long size)
+{
+        int order;
+
+        size = (size-1) >> (PAGE_SHIFT-1);
+        order = -1;
+        do {
+                size >>= 1;
+                order++;
+        } while (size);
+        return order;
+}
+
 #endif /* !__ASSEMBLY__ */
 
 /* to align the pointer to the (next) page boundary */
@@ -88,6 +107,7 @@
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
+
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/semaphore.h linux.18p8/include/asm-i386/semaphore.h
--- linux.vanilla/include/asm-i386/semaphore.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/asm-i386/semaphore.h	Fri Sep  1 21:39:40 2000
@@ -41,6 +41,11 @@
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL })
 #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, NULL })
 
+#define init_MUTEX(x)				*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)			*(x)=MUTEX_LOCKED
+#define DECLARE_MUTEX(name)			struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)		struct semaphore name=MUTEX_LOCKED
+
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
 asmlinkage int  __down_failed_trylock(void  /* params in registers */);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/smplock.h linux.18p8/include/asm-i386/smplock.h
--- linux.vanilla/include/asm-i386/smplock.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/asm-i386/smplock.h	Fri Sep 15 14:59:45 2000
@@ -15,8 +15,6 @@
 do { \
 	if (task->lock_depth >= 0) \
 		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
 } while (0)
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/types.h linux.18p8/include/asm-i386/types.h
--- linux.vanilla/include/asm-i386/types.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-i386/types.h	Sat Sep  2 19:27:30 2000
@@ -41,6 +41,8 @@
 
 #define BITS_PER_LONG 32
 
+typedef u32 dma_addr_t;
+
 #endif /* __KERNEL__ */
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/page.h linux.18p8/include/asm-m68k/page.h
--- linux.vanilla/include/asm-m68k/page.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-m68k/page.h	Sat Sep  2 19:32:45 2000
@@ -130,6 +130,19 @@
 }
 #define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
 
+extern __inline__ int get_order(unsigned long size)
+{
+        int order;
+
+        size = (size-1) >> (PAGE_SHIFT-1);
+        order = -1;
+        do {
+                size >>= 1;
+                order++;
+        } while (size);
+        return order;
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* _M68K_PAGE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/semaphore.h linux.18p8/include/asm-m68k/semaphore.h
--- linux.vanilla/include/asm-m68k/semaphore.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-m68k/semaphore.h	Fri Sep  1 21:40:01 2000
@@ -24,6 +24,11 @@
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
 #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
+#define init_MUTEX(x)				*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)			*(x)=MUTEX_LOCKED
+#define DECLARE_MUTEX(name)			struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)		struct semaphore name=MUTEX_LOCKED
+
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
 asmlinkage int  __down_failed_trylock(void  /* params in registers */);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/smplock.h linux.18p8/include/asm-m68k/smplock.h
--- linux.vanilla/include/asm-m68k/smplock.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-m68k/smplock.h	Thu Aug 31 15:37:12 2000
@@ -15,8 +15,6 @@
 do { \
 	if (task->lock_depth >= 0) \
 		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
 } while (0)
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/types.h linux.18p8/include/asm-m68k/types.h
--- linux.vanilla/include/asm-m68k/types.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-m68k/types.h	Sat Sep  2 19:28:44 2000
@@ -49,6 +49,8 @@
 
 #define BITS_PER_LONG 32
 
+typedef u32 dma_addr_t;
+
 #endif /* __KERNEL__ */
 
 #endif /* _M68K_TYPES_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/page.h linux.18p8/include/asm-mips/page.h
--- linux.vanilla/include/asm-mips/page.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-mips/page.h	Sun Sep  3 00:05:30 2000
@@ -25,6 +25,21 @@
 extern void (*clear_page)(unsigned long page);
 extern void (*copy_page)(unsigned long to, unsigned long from);
 
+extern __inline__ int get_order(unsigned long size)
+{
+        int order;
+
+        size = (size-1) >> (PAGE_SHIFT-1);
+        order = -1;
+        do {
+                size >>= 1;
+                order++;
+        } while (size);
+        return order;
+}
+
+#endif /* defined (__KERNEL__) */
+
 #ifdef STRICT_MM_TYPECHECKS
 /*
  * These are used to make use of C type-checking..
@@ -79,6 +94,5 @@
 #define __va(x)		((void *)((unsigned long) (x) + PAGE_OFFSET))
 #define MAP_NR(addr)	(__pa(addr) >> PAGE_SHIFT)
 
-#endif /* defined (__KERNEL__) */
 
 #endif /* __ASM_MIPS_PAGE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/semaphore.h linux.18p8/include/asm-mips/semaphore.h
--- linux.vanilla/include/asm-mips/semaphore.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-mips/semaphore.h	Fri Sep  1 21:40:17 2000
@@ -25,6 +25,11 @@
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
 #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
+#define init_MUTEX(x)				*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)			*(x)=MUTEX_LOCKED
+#define DECLARE_MUTEX(name)			struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)		struct semaphore name=MUTEX_LOCKED
+
 asmlinkage void __down(struct semaphore * sem);
 asmlinkage int  __down_interruptible(struct semaphore * sem);
 asmlinkage int __down_trylock(struct semaphore * sem);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/smplock.h linux.18p8/include/asm-mips/smplock.h
--- linux.vanilla/include/asm-mips/smplock.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-mips/smplock.h	Thu Aug 31 15:37:12 2000
@@ -18,8 +18,6 @@
 do { \
 	if (task->lock_depth >= 0) \
 		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
 } while (0)
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/types.h linux.18p8/include/asm-mips/types.h
--- linux.vanilla/include/asm-mips/types.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-mips/types.h	Sat Sep  2 19:28:52 2000
@@ -69,6 +69,8 @@
 #endif
 #define BITS_PER_LONG _MIPS_SZLONG
 
+typedef u32 dma_addr_t;
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_MIPS_TYPES_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/page.h linux.18p8/include/asm-ppc/page.h
--- linux.vanilla/include/asm-ppc/page.h	Sat Sep  9 18:42:50 2000
+++ linux.18p8/include/asm-ppc/page.h	Sat Sep  2 19:33:24 2000
@@ -81,6 +81,20 @@
 #define MAP_PAGE_RESERVED	(1<<15)
 
 extern unsigned long get_zero_page_fast(void);
+
+extern __inline__ int get_order(unsigned long size)
+{
+        int order;
+
+        size = (size-1) >> (PAGE_SHIFT-1);
+        order = -1;
+        do {
+                size >>= 1;
+                order++;
+        } while (size);
+        return order;
+}
+
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
 #endif /* _PPC_PAGE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/semaphore.h linux.18p8/include/asm-ppc/semaphore.h
--- linux.vanilla/include/asm-ppc/semaphore.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-ppc/semaphore.h	Fri Sep  1 21:40:34 2000
@@ -23,6 +23,11 @@
 #define MUTEX_LOCKED	((struct semaphore) \
 			 { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
+#define init_MUTEX(x)				*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)			*(x)=MUTEX_LOCKED
+#define DECLARE_MUTEX(name)			struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)		struct semaphore name=MUTEX_LOCKED
+
 extern void __down(struct semaphore * sem);
 extern int  __down_interruptible(struct semaphore * sem);
 extern int  __down_trylock(struct semaphore * sem);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/smplock.h linux.18p8/include/asm-ppc/smplock.h
--- linux.vanilla/include/asm-ppc/smplock.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-ppc/smplock.h	Thu Aug 31 15:37:12 2000
@@ -15,8 +15,6 @@
 do { \
 	if (task->lock_depth >= 0) \
 		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
 } while (0)
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/irq.h linux.18p8/include/asm-s390/irq.h
--- linux.vanilla/include/asm-s390/irq.h	Sat Sep  9 18:42:50 2000
+++ linux.18p8/include/asm-s390/irq.h	Sat Sep  2 23:39:30 2000
@@ -799,12 +799,13 @@
  * x86 profiling function, SMP safe. We might want to do this in
  * assembly totally?
  */
-extern char _stext;
+extern char _stext[];
+
 static inline void s390_do_profile (unsigned long addr)
 {
         if (prof_buffer && current->pid) {
                 addr &= 0x7fffffff;
-                addr -= (unsigned long) &_stext;
+                addr -= (unsigned long)&_stext[0];
                 addr >>= prof_shift;
                 /*
                  * Don't ignore out-of-bounds EIP values silently,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/page.h linux.18p8/include/asm-s390/page.h
--- linux.vanilla/include/asm-s390/page.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-s390/page.h	Sun Sep  3 00:06:05 2000
@@ -26,6 +26,19 @@
 #define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)      memcpy((void *)(to), (void *)(from), PAGE_SIZE)
 
+extern __inline__ int get_order(unsigned long size)
+{
+        int order;
+
+        size = (size-1) >> (PAGE_SHIFT-1);
+        order = -1;
+        do {
+                size >>= 1;
+                order++;
+        } while (size);
+        return order;
+}
+
 #ifdef STRICT_MM_TYPECHECKS
 /*
  * These are used to make use of C type-checking..
@@ -90,6 +103,7 @@
 #define __pa(x)                 ((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)                 ((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define MAP_NR(addr)            (__pa(addr) >> PAGE_SHIFT)
+
 
 #endif                                 /* __KERNEL__                       */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/semaphore.h linux.18p8/include/asm-s390/semaphore.h
--- linux.vanilla/include/asm-s390/semaphore.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-s390/semaphore.h	Fri Sep  1 21:41:05 2000
@@ -26,6 +26,11 @@
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL })
 #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, NULL })
 
+#define init_MUTEX(x)				*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)			*(x)=MUTEX_LOCKED
+#define DECLARE_MUTEX(name)			struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)		struct semaphore name=MUTEX_LOCKED
+
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
 asmlinkage int  __down_failed_trylock(void  /* params in registers */);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/smplock.h linux.18p8/include/asm-s390/smplock.h
--- linux.vanilla/include/asm-s390/smplock.h	Fri Apr 21 12:46:49 2000
+++ linux.18p8/include/asm-s390/smplock.h	Thu Aug 31 15:37:12 2000
@@ -18,8 +18,6 @@
 do {                                       \
 	if (task->lock_depth >= 0)         \
 		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu);              \
-	__sti();                           \
 } while (0)
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/types.h linux.18p8/include/asm-s390/types.h
--- linux.vanilla/include/asm-s390/types.h	Sun Jun 11 21:44:23 2000
+++ linux.18p8/include/asm-s390/types.h	Sat Sep  2 19:29:07 2000
@@ -60,5 +60,7 @@
 #define FALSE 0
 #endif
 
+typedef u32 dma_addr_t;
+
 #endif                                 /* __KERNEL__                       */
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/semaphore.h linux.18p8/include/asm-sparc/semaphore.h
--- linux.vanilla/include/asm-sparc/semaphore.h	Fri Apr 21 12:46:50 2000
+++ linux.18p8/include/asm-sparc/semaphore.h	Fri Sep  1 21:41:23 2000
@@ -16,6 +16,11 @@
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
 #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
+#define init_MUTEX(x)				*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)			*(x)=MUTEX_LOCKED
+#define DECLARE_MUTEX(name)			struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)		struct semaphore name=MUTEX_LOCKED
+
 extern void __down(struct semaphore * sem);
 extern int __down_interruptible(struct semaphore * sem);
 extern int __down_trylock(struct semaphore * sem);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/smplock.h linux.18p8/include/asm-sparc/smplock.h
--- linux.vanilla/include/asm-sparc/smplock.h	Fri Apr 21 12:46:50 2000
+++ linux.18p8/include/asm-sparc/smplock.h	Thu Aug 31 15:37:12 2000
@@ -15,8 +15,6 @@
 do { \
 	if (task->lock_depth >= 0) \
 		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
 } while (0)
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/semaphore.h linux.18p8/include/asm-sparc64/semaphore.h
--- linux.vanilla/include/asm-sparc64/semaphore.h	Fri Apr 21 12:46:51 2000
+++ linux.18p8/include/asm-sparc64/semaphore.h	Fri Sep  1 21:41:39 2000
@@ -16,6 +16,11 @@
 #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
 #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
+#define init_MUTEX(x)				*(x)=MUTEX
+#define init_MUTEX_LOCKED(x)			*(x)=MUTEX_LOCKED
+#define DECLARE_MUTEX(name)			struct semaphore name=MUTEX
+#define DECLARE_MUTEX_LOCKED(name)		struct semaphore name=MUTEX_LOCKED
+
 extern void __down(struct semaphore * sem);
 extern int  __down_interruptible(struct semaphore * sem);
 extern int  __down_trylock(struct semaphore * sem);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/smplock.h linux.18p8/include/asm-sparc64/smplock.h
--- linux.vanilla/include/asm-sparc64/smplock.h	Fri Apr 21 12:46:51 2000
+++ linux.18p8/include/asm-sparc64/smplock.h	Thu Aug 31 15:37:12 2000
@@ -16,8 +16,6 @@
 do { \
 	if (task->lock_depth >= 0) \
 		spin_unlock(&kernel_flag); \
-	release_irqlock(cpu); \
-	__sti(); \
 } while (0)
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/system.h linux.18p8/include/asm-sparc64/system.h
--- linux.vanilla/include/asm-sparc64/system.h	Fri Apr 21 12:46:52 2000
+++ linux.18p8/include/asm-sparc64/system.h	Sun Sep 10 14:49:10 2000
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.50.2.1 2000/03/06 22:30:28 davem Exp $ */
+/* $Id: system.h,v 1.50.2.2 2000/09/05 00:10:58 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -252,6 +252,63 @@
 }
 
 extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn));
+
+/* 
+ * Atomic compare and exchange.  Compare OLD with MEM, if identical,
+ * store NEW in MEM.  Return the initial value in MEM.  Success is
+ * indicated by comparing RETURN with OLD.
+ */
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+extern __inline__ unsigned long
+__cmpxchg_u32(volatile int *m, int old, int new)
+{
+	__asm__ __volatile__("cas [%2], %3, %0\n\t"
+			     "membar #StoreStore | #StoreLoad"
+			     : "=&r" (new)
+			     : "0" (new), "r" (m), "r" (old)
+			     : "memory");
+
+	return new;
+}
+
+extern __inline__ unsigned long
+__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
+{
+	__asm__ __volatile__("casx [%2], %3, %0\n\t"
+			     "membar #StoreStore | #StoreLoad"
+			     : "=&r" (new)
+			     : "0" (new), "r" (m), "r" (old)
+			     : "memory");
+
+	return new;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+   if something tries to do an invalid cmpxchg().  */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+	switch (size) {
+		case 4:
+			return __cmpxchg_u32(ptr, old, new);
+		case 8:
+			return __cmpxchg_u64(ptr, old, new);
+	}
+	__cmpxchg_called_with_bad_pointer();
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)						 \
+  ({									 \
+     __typeof__(*(ptr)) _o_ = (o);					 \
+     __typeof__(*(ptr)) _n_ = (n);					 \
+     (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,		 \
+				    (unsigned long)_n_, sizeof(*(ptr))); \
+  })
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/agp_backend.h linux.18p8/include/linux/agp_backend.h
--- linux.vanilla/include/linux/agp_backend.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/agp_backend.h	Fri Sep  1 14:14:15 2000
@@ -0,0 +1,228 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _AGP_BACKEND_H
+#define _AGP_BACKEND_H 1
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define AGPGART_VERSION_MAJOR 0
+#define AGPGART_VERSION_MINOR 99
+
+enum chipset_type {
+	NOT_SUPPORTED,
+	INTEL_GENERIC,
+	INTEL_LX,
+	INTEL_BX,
+	INTEL_GX,
+	INTEL_I810,
+	INTEL_I840,
+	VIA_GENERIC,
+	VIA_VP3,
+	VIA_MVP3,
+	VIA_MVP4,
+	VIA_APOLLO_SUPER,
+	VIA_APOLLO_PRO,
+	SIS_GENERIC,
+	AMD_GENERIC,
+	AMD_IRONGATE,
+	ALI_M1541,
+	ALI_GENERIC
+};
+
+typedef struct _agp_version {
+	u16 major;
+	u16 minor;
+} agp_version;
+
+typedef struct _agp_kern_info {
+	agp_version version;
+	struct pci_dev *device;
+	enum chipset_type chipset;
+	unsigned long mode;
+	off_t aper_base;
+	size_t aper_size;
+	int max_memory;		/* In pages */
+	int current_memory;
+} agp_kern_info;
+
+/* 
+ * The agp_memory structure has information
+ * about the block of agp memory allocated.
+ * A caller may manipulate the next and prev
+ * pointers to link each allocated item into
+ * a list.  These pointers are ignored by the 
+ * backend.  Everything else should never be
+ * written to, but the caller may read any of
+ * the items to detrimine the status of this
+ * block of agp memory.
+ * 
+ */
+
+typedef struct _agp_memory {
+	int key;
+	struct _agp_memory *next;
+	struct _agp_memory *prev;
+	size_t page_count;
+	int num_scratch_pages;
+	unsigned long *memory;
+	off_t pg_start;
+	u32 type;
+	u32 physical;
+	u8 is_bound;
+	u8 is_flushed;
+} agp_memory;
+
+#define AGP_NORMAL_MEMORY 0
+
+extern void agp_free_memory(agp_memory *);
+
+/*
+ * agp_free_memory :
+ * 
+ * This function frees memory associated with
+ * an agp_memory pointer.  It is the only function
+ * that can be called when the backend is not owned
+ * by the caller.  (So it can free memory on client
+ * death.)
+ * 
+ * It takes an agp_memory pointer as an argument.
+ * 
+ */
+
+extern agp_memory *agp_allocate_memory(size_t, u32);
+
+/*
+ * agp_allocate_memory :
+ * 
+ * This function allocates a group of pages of
+ * a certain type.
+ * 
+ * It takes a size_t argument of the number of pages, and
+ * an u32 argument of the type of memory to be allocated.  
+ * Every agp bridge device will allow you to allocate 
+ * AGP_NORMAL_MEMORY which maps to physical ram.  Any other
+ * type is device dependant.
+ * 
+ * It returns NULL whenever memory is unavailable.
+ * 
+ */
+
+extern void agp_copy_info(agp_kern_info *);
+
+/*
+ * agp_copy_info :
+ * 
+ * This function copies information about the
+ * agp bridge device and the state of the agp
+ * backend into an agp_kern_info pointer.
+ * 
+ * It takes an agp_kern_info pointer as an
+ * argument.  The caller should insure that
+ * this pointer is valid.
+ * 
+ */
+
+extern int agp_bind_memory(agp_memory *, off_t);
+
+/*
+ * agp_bind_memory :
+ * 
+ * This function binds an agp_memory structure
+ * into the graphics aperture translation table.
+ * 
+ * It takes an agp_memory pointer and an offset into
+ * the graphics aperture translation table as arguments
+ * 
+ * It returns -EINVAL if the pointer == NULL.
+ * It returns -EBUSY if the area of the table
+ * requested is already in use.
+ * 
+ */
+
+extern int agp_unbind_memory(agp_memory *);
+
+/* 
+ * agp_unbind_memory :
+ * 
+ * This function removes an agp_memory structure
+ * from the graphics aperture translation table.
+ * 
+ * It takes an agp_memory pointer as an argument.
+ * 
+ * It returns -EINVAL if this piece of agp_memory
+ * is not currently bound to the graphics aperture
+ * translation table or if the agp_memory 
+ * pointer == NULL
+ * 
+ */
+
+extern void agp_enable(u32);
+
+/* 
+ * agp_enable :
+ * 
+ * This function initializes the agp point-to-point
+ * connection.
+ * 
+ * It takes an agp mode register as an argument
+ * 
+ */
+
+extern int agp_backend_acquire(void);
+
+/*
+ * agp_backend_acquire :
+ * 
+ * This Function attempts to acquire the agp
+ * backend.
+ * 
+ * returns -EBUSY if agp is in use,
+ * returns 0 if the caller owns the agp backend
+ */
+
+extern void agp_backend_release(void);
+
+/*
+ * agp_backend_release :
+ * 
+ * This Function releases the lock on the agp
+ * backend.
+ * 
+ * The caller must insure that the graphics
+ * aperture translation table is read for use
+ * by another entity.  (Ensure that all memory
+ * it bound is unbound.)
+ * 
+ */
+
+#endif				/* _AGP_BACKEND_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/agpgart.h linux.18p8/include/linux/agpgart.h
--- linux.vanilla/include/linux/agpgart.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/agpgart.h	Fri Sep  1 14:06:07 2000
@@ -0,0 +1,224 @@
+/*
+ * AGPGART module version 0.99
+ * Copyright (C) 1999 Jeff Hartmann
+ * Copyright (C) 1999 Precision Insight, Inc.
+ * Copyright (C) 1999 Xi Graphics, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, 
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _AGP_H
+#define _AGP_H 1
+
+#define AGPIOC_BASE       'A'
+#define AGPIOC_INFO       _IOR (AGPIOC_BASE, 0, agp_info*)
+#define AGPIOC_ACQUIRE    _IO  (AGPIOC_BASE, 1)
+#define AGPIOC_RELEASE    _IO  (AGPIOC_BASE, 2)
+#define AGPIOC_SETUP      _IOW (AGPIOC_BASE, 3, agp_setup*)
+#define AGPIOC_RESERVE    _IOW (AGPIOC_BASE, 4, agp_region*)
+#define AGPIOC_PROTECT    _IOW (AGPIOC_BASE, 5, agp_region*)
+#define AGPIOC_ALLOCATE   _IOWR(AGPIOC_BASE, 6, agp_allocate*)
+#define AGPIOC_DEALLOCATE _IOW (AGPIOC_BASE, 7, int)
+#define AGPIOC_BIND       _IOW (AGPIOC_BASE, 8, agp_bind*)
+#define AGPIOC_UNBIND     _IOW (AGPIOC_BASE, 9, agp_unbind*)
+
+#define AGP_DEVICE      "/dev/agpgart"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef __KERNEL__
+#include <linux/types.h>
+#include <asm/types.h>
+
+typedef struct _agp_version {
+	__u16 major;
+	__u16 minor;
+} agp_version;
+
+typedef struct _agp_info {
+	agp_version version;	/* version of the driver        */
+	__u32 bridge_id;	/* bridge vendor/device         */
+	__u32 agp_mode;		/* mode info of bridge          */
+	off_t aper_base;	/* base of aperture             */
+	size_t aper_size;	/* size of aperture             */
+	size_t pg_total;	/* max pages (swap + system)    */
+	size_t pg_system;	/* max pages (system)           */
+	size_t pg_used;		/* current pages used           */
+} agp_info;
+
+typedef struct _agp_setup {
+	__u32 agp_mode;		/* mode info of bridge          */
+} agp_setup;
+
+/*
+ * The "prot" down below needs still a "sleep" flag somehow ...
+ */
+typedef struct _agp_segment {
+	off_t pg_start;		/* starting page to populate    */
+	size_t pg_count;	/* number of pages              */
+	int prot;		/* prot flags for mmap          */
+} agp_segment;
+
+typedef struct _agp_region {
+	pid_t pid;		/* pid of process               */
+	size_t seg_count;	/* number of segments           */
+	struct _agp_segment *seg_list;
+} agp_region;
+
+typedef struct _agp_allocate {
+	int key;		/* tag of allocation            */
+	size_t pg_count;	/* number of pages              */
+	__u32 type;		/* 0 == normal, other devspec   */
+   	__u32 physical;         /* device specific (some devices  
+				 * need a phys address of the     
+				 * actual page behind the gatt    
+				 * table)                        */
+} agp_allocate;
+
+typedef struct _agp_bind {
+	int key;		/* tag of allocation            */
+	off_t pg_start;		/* starting page to populate    */
+} agp_bind;
+
+typedef struct _agp_unbind {
+	int key;		/* tag of allocation            */
+	__u32 priority;		/* priority for paging out      */
+} agp_unbind;
+
+#else				/* __KERNEL__ */
+
+#define AGPGART_MINOR 175
+
+#define AGP_UNLOCK()      	up(&(agp_fe.agp_mutex));
+#define AGP_LOCK()    		down(&(agp_fe.agp_mutex));
+#define AGP_LOCK_INIT() 	sema_init(&(agp_fe.agp_mutex), 1)
+
+#ifndef _AGP_BACKEND_H
+typedef struct _agp_version {
+	u16 major;
+	u16 minor;
+} agp_version;
+
+#endif
+
+typedef struct _agp_info {
+	agp_version version;	/* version of the driver        */
+	u32 bridge_id;		/* bridge vendor/device         */
+	u32 agp_mode;		/* mode info of bridge          */
+	off_t aper_base;	/* base of aperture             */
+	size_t aper_size;	/* size of aperture             */
+	size_t pg_total;	/* max pages (swap + system)    */
+	size_t pg_system;	/* max pages (system)           */
+	size_t pg_used;		/* current pages used           */
+} agp_info;
+
+typedef struct _agp_setup {
+	u32 agp_mode;		/* mode info of bridge          */
+} agp_setup;
+
+/*
+ * The "prot" down below needs still a "sleep" flag somehow ...
+ */
+typedef struct _agp_segment {
+	off_t pg_start;		/* starting page to populate    */
+	size_t pg_count;	/* number of pages              */
+	int prot;		/* prot flags for mmap          */
+} agp_segment;
+
+typedef struct _agp_segment_priv {
+	off_t pg_start;
+	size_t pg_count;
+	pgprot_t prot;
+} agp_segment_priv;
+
+typedef struct _agp_region {
+	pid_t pid;		/* pid of process               */
+	size_t seg_count;	/* number of segments           */
+	struct _agp_segment *seg_list;
+} agp_region;
+
+typedef struct _agp_allocate {
+	int key;		/* tag of allocation            */
+	size_t pg_count;	/* number of pages              */
+	u32 type;		/* 0 == normal, other devspec   */
+	u32 physical;           /* device specific (some devices  
+				 * need a phys address of the     
+				 * actual page behind the gatt    
+				 * table)                        */
+} agp_allocate;
+
+typedef struct _agp_bind {
+	int key;		/* tag of allocation            */
+	off_t pg_start;		/* starting page to populate    */
+} agp_bind;
+
+typedef struct _agp_unbind {
+	int key;		/* tag of allocation            */
+	u32 priority;		/* priority for paging out      */
+} agp_unbind;
+
+typedef struct _agp_client {
+	struct _agp_client *next;
+	struct _agp_client *prev;
+	pid_t pid;
+	int num_segments;
+	agp_segment_priv **segments;
+} agp_client;
+
+typedef struct _agp_controller {
+	struct _agp_controller *next;
+	struct _agp_controller *prev;
+	pid_t pid;
+	int num_clients;
+	agp_memory *pool;
+	agp_client *clients;
+} agp_controller;
+
+#define AGP_FF_ALLOW_CLIENT		0
+#define AGP_FF_ALLOW_CONTROLLER 	1
+#define AGP_FF_IS_CLIENT		2
+#define AGP_FF_IS_CONTROLLER		3
+#define AGP_FF_IS_VALID 		4
+
+typedef struct _agp_file_private {
+	struct _agp_file_private *next;
+	struct _agp_file_private *prev;
+	pid_t my_pid;
+	u32 access_flags;
+} agp_file_private;
+
+struct agp_front_data {
+	struct semaphore agp_mutex;
+	agp_controller *current_controller;
+	agp_controller *controllers;
+	agp_file_private *file_priv_list;
+	u8 used_by_controller;
+	u8 backend_acquired;
+};
+
+#endif				/* __KERNEL__ */
+
+#endif				/* _AGP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/apm_bios.h linux.18p8/include/linux/apm_bios.h
--- linux.vanilla/include/linux/apm_bios.h	Fri Apr 21 12:46:59 2000
+++ linux.18p8/include/linux/apm_bios.h	Mon Sep 11 17:05:42 2000
@@ -95,9 +95,6 @@
  */
 extern struct apm_bios_info	apm_bios_info;
 
-extern void		apm_init(void);
-extern void		apm_setup(char *, int *);
-
 extern int		apm_register_callback(int (*callback)(apm_event_t));
 extern void		apm_unregister_callback(int (*callback)(apm_event_t));
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/cciss_ioctl.h linux.18p8/include/linux/cciss_ioctl.h
--- linux.vanilla/include/linux/cciss_ioctl.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/cciss_ioctl.h	Sun Sep  3 00:10:45 2000
@@ -0,0 +1,186 @@
+#ifndef CCISS_IOCTLH
+#define CCISS_IOCTLH
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define CCISS_IOC_MAGIC 'B'
+
+
+typedef struct _cciss_pci_info_struct
+{
+	unsigned char 	bus;
+	unsigned char 	dev_fn;
+	__u32 		board_id;
+} cciss_pci_info_struct; 
+
+typedef struct _cciss_coalint_struct
+{
+	__u32  delay;
+	__u32  count;
+} cciss_coalint_struct;
+
+typedef char NodeName_type[16];
+
+typedef __u32 Heartbeat_type;
+
+#define CISS_PARSCSIU2 	0x0001
+#define CISS_PARCSCIU3 	0x0002
+#define CISS_FIBRE1G	0x0100
+#define CISS_FIBRE2G	0x0200
+typedef __u32 BusTypes_type;
+
+typedef char FirmwareVer_type[4];
+typedef __u32 DriverVer_type;
+
+
+#ifndef CCISS_CMD_H
+// This defines are duplicated in cciss_cmd.h in the driver directory 
+
+//general boundary defintions
+#define SENSEINFOBYTES          32//note that this value may vary between host implementations
+
+//Command Status value
+#define CMD_SUCCESS             0x0000
+#define CMD_TARGET_STATUS       0x0001
+#define CMD_DATA_UNDERRUN       0x0002
+#define CMD_DATA_OVERRUN        0x0003
+#define CMD_INVALID             0x0004
+#define CMD_PROTOCOL_ERR        0x0005
+#define CMD_HARDWARE_ERR        0x0006
+#define CMD_CONNECTION_LOST     0x0007
+#define CMD_ABORTED             0x0008
+#define CMD_ABORT_FAILED        0x0009
+#define CMD_UNSOLICITED_ABORT   0x000A
+#define CMD_TIMEOUT             0x000B
+#define CMD_UNABORTABLE		0x000C
+
+//transfer direction
+#define XFER_NONE               0x00
+#define XFER_WRITE              0x01
+#define XFER_READ               0x02
+#define XFER_RSVD               0x03
+
+//task attribute
+#define ATTR_UNTAGGED           0x00
+#define ATTR_SIMPLE             0x04
+#define ATTR_HEADOFQUEUE        0x05
+#define ATTR_ORDERED            0x06
+#define ATTR_ACA                0x07
+
+//cdb type
+#define TYPE_CMD				0x00
+#define TYPE_MSG				0x01
+
+// Type defs used in the following structs
+#define BYTE __u8
+#define WORD __u16
+#define HWORD __u16
+#define DWORD __u32
+
+#define CISS_MAX_LUN	16	
+
+#pragma pack(1)
+
+//Command List Structure
+typedef union _SCSI3Addr_struct {
+   struct {
+    BYTE Bus:6;
+    BYTE Mode:2;        // b00
+    BYTE Dev;
+  } PeripDev;
+   struct {
+    BYTE DevMSB:6;
+    BYTE Mode:2;        // b01
+    BYTE DevLSB;
+  } LogDev;
+   struct {
+    BYTE Targ:6;
+    BYTE Mode:2;        // b10
+    BYTE Dev:5;
+    BYTE Bus:3;
+  } LogUnit;
+} SCSI3Addr_struct;
+
+typedef struct _PhysDevAddr_struct {
+  DWORD             TargetId:24;
+  DWORD             Bus:6;
+  DWORD             Mode:2;
+  SCSI3Addr_struct  Target[2]; //2 level target device addr
+} PhysDevAddr_struct;
+  
+typedef struct _LogDevAddr_struct {
+  DWORD            VolId:30;
+  DWORD            Mode:2;
+  BYTE             reserved[4];
+} LogDevAddr_struct;
+
+typedef union _LUNAddr_struct {
+  BYTE               LunAddrBytes[8];
+  SCSI3Addr_struct   SCSI3Lun[4];
+  PhysDevAddr_struct PhysDev;
+  LogDevAddr_struct  LogDev;
+} LUNAddr_struct;
+
+typedef struct _RequestBlock_struct {
+  BYTE   CDBLen;
+  struct {
+    BYTE Type:3;
+    BYTE Attribute:3;
+    BYTE Direction:2;
+  } Type;
+  HWORD  Timeout;
+  BYTE   CDB[16];
+} RequestBlock_struct;
+
+typedef union _MoreErrInfo_struct{
+  struct {
+    BYTE  Reserved[3];
+    BYTE  Type;
+    DWORD ErrorInfo;
+  }Common_Info;
+  struct{
+    BYTE  Reserved[2];
+    BYTE  offense_size;//size of offending entry
+    BYTE  offense_num; //byte # of offense 0-base
+    DWORD offense_value;
+  }Invalid_Cmd;
+}MoreErrInfo_struct;
+typedef struct _ErrorInfo_struct {
+  BYTE               ScsiStatus;
+  BYTE               SenseLen;
+  HWORD              CommandStatus;
+  DWORD              ResidualCnt;
+  MoreErrInfo_struct MoreErrInfo;
+  BYTE               SenseInfo[SENSEINFOBYTES];
+} ErrorInfo_struct;
+
+#pragma pack()
+#endif /* CCISS_CMD_H */ 
+
+typedef struct _IOCTL_Command_struct {
+  LUNAddr_struct	   LUN_info;
+  RequestBlock_struct      Request;
+  ErrorInfo_struct  	   error_info; 
+  WORD			   buf_size;  /* size in bytes of the buf */
+  BYTE			   *buf;
+} IOCTL_Command_struct;
+
+
+#define CCISS_GETPCIINFO _IOR(CCISS_IOC_MAGIC, 1, cciss_pci_info_struct)
+
+#define CCISS_GETINTINFO _IOR(CCISS_IOC_MAGIC, 2, cciss_coalint_struct)
+#define CCISS_SETINTINFO _IOW(CCISS_IOC_MAGIC, 3, cciss_coalint_struct)
+
+#define CCISS_GETNODENAME _IOR(CCISS_IOC_MAGIC, 4, NodeName_type)
+#define CCISS_SETNODENAME _IOW(CCISS_IOC_MAGIC, 5, NodeName_type)
+
+#define CCISS_GETHEARTBEAT _IOR(CCISS_IOC_MAGIC, 6, Heartbeat_type)
+#define CCISS_GETBUSTYPES  _IOR(CCISS_IOC_MAGIC, 7, BusTypes_type)
+#define CCISS_GETFIRMVER   _IOR(CCISS_IOC_MAGIC, 8, FirmwareVer_type)
+#define CCISS_GETDRIVVER   _IOR(CCISS_IOC_MAGIC, 9, DriverVer_type)
+#define CCISS_REVALIDVOLS  _IO(CCISS_IOC_MAGIC, 10)
+#define CCISS_PASSTHRU	   _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct)
+
+
+#endif  
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/compatmac.h linux.18p8/include/linux/compatmac.h
--- linux.vanilla/include/linux/compatmac.h	Wed May  3 22:26:00 2000
+++ linux.18p8/include/linux/compatmac.h	Fri Sep 15 15:06:25 2000
@@ -149,15 +149,4 @@
 
 #endif
 
-#ifndef TWO_THREE
-/* These are new in 2.3. The source now uses 2.3 syntax, and here is 
-   the compatibility define... */
-#define wait_queue_head_t     struct wait_queue *
-#define DECLARE_MUTEX(name)   struct semaphore name = MUTEX
-#define DECLARE_WAITQUEUE(wait, current) \
-                              struct wait_queue wait = { current, NULL }
-
-#endif
-
-
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/cpia.h linux.18p8/include/linux/cpia.h
--- linux.vanilla/include/linux/cpia.h	Fri Apr 21 23:14:09 2000
+++ linux.18p8/include/linux/cpia.h	Thu Jan  1 01:00:00 1970
@@ -1,220 +0,0 @@
-#ifndef cpia_h
-#define cpia_h
-
-/*
- * CPiA Parallel Port Video4Linux driver
- *
- * Supports CPiA based parallel port Video Camera's.
- *
- * (C) Copyright 1999 Bas Huisman,
- *                    Peter Pregler,
- *                    Scott J. Bertin,
- *                    VLSI Vision Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#define CPIA_MAJ_VER	0
-#define CPIA_MIN_VER    5
-#define CPIA_PATCH_VER	0
-
-#define CPIA_PP_MAJ_VER       0
-#define CPIA_PP_MIN_VER       5
-#define CPIA_PP_PATCH_VER     0
-
-#define CPIA_MAX_FRAME_SIZE_UNALIGNED	(352 * 288 * 4)   /* CIF at RGB32 */
-#define CPIA_MAX_FRAME_SIZE	((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
-
-#ifdef __KERNEL__
-
-#include <asm/uaccess.h>
-
-struct cpia_camera_ops
-{
-	/* open sets privdata to point to structure for this camera.
-         * Returns negative value on error, otherwise 0.
-	 */
-	int (*open)(int camnr, void **privdata);
-	
-	/* Registers callback function cb to be called with cbdata
-	 * when an image is ready.  If cb is NULL, only single image grabs
-	 * should be used.  cb should immediately call streamRead to read
-	 * the data or data may be lost. Returns negative value on error,
-	 * otherwise 0.
-	 */
-	int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
-	                        void *cbdata);
-	
-	/* transferCmd sends commands to the camera.  command MUST point to
-	 * an  8 byte buffer in kernel space. data can be NULL if no extra
-	 * data is needed.  The size of the data is given by the last 2
-	 * bytes of comand.  data must also point to memory in kernel space.
-	 * Returns negative value on error, otherwise 0.
-	 */
-	int (*transferCmd)(void *privdata, u8 *command, u8 *data);
-
-	/* streamStart initiates stream capture mode.
-	 * Returns negative value on error, otherwise 0.
-	 */
-	int (*streamStart)(void *privdata);
-	
-	/* streamStop terminates stream capture mode.
-	 * Returns negative value on error, otherwise 0.
-	 */
-	int (*streamStop)(void *privdata);
-        
-	/* streamRead reads a frame from the camera.  buffer points to a
-         * buffer large enough to hold a complete frame in kernel space.
-         * noblock indicates if this should be a non blocking read.
-	 * Returns the number of bytes read, or negative value on error.
-         */
-	int (*streamRead)(void *privdata, u8 *buffer, int noblock);
-	
-	/* close disables the device until open() is called again.
-	 * Returns negative value on error, otherwise 0.
-	 */
-	int (*close)(void *privdata);
-};
-
-/* cpia_register_camera is called by low level driver for each camera.
- * A unique camera number is returned, or a negative value on error */
-int cpia_register_camera(struct cpia_camera_ops *ops);
-
-/* cpia_unregister_camera is called by low level driver when a camera
- * is removed.  This must not fail. */
-void cpia_unregister_camera(int camnr);
-
-#define CPIA_MAXCAMS		4
-
-/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI +
- * one byte 16bit DMA alignment
- */
-#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5)
-
-/* constant value's */
-#define MAGIC_0		0x19
-#define MAGIC_1		0x68
-#define DATA_IN		0xC0
-#define DATA_OUT	0x40
-#define VIDEOSIZE_QCIF	0	/* 176x144 */
-#define VIDEOSIZE_CIF	1	/* 352x288 */
-#define VIDEOSIZE_SIF	2	/* 320x240 */
-#define VIDEOSIZE_QSIF	3	/* 160x120 */
-#define VIDEOSIZE_48_48		4 /* where no one has gone before, iconsize! */
-#define VIDEOSIZE_64_48		5
-#define VIDEOSIZE_128_96	6
-#define VIDEOSIZE_160_120	VIDEOSIZE_QSIF
-#define VIDEOSIZE_176_144	VIDEOSIZE_QCIF
-#define VIDEOSIZE_192_144	7
-#define VIDEOSIZE_224_168	8
-#define VIDEOSIZE_256_192	9
-#define VIDEOSIZE_288_216	10
-#define VIDEOSIZE_320_240	VIDEOSIZE_SIF
-#define VIDEOSIZE_352_288	VIDEOSIZE_CIF
-#define SUBSAMPLE_420	0
-#define SUBSAMPLE_422	1
-#define YUVORDER_YUYV	0
-#define YUVORDER_UYVY	1
-#define NOT_COMPRESSED	0
-#define COMPRESSED	1
-#define NO_DECIMATION	0
-#define DECIMATION_ENAB	1
-#define EOI		0xff	/* End Of Image */
-#define EOL		0xfd	/* End Of Line */
-
-/* Image grab modes */
-#define CPIA_GRAB_SINGLE	0
-#define CPIA_GRAB_CONTINUOUS	1
-
-/* Compression parameters */
-#define CPIA_COMPRESSION_NONE	0
-#define CPIA_COMPRESSION_AUTO	1
-#define CPIA_COMPRESSION_MANUAL	2
-#define CPIA_COMPRESSION_TARGET_QUALITY         0
-#define CPIA_COMPRESSION_TARGET_FRAMERATE       1
-
-/* Return offsets for GetCameraState */
-#define SYSTEMSTATE	0
-#define GRABSTATE	1
-#define STREAMSTATE	2
-#define FATALERROR	3
-#define CMDERROR	4
-#define DEBUGFLAGS	5
-#define VPSTATUS	6
-#define ERRORCODE	7
-
-/* SystemState */
-#define UNINITIALISED_STATE	0
-#define PASS_THROUGH_STATE	1
-#define LO_POWER_STATE		2
-#define HI_POWER_STATE		3
-#define WARM_BOOT_STATE		4
-
-/* GrabState */
-#define GRAB_IDLE		0
-#define GRAB_ACTIVE		1
-#define GRAB_DONE		2
-
-/* StreamState */
-#define STREAM_NOT_READY	0
-#define STREAM_READY		1
-#define STREAM_OPEN		2
-#define STREAM_PAUSED		3
-#define STREAM_FINISHED		4
-
-/* Fatal Error, CmdError, and DebugFlags */
-#define CPIA_FLAG	  1
-#define SYSTEM_FLAG	  2
-#define INT_CTRL_FLAG	  4
-#define PROCESS_FLAG	  8
-#define COM_FLAG	 16
-#define VP_CTRL_FLAG	 32
-#define CAPTURE_FLAG	 64
-#define DEBUG_FLAG	128
-
-/* VPStatus */
-#define VP_STATE_OK			0x00
-
-#define VP_STATE_FAILED_VIDEOINIT	0x01
-#define VP_STATE_FAILED_AECACBINIT	0x02
-#define VP_STATE_AEC_MAX		0x04
-#define VP_STATE_ACB_BMAX		0x08
-
-#define VP_STATE_ACB_RMIN		0x10
-#define VP_STATE_ACB_GMIN		0x20
-#define VP_STATE_ACB_RMAX		0x40
-#define VP_STATE_ACB_GMAX		0x80
-
-/* ErrorCode */
-#define ERROR_FLICKER_BELOW_MIN_EXP     0x01 /*flicker exposure got below minimum exposure */
-
-#define ALOG(lineno,fmt,args...) printk(fmt,lineno,##args)
-#define LOG(fmt,args...) ALOG((__LINE__),KERN_INFO __FILE__":"__FUNCTION__"(%d):"fmt,##args)
-
-#ifdef _CPIA_DEBUG_
-#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, lineno, ##args)
-#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):"__FUNCTION__"(%d):"fmt,##args)
-#else
-#define DBG(fmn,args...) {}
-#endif
-
-#define DEB_BYTE(p)\
-  DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
-      (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
-        (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
-
-#endif /* __KERNEL__ */
-
-#endif /* cpia_h */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/devfs_fs_kernel.h linux.18p8/include/linux/devfs_fs_kernel.h
--- linux.vanilla/include/linux/devfs_fs_kernel.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/devfs_fs_kernel.h	Fri Sep  1 21:43:38 2000
@@ -0,0 +1,9 @@
+typedef int* devfs_handle_t;
+
+#define devfs_register(a,b,c,d,e,f,g,h,i,j,k)	NULL
+#define devfs_unregister(a)
+#define devfs_mk_dir(a,b,c,d)			NULL
+#define devfs_register_chrdev(a,b,c)		register_chrdev(a,b,c)
+#define devfs_unregister_chrdev(a,b)		unregister_chrdev(a,b)
+#define tty_register_devfs(driver,flags,minor)
+#define tty_unregister_devfs(driver,minor)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/ext2_fs.h linux.18p8/include/linux/ext2_fs.h
--- linux.vanilla/include/linux/ext2_fs.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/linux/ext2_fs.h	Mon Sep 11 17:37:18 2000
@@ -546,6 +546,7 @@
 /* file.c */
 extern int ext2_read (struct inode *, struct file *, char *, int);
 extern int ext2_write (struct inode *, struct file *, char *, int);
+extern void ext2_remove_suid (struct inode *); 
 
 /* fsync.c */
 extern int ext2_sync_file (struct file *, struct dentry *);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/ext2_fs_sb.h linux.18p8/include/linux/ext2_fs_sb.h
--- linux.vanilla/include/linux/ext2_fs_sb.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/linux/ext2_fs_sb.h	Tue Sep 12 12:55:12 2000
@@ -16,7 +16,6 @@
 #ifndef _LINUX_EXT2_FS_SB
 #define _LINUX_EXT2_FS_SB
 
-#include <linux/ext2_fs.h>
 
 /*
  * The following is not needed anymore since the descriptors buffer
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/fs.h linux.18p8/include/linux/fs.h
--- linux.vanilla/include/linux/fs.h	Sat Sep  9 18:42:50 2000
+++ linux.18p8/include/linux/fs.h	Wed Sep 13 16:48:19 2000
@@ -279,6 +279,7 @@
 #include <linux/hfs_fs_i.h>
 #include <linux/adfs_fs_i.h>
 #include <linux/qnx4_fs_i.h>
+#include <linux/usbdev_fs_i.h>
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
@@ -360,6 +361,7 @@
 	struct wait_queue	*i_wait;
 	struct file_lock	*i_flock;
 	struct vm_area_struct	*i_mmap;
+	struct vm_area_struct	*i_mmap_shared;
 	struct page		*i_pages;
 	struct dquot		*i_dquot[MAXQUOTAS];
 
@@ -392,6 +394,7 @@
 		struct hfs_inode_info		hfs_i;
 		struct adfs_inode_info		adfs_i;
 		struct qnx4_inode_info		qnx4_i;
+		struct usbdev_inode_info	usbdev_i;
 		struct socket			socket_i;
 		void				*generic_ip;
 	} u;
@@ -514,6 +517,7 @@
 #include <linux/hfs_fs_sb.h>
 #include <linux/adfs_fs_sb.h>
 #include <linux/qnx4_fs_sb.h>
+#include <linux/usbdev_fs_sb.h>
 
 extern struct list_head super_blocks;
 
@@ -557,6 +561,7 @@
 		struct hfs_sb_info	hfs_sb;
 		struct adfs_sb_info	adfs_sb;
 		struct qnx4_sb_info	qnx4_sb;	   
+		struct usbdev_sb_info	usbdevfs_sb;
 		void			*generic_sbp;
 	} u;
 	/*
@@ -653,6 +658,13 @@
 	struct super_block *(*read_super) (struct super_block *, void *, int);
 	struct file_system_type * next;
 };
+
+#define DECLARE_FSTYPE(var,type,read,flags) \
+struct file_system_type var = { \
+        name:           type, \
+        read_super:     read, \
+        fs_flags:       flags, \
+}
 
 extern int register_filesystem(struct file_system_type *);
 extern int unregister_filesystem(struct file_system_type *);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/i2o.h linux.18p8/include/linux/i2o.h
--- linux.vanilla/include/linux/i2o.h	Sat Sep  9 18:42:50 2000
+++ linux.18p8/include/linux/i2o.h	Fri Sep  1 21:49:20 2000
@@ -638,12 +638,6 @@
 #define I2O_POST_WAIT_OK	0
 #define I2O_POST_WAIT_TIMEOUT	-ETIMEDOUT
 
-#define DECLARE_MUTEX(name) struct semaphore name=MUTEX
-
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAIT_QUEUE_HEAD(wait)\
-        wait_queue_head_t wait
-
 #endif /* __KERNEL__ */
 
 #endif /* _I2O_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/in6.h linux.18p8/include/linux/in6.h
--- linux.vanilla/include/linux/in6.h	Fri Apr 21 23:11:02 2000
+++ linux.18p8/include/linux/in6.h	Fri Sep  8 16:53:11 2000
@@ -34,21 +34,10 @@
 		__u8		u6_addr8[16];
 		__u16		u6_addr16[8];
 		__u32		u6_addr32[4];
-#if (~0UL) > 0xffffffff
-#ifndef __RELAX_IN6_ADDR_ALIGNMENT
-		/* Alas, protocols do not respect 64bit alignmnet.
-		   rsvp/pim/... are broken. However, it is good
-		   idea to force correct alignment always, when
-		   it is possible.
-		 */
-		__u64		u6_addr64[2];
-#endif
-#endif
 	} in6_u;
 #define s6_addr			in6_u.u6_addr8
 #define s6_addr16		in6_u.u6_addr16
 #define s6_addr32		in6_u.u6_addr32
-#define s6_addr64		in6_u.u6_addr64
 };
 
 struct sockaddr_in6 {
@@ -138,7 +127,7 @@
  */
 #define IPV6_TLV_PAD0		0
 #define IPV6_TLV_PADN		1
-#define IPV6_TLV_ROUTERALERT	20
+#define IPV6_TLV_ROUTERALERT	5
 #define IPV6_TLV_JUMBO		194
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/init.h linux.18p8/include/linux/init.h
--- linux.vanilla/include/linux/init.h	Sun Jun 11 21:44:23 2000
+++ linux.18p8/include/linux/init.h	Mon Sep 11 17:28:30 2000
@@ -17,7 +17,7 @@
  *    extern int z; z = x * y;
  * }
  *
- * Depricated: you can surround the whole function declaration 
+ * Deprecated: you can surround the whole function declaration 
  * just before function body into __initfunc() macro, like:
  *
  * __initfunc (static void initme(int x, int y))
@@ -65,4 +65,69 @@
 #define __initlocaldata
 #endif
 
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Used for kernel command line parameter setup
+ */
+struct new_kernel_param {
+	const char *str;
+	int (*setup_func)(char *);
+};
+
+extern struct new_kernel_param __setup_start, __setup_end;
+
+#define __setup(str, fn)								\
+	static char __setup_str_##fn[] __initdata = str;				\
+	static struct new_kernel_param __setup_##fn __initsetup = { __setup_str_##fn, fn }
+
+#define __initsetup	__attribute__ ((unused,__section__ (".setup.init")))
+
+
+/*
+ * Used for initialization calls..
+ */
+typedef int (*initcall_t)(void);
+typedef void (*exitcall_t)(void);
+
+#define __init_call	__attribute__ ((unused,__section__ (".initcall.init")))
+#define __exit_call	__attribute__ ((unused,__section__ (".exitcall.exit")))
+
+extern initcall_t __initcall_start, __initcall_end;
+
+#define __initcall(fn)								\
+	static initcall_t __initcall_##fn __init_call = fn
+#define __exitcall(fn)								\
+	static exitcall_t __exitcall_##fn __exit_call = fn
+
+#ifdef MODULE
+/* Not sure what version aliases were introduced in, but certainly in 2.91.66.  */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)
+/* These macros create a dummy inline: gcc 2.9x does not count alias
+ as usage, hence the `unused function' warning when __init functions
+ are declared static. We use the dummy __*_module_inline functions
+ both to kill the warning and check the type of the init/cleanup
+ function. */
+typedef int (*__init_module_func_t)(void);
+typedef void (*__cleanup_module_func_t)(void);
+#define module_init(x) \
+	int init_module(void) __attribute__((alias(#x))); \
+	extern inline __init_module_func_t __init_module_inline(void) \
+	{ return x; }
+#define module_exit(x) \
+	void cleanup_module(void) __attribute__((alias(#x))); \
+	extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
+	{ return x; }
+#else
+#define module_init(x)	int init_module(void) { return x(); }
+#define module_exit(x)	void cleanup_module(void) { x(); }
+#endif
+
+#else 
+#define module_init(x)	__initcall(x);
+#define module_exit(x)	__exitcall(x);
+#endif
+
+#endif /* __ASSEMBLY __ */
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/input.h linux.18p8/include/linux/input.h
--- linux.vanilla/include/linux/input.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/input.h	Fri Sep 15 15:12:46 2000
@@ -0,0 +1,532 @@
+#ifndef _INPUT_H
+#define _INPUT_H
+
+/*
+ * $Id: input.h,v 1.13 2000/05/29 10:54:53 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#ifdef __KERNEL__
+#include <linux/time.h>
+#else
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#endif
+
+/*
+ * The event structure itself
+ */
+
+struct input_event {
+	struct timeval time;
+	unsigned short type;
+	unsigned short code;
+	unsigned int value;
+};
+
+/*
+ * Protocol version.
+ */
+
+#define EV_VERSION		0x010000
+
+/*
+ * IOCTLs (0x00 - 0x7f)
+ */
+
+#define EVIOCGVERSION		_IOR('E', 0x01, int)                    /* get driver version */
+#define EVIOCGID		_IOR('E', 0x02, short[4])		/* get device ID */
+#define EVIOCGREP		_IOR('E', 0x03, int[2])			/* get repeat settings */
+#define EVIOCSREP		_IOW('E', 0x03, int[2])			/* get repeat settings */
+#define EVIOCGKEYCODE		_IOR('E', 0x04, int[2])			/* get keycode */
+#define EVIOCSKEYCODE		_IOW('E', 0x04, int[2])			/* set keycode */
+#define EVIOCGKEY		_IOR('E', 0x05, int[2])			/* get key value */
+#define EVIOCGNAME(len)		_IOC(_IOC_READ, 'E', 0x06, len)		/* get device name */
+
+#define EVIOCGBIT(ev,len)	_IOC(_IOC_READ, 'E', 0x20 + ev, len)	/* get event bits */
+#define EVIOCGABS(abs)		_IOR('E', 0x40 + abs, int[5])		/* get abs value/limits */ 
+
+/*
+ * Event types
+ */
+
+#define EV_RST			0x00
+#define EV_KEY			0x01
+#define EV_REL			0x02
+#define EV_ABS			0x03
+#define EV_LED			0x11
+#define EV_SND			0x12
+#define EV_REP			0x14
+#define EV_MAX			0x1f
+
+/*
+ * Keys and buttons
+ */
+
+#define KEY_RESERVED		0		
+#define KEY_ESC			1		
+#define KEY_1			2		
+#define KEY_2			3		
+#define KEY_3			4		
+#define KEY_4			5		
+#define KEY_5			6		
+#define KEY_6			7		
+#define KEY_7			8		
+#define KEY_8			9		
+#define KEY_9			10		
+#define KEY_0			11		
+#define KEY_MINUS		12		
+#define KEY_EQUAL		13		
+#define KEY_BACKSPACE		14		
+#define KEY_TAB			15		
+#define KEY_Q			16		
+#define KEY_W			17		
+#define KEY_E			18		
+#define KEY_R			19		
+#define KEY_T			20		
+#define KEY_Y			21		
+#define KEY_U			22		
+#define KEY_I			23		
+#define KEY_O			24		
+#define KEY_P			25		
+#define KEY_LEFTBRACE		26		
+#define KEY_RIGHTBRACE		27		
+#define KEY_ENTER		28		
+#define KEY_LEFTCTRL		29		
+#define KEY_A			30		
+#define KEY_S			31		
+#define KEY_D			32		
+#define KEY_F			33		
+#define KEY_G			34		
+#define KEY_H			35		
+#define KEY_J			36		
+#define KEY_K			37		
+#define KEY_L			38		
+#define KEY_SEMICOLON		39		
+#define KEY_APOSTROPHE		40		
+#define KEY_GRAVE		41		
+#define KEY_LEFTSHIFT		42		
+#define KEY_BACKSLASH		43		
+#define KEY_Z			44		
+#define KEY_X			45		
+#define KEY_C			46		
+#define KEY_V			47		
+#define KEY_B			48		
+#define KEY_N			49		
+#define KEY_M			50		
+#define KEY_COMMA		51		
+#define KEY_DOT			52		
+#define KEY_SLASH		53		
+#define KEY_RIGHTSHIFT		54		
+#define KEY_KPASTERISK		55		
+#define KEY_LEFTALT		56		
+#define KEY_SPACE		57		
+#define KEY_CAPSLOCK		58		
+#define KEY_F1			59		
+#define KEY_F2			60		
+#define KEY_F3			61		
+#define KEY_F4			62		
+#define KEY_F5			63		
+#define KEY_F6			64		
+#define KEY_F7			65		
+#define KEY_F8			66		
+#define KEY_F9			67		
+#define KEY_F10			68		
+#define KEY_NUMLOCK		69		
+#define KEY_SCROLLLOCK		70		
+#define KEY_KP7			71		
+#define KEY_KP8			72		
+#define KEY_KP9			73		
+#define KEY_KPMINUS		74		
+#define KEY_KP4			75		
+#define KEY_KP5			76		
+#define KEY_KP6			77		
+#define KEY_KPPLUS		78		
+#define KEY_KP1			79		
+#define KEY_KP2			80		
+#define KEY_KP3			81		
+#define KEY_KP0			82		
+#define KEY_KPDOT		83		
+#define KEY_103RD		84
+#define KEY_F13			85		
+#define KEY_102ND		86		
+#define KEY_F11			87		
+#define KEY_F12			88		
+#define KEY_F14			89		
+#define KEY_F15			90		
+#define KEY_F16			91		
+#define KEY_F17			92		
+#define KEY_F18			93		
+#define KEY_F19			94		
+#define KEY_F20			95		
+#define KEY_KPENTER		96		
+#define KEY_RIGHTCTRL		97		
+#define KEY_KPSLASH		98		
+#define KEY_SYSRQ		99		
+#define KEY_RIGHTALT		100		
+#define KEY_LINEFEED		101		
+#define KEY_HOME		102		
+#define KEY_UP			103		
+#define KEY_PAGEUP		104		
+#define KEY_LEFT		105		
+#define KEY_RIGHT		106		
+#define KEY_END			107		
+#define KEY_DOWN		108		
+#define KEY_PAGEDOWN		109		
+#define KEY_INSERT		110		
+#define KEY_DELETE		111		
+#define KEY_MACRO		112		
+#define KEY_MUTE		113		
+#define KEY_VOLUMEDOWN		114		
+#define KEY_VOLUMEUP		115		
+#define KEY_POWER		116		
+#define KEY_KPEQUAL		117		
+#define KEY_KPPLUSMINUS		118		
+#define KEY_PAUSE		119		
+#define KEY_F21			120		
+#define KEY_F22			121		
+#define KEY_F23			122		
+#define KEY_F24			123		
+#define KEY_JPN			124		
+#define KEY_LEFTMETA		125		
+#define KEY_RIGHTMETA		126		
+#define KEY_COMPOSE		127		
+
+#define KEY_STOP		128		
+#define KEY_AGAIN		129		
+#define KEY_PROPS		130		
+#define KEY_UNDO		131		
+#define KEY_FRONT		132		
+#define KEY_COPY		133		
+#define KEY_OPEN		134		
+#define KEY_PASTE		135		
+#define KEY_FIND		136		
+#define KEY_CUT			137		
+#define KEY_HELP		138		
+#define KEY_MENU		139		
+#define KEY_CALC		140		
+#define KEY_SETUP		141		
+#define KEY_SLEEP		142		
+#define KEY_WAKEUP		143		
+#define KEY_FILE		144		
+#define KEY_SENDFILE		145		
+#define KEY_DELETEFILE		146		
+#define KEY_XFER		147		
+#define KEY_PROG1		148		
+#define KEY_PROG2		149		
+#define KEY_WWW			150		
+#define KEY_MSDOS		151		
+#define KEY_COFFEE		152		
+#define KEY_DIRECTION		153		
+#define KEY_CYCLEWINDOWS	154		
+#define KEY_MAIL		155
+#define KEY_BOOKMARKS		156
+#define KEY_COMPUTER		157
+#define KEY_BACK		158
+#define KEY_FORWARD		159
+#define KEY_CLOSECD		160		
+#define KEY_EJECTCD		161		
+#define KEY_EJECTCLOSECD	162		
+#define KEY_NEXTSONG		163		
+#define KEY_PLAYPAUSE		164		
+#define KEY_PREVIOUSSONG	165		
+#define KEY_STOPCD		166		
+#define KEY_RECORD		167		
+#define KEY_REWIND		168		
+#define KEY_PHONE		169
+
+#define KEY_CONFIG		171
+#define KEY_HOMEPAGE		172
+#define KEY_REFRESH		173
+#define KEY_EXIT		174
+#define KEY_MOVE		175
+#define KEY_EDIT		176
+#define KEY_SCROLLUP		177
+#define KEY_SCROLLDOWN		178
+
+#define KEY_UNKNOWN		180
+
+#define BTN_MISC		0x100
+#define BTN_0			0x100
+#define BTN_1			0x101
+#define BTN_2			0x102
+#define BTN_3			0x103
+#define BTN_4			0x104
+#define BTN_5			0x105
+#define BTN_6			0x106
+#define BTN_7			0x107
+#define BTN_8			0x108
+#define BTN_9			0x109
+
+#define BTN_MOUSE		0x110
+#define BTN_LEFT		0x110
+#define BTN_RIGHT		0x111
+#define BTN_MIDDLE		0x112
+#define BTN_SIDE		0x113
+#define BTN_EXTRA		0x114
+#define BTN_FORWARD		0x115
+#define BTN_BACK		0x116
+
+#define BTN_JOYSTICK		0x120
+#define BTN_TRIGGER		0x120
+#define BTN_THUMB		0x121
+#define BTN_THUMB2		0x122
+#define BTN_TOP			0x123
+#define BTN_TOP2		0x124
+#define BTN_PINKIE		0x125
+#define BTN_BASE		0x126
+#define BTN_BASE2		0x127
+#define BTN_BASE3		0x128
+#define BTN_BASE4		0x129
+#define BTN_BASE5		0x12a
+#define BTN_BASE6		0x12b
+
+#define BTN_GAMEPAD		0x130
+#define BTN_A			0x130
+#define BTN_B			0x131
+#define BTN_C			0x132
+#define BTN_X			0x133
+#define BTN_Y			0x134
+#define BTN_Z			0x135
+#define BTN_TL			0x136
+#define BTN_TR			0x137
+#define BTN_TL2			0x138
+#define BTN_TR2			0x139
+#define BTN_SELECT		0x13a
+#define BTN_START		0x13b
+#define BTN_MODE		0x13c
+
+#define BTN_DIGI		0x140
+#define BTN_TOOL_PEN		0x140
+#define BTN_TOOL_RUBBER		0x141
+#define BTN_TOOL_BRUSH		0x142
+#define BTN_TOOL_PENCIL		0x143
+#define BTN_TOOL_AIRBRUSH	0x144
+#define BTN_TOOL_FINGER		0x145
+#define BTN_TOOL_MOUSE		0x146
+#define BTN_TOOL_LENS		0x147
+#define BTN_TOUCH		0x14a
+#define BTN_STYLUS		0x14b
+#define BTN_STYLUS2		0x14c
+
+#define KEY_MAX			0x1ff
+
+/*
+ * Relative axes
+ */
+
+#define REL_X			0x00
+#define REL_Y			0x01
+#define REL_Z			0x02
+#define REL_HWHEEL		0x06
+#define REL_DIAL		0x07
+#define REL_WHEEL		0x08
+#define REL_MISC		0x09
+#define REL_MAX			0x0f
+
+/*
+ * Absolute axes
+ */
+
+#define ABS_X			0x00
+#define ABS_Y			0x01
+#define ABS_Z			0x02
+#define ABS_RX			0x03
+#define ABS_RY			0x04
+#define ABS_RZ			0x05
+#define ABS_THROTTLE		0x06
+#define ABS_RUDDER		0x07
+#define ABS_TL			0x08
+#define ABS_TR			0x09
+#define ABS_HAT0X		0x10
+#define ABS_HAT0Y		0x11
+#define ABS_HAT1X		0x12
+#define ABS_HAT1Y		0x13
+#define ABS_HAT2X		0x14
+#define ABS_HAT2Y		0x15
+#define ABS_HAT3X		0x16
+#define ABS_HAT3Y		0x17
+#define ABS_PRESSURE		0x18
+#define ABS_DISTANCE		0x19
+#define ABS_TILT_X		0x1a
+#define ABS_TILT_Y		0x1b
+#define ABS_MISC		0x1c
+#define ABS_MAX			0x1f
+
+/*
+ * LEDs
+ */
+
+#define LED_NUML		0x00
+#define LED_CAPSL		0x01
+#define LED_SCROLLL		0x02
+#define LED_COMPOSE		0x03
+#define LED_KANA		0x04
+#define LED_MAX			0x0f
+
+/*
+ * Autorepeat values
+ */
+
+#define REP_DELAY		0x00
+#define REP_PERIOD		0x01
+#define REP_MAX			0x01
+
+/*
+ * Sounds
+ */
+
+#define SND_CLICK		0x00
+#define SND_BELL		0x01
+#define SND_MAX			0x07
+
+/*
+ * IDs.
+ */
+
+#define ID_BUS			0
+#define ID_VENDOR		1
+#define ID_PRODUCT		2
+#define ID_VERSION		3
+
+#define BUS_PCI			0x01
+#define BUS_ISAPNP		0x02
+#define BUS_USB			0x03
+
+#define BUS_ISA			0x10
+#define BUS_I8042		0x11
+#define BUS_XTKBD		0x12
+#define BUS_RS232		0x13
+#define BUS_GAMEPORT		0x14
+#define BUS_PARPORT		0x15
+#define BUS_AMIGA		0x16
+
+#ifdef __KERNEL__
+
+/*
+ * In-kernel definitions.
+ */
+
+#include <linux/sched.h>
+#include <linux/devfs_fs_kernel.h>
+
+#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define BIT(x)	(1UL<<((x)%BITS_PER_LONG))
+#define LONG(x) ((x)/BITS_PER_LONG)
+
+struct input_dev {
+
+	void *private;
+
+	int number;
+	char *name;
+	unsigned short idbus;
+	unsigned short idvendor;
+	unsigned short idproduct;
+	unsigned short idversion;
+
+	unsigned long evbit[NBITS(EV_MAX)];
+	unsigned long keybit[NBITS(KEY_MAX)];
+	unsigned long relbit[NBITS(REL_MAX)];
+	unsigned long absbit[NBITS(ABS_MAX)];
+	unsigned long ledbit[NBITS(LED_MAX)];
+	unsigned long sndbit[NBITS(SND_MAX)];
+
+	unsigned int keycodemax;
+	unsigned int keycodesize;
+	void *keycode;
+
+	unsigned int repeat_key;
+	struct timer_list timer;
+
+	int abs[ABS_MAX + 1];
+	int rep[REP_MAX + 1];
+
+	unsigned long key[NBITS(KEY_MAX)];
+	unsigned long led[NBITS(LED_MAX)];
+	unsigned long snd[NBITS(SND_MAX)];
+	
+	int absmax[ABS_MAX + 1];
+	int absmin[ABS_MAX + 1];
+	int absfuzz[ABS_MAX + 1];
+	int absflat[ABS_MAX + 1];
+
+	int (*open)(struct input_dev *dev);
+	void (*close)(struct input_dev *dev);
+	int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+
+	struct input_handle *handle;
+	struct input_dev *next;
+};
+
+struct input_handler {
+
+	void *private;
+
+	void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
+	struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev);
+	void (*disconnect)(struct input_handle *handle);
+
+	struct file_operations *fops;
+	int minor;
+
+	struct input_handle *handle;
+	struct input_handler *next;
+};
+
+struct input_handle {
+
+	void *private;
+
+	int open;
+	
+	struct input_dev *dev;
+	struct input_handler *handler;
+
+	struct input_handle *dnext;
+	struct input_handle *hnext;
+};
+
+void input_register_device(struct input_dev *);
+void input_unregister_device(struct input_dev *);
+
+void input_register_handler(struct input_handler *);
+void input_unregister_handler(struct input_handler *);
+
+int input_open_device(struct input_handle *);
+void input_close_device(struct input_handle *);
+
+devfs_handle_t input_register_minor(char *name, int minor, int minor_base);
+void input_unregister_minor(devfs_handle_t handle);
+
+void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+
+#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c))
+#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c)
+#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c)
+
+#endif
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/joystick.h linux.18p8/include/linux/joystick.h
--- linux.vanilla/include/linux/joystick.h	Wed May  3 21:21:40 2000
+++ linux.18p8/include/linux/joystick.h	Fri Sep 15 15:00:24 2000
@@ -134,18 +134,14 @@
 #error "You need to use at least v2.2 Linux kernel."
 #endif
 
+#include <linux/spinlock.h>
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-#include <asm/spinlock.h>
-typedef struct wait_queue *wait_queue_head_t;
-#define __setup(a,b)
+#define __exit
 #define BASE_ADDRESS(x,i)	((x)->base_address[i])
-#define DECLARE_WAITQUEUE(x,y)	struct wait_queue x = { y, NULL }
-#define init_waitqueue_head(x)	do { *(x) = NULL; } while (0)
-#define __set_current_state(x)	current->state = x
-#define SETUP_PARAM		char *str, int *ints
-#define SETUP_PARSE(x)		do {} while (0)
+#define SETUP_PARAM		char *str
+#define SETUP_PARSE(x)		int ints[x]; get_options(str, x, ints)
 #else
-#include <linux/spinlock.h>
 #define BASE_ADDRESS(x,i)	((x)->resource[i].start)
 #define SETUP_PARAM		char *str
 #define SETUP_PARSE(x)		int ints[x]; get_options(str, x, ints)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/kbd_kern.h linux.18p8/include/linux/kbd_kern.h
--- linux.vanilla/include/linux/kbd_kern.h	Fri Apr 21 23:10:44 2000
+++ linux.18p8/include/linux/kbd_kern.h	Fri Sep 15 15:00:14 2000
@@ -69,6 +69,8 @@
 
 extern int do_poke_blanked_console;
 
+extern void (*kbd_ledfunc)(unsigned int led);
+
 extern inline void show_console(void)
 {
 	do_poke_blanked_console = 1;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/kcomp.h linux.18p8/include/linux/kcomp.h
--- linux.vanilla/include/linux/kcomp.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/kcomp.h	Fri Sep 15 15:05:59 2000
@@ -0,0 +1,43 @@
+/*
+ * Kernel compatibility glue to allow USB compile on 2.2.x kernels
+ */
+
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/pagemap.h>
+
+#define __exit
+
+#ifdef __alpha
+extern long __kernel_thread (unsigned long, int (*)(void *), void *);
+static inline long kernel_thread (int (*fn) (void *), void *arg, unsigned long flags)
+{
+	return __kernel_thread (flags | CLONE_VM, fn, arg);
+}
+#undef CONFIG_APM
+#endif
+
+
+#define pci_enable_device(x)			0
+
+#define page_address(x)				(x | PAGE_OFFSET)
+
+#define	TTY_DRIVER_NO_DEVFS			0
+
+#define	net_device			device
+#define dev_kfree_skb_irq(a)		dev_kfree_skb(a)
+#define netif_wake_queue(dev)		clear_bit(0, &dev->tbusy)
+#define netif_stop_queue(dev)		set_bit(0, &dev->tbusy)
+#define netif_start_queue(dev)		do { dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; } while (0)
+#define netif_queue_stopped(dev)	dev->tbusy
+#define netif_running(dev)		dev->start
+
+#define NET_XMIT_SUCCESS	0
+#define NET_XMIT_DROP		1
+#define NET_XMIT_CN		2
+
+#define IORESOURCE_IO			1
+#define pci_resource_start(dev, i)	(dev->base_address[i] & ~IORESOURCE_IO)
+#define pci_resource_flags(dev, i)	(dev->base_address[i] & IORESOURCE_IO)
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/list.h linux.18p8/include/linux/list.h
--- linux.vanilla/include/linux/list.h	Fri Apr 21 12:46:59 2000
+++ linux.18p8/include/linux/list.h	Fri Sep  8 17:03:06 2000
@@ -17,6 +17,8 @@
 	struct list_head *next, *prev;
 };
 
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
 #define LIST_HEAD(name) \
 	struct list_head name = { &name, &name }
 
@@ -49,6 +51,14 @@
 }
 
 /*
+ * Insert a new entry at the tail
+ */
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
  * Delete a list entry by making the prev/next entries
  * point to each other.
  *
@@ -93,6 +103,9 @@
 
 #define list_entry(ptr, type, member) \
 	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define list_for_each(pos, head) \
+        for (pos = (head)->next; pos != (head); pos = pos->next)
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/major.h linux.18p8/include/linux/major.h
--- linux.vanilla/include/linux/major.h	Sun Jun 11 21:44:23 2000
+++ linux.18p8/include/linux/major.h	Mon Sep 11 18:14:04 2000
@@ -109,6 +109,15 @@
 #define SPECIALIX_NORMAL_MAJOR 75
 #define SPECIALIX_CALLOUT_MAJOR 76
 
+#define COMPAQ_CISS_MAJOR 	104
+#define COMPAQ_CISS_MAJOR1	105
+#define COMPAQ_CISS_MAJOR2      106
+#define COMPAQ_CISS_MAJOR3      107
+#define COMPAQ_CISS_MAJOR4      108
+#define COMPAQ_CISS_MAJOR5      109
+#define COMPAQ_CISS_MAJOR6      110
+#define COMPAQ_CISS_MAJOR7      111
+
 #define DASD_MAJOR      94	/* Official assignations from Peter */
 
 #define LVM_CHAR_MAJOR	109	/* Logical Volume Manager */
@@ -120,6 +129,9 @@
 #define UNIX98_PTY_MASTER_MAJOR	128
 #define UNIX98_PTY_MAJOR_COUNT	8
 #define UNIX98_PTY_SLAVE_MAJOR	(UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
+
+#define MSR_MAJOR 202
+#define CPUID_MAJOR 203
 
 /*
  * Tests for SCSI devices.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/mm.h linux.18p8/include/linux/mm.h
--- linux.vanilla/include/linux/mm.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/linux/mm.h	Fri Sep 15 14:59:44 2000
@@ -47,7 +47,7 @@
 	struct vm_area_struct * vm_avl_left;
 	struct vm_area_struct * vm_avl_right;
 
-	/* For areas with inode, the list inode->i_mmap, for shm areas,
+	/* For areas with inode, the list inode->i_mmap{,_shared}, for shm areas,
 	 * the list of attaches, otherwise unused.
 	 */
 	struct vm_area_struct *vm_next_share;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/module.h linux.18p8/include/linux/module.h
--- linux.vanilla/include/linux/module.h	Wed May  3 21:21:21 2000
+++ linux.18p8/include/linux/module.h	Fri Sep 15 14:59:47 2000
@@ -142,8 +142,11 @@
 #define __MODULE_STRING(x)	__MODULE_STRING_1(x)
 
 /* Find a symbol exported by the kernel or another module */
+#ifndef CONFIG_MODULES
+static inline unsigned long get_module_symbol(char *A, char *B) { return 0; };
+#else
 extern unsigned long get_module_symbol(char *, char *);
-
+#endif
 #if defined(MODULE) && !defined(__GENKSYMS__)
 
 /* Embedded module documentation macros.  */
@@ -195,6 +198,7 @@
 /* Define the module variable, and usage macros.  */
 extern struct module __this_module;
 
+#define THIS_MODULE		(&__this_module)
 #define MOD_INC_USE_COUNT	__MOD_INC_USE_COUNT(&__this_module)
 #define MOD_DEC_USE_COUNT	__MOD_DEC_USE_COUNT(&__this_module)
 #define MOD_IN_USE		__MOD_IN_USE(&__this_module)
@@ -216,6 +220,7 @@
 #define MODULE_SUPPORTED_DEVICE(name)
 #define MODULE_PARM(var,type)
 #define MODULE_PARM_DESC(var,desc)
+#define THIS_MODULE		NULL
 
 #ifndef __GENKSYMS__
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/msdos_fs_sb.h linux.18p8/include/linux/msdos_fs_sb.h
--- linux.vanilla/include/linux/msdos_fs_sb.h	Fri Apr 21 12:47:00 2000
+++ linux.18p8/include/linux/msdos_fs_sb.h	Thu Aug 31 14:33:07 2000
@@ -24,7 +24,9 @@
 		 posixfs:1,       /* Allow names like makefile and Makefile to coexist */
 		 numtail:1,       /* Does first alias have a numeric '~1' type tail? */
 		 atari:1,         /* Use Atari GEMDOS variation of MS-DOS fs */
-		 fat32:1;	  /* Is this a FAT32 partition? */
+		 fat32:1,	  /* Is this a FAT32 partition? */
+		 small_letter:1,  /* Use small letters for short name */
+		 force_long:1;	  /* Force create longname */
 };
 
 struct vfat_unicode {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/pci.h linux.18p8/include/linux/pci.h
--- linux.vanilla/include/linux/pci.h	Sat Sep  9 18:42:51 2000
+++ linux.18p8/include/linux/pci.h	Thu Sep 14 15:41:05 2000
@@ -298,6 +298,7 @@
 #define PCI_DEVICE_ID_COMPAQ_NETEL100D	0xae40
 #define PCI_DEVICE_ID_COMPAQ_NETEL100PI	0xae43
 #define PCI_DEVICE_ID_COMPAQ_NETEL100I	0xb011
+#define PCI_DEVICE_ID_COMPAQ_CISS	0xb060
 #define PCI_DEVICE_ID_COMPAQ_THUNDER	0xf130
 #define PCI_DEVICE_ID_COMPAQ_NETFLEX3B	0xf150
 
@@ -415,6 +416,7 @@
 #define PCI_DEVICE_ID_IBM_TR_WAKE	0x003e
 #define PCI_DEVICE_ID_IBM_MPIC		0x0046
 #define PCI_DEVICE_ID_IBM_3780IDSP	0x007d
+#define PCI_DEVICE_ID_IBM_SERVERAIDI960	0x01bd
 #define PCI_DEVICE_ID_IBM_MPIC_2	0xffff
 
 #define PCI_VENDOR_ID_WD		0x101c
@@ -766,6 +768,7 @@
 #define PCI_DEVICE_ID_TTI_HPT343	0x0003
 
 #define PCI_VENDOR_ID_VIA		0x1106
+#define PCI_DEVICE_ID_VIA_8371_0        0x0391
 #define PCI_DEVICE_ID_VIA_82C505	0x0505
 #define PCI_DEVICE_ID_VIA_82C561	0x0561
 #define PCI_DEVICE_ID_VIA_82C586_1	0x0571
@@ -1054,11 +1057,16 @@
 #define PCI_DEVICE_ID_LAVA_PARALLEL	0x8000
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A	0x8002 /* The Lava Dual Parallel is */
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_B	0x8003 /* two PCI devices on a card */
+#define PCI_DEVICE_ID_LAVA_BOCA_IOPPAR	0x8800
 
 #define PCI_VENDOR_ID_TIMEDIA		0x1409
 #define PCI_DEVICE_ID_TIMEDIA_1889	0x7168
 #define PCI_DEVICE_ID_TIMEDIA_4008A	0x7268
 
+#define PCI_VENDOR_ID_OXSEMI		0x1415
+#define PCI_DEVICE_ID_OXSEMI_12PCI840	0x8403
+#define PCI_DEVICE_ID_OXSEMI_16PCI954PP	0x9513
+
 #define PCI_VENDOR_ID_AFAVLAB		0x14db
 #define PCI_DEVICE_ID_AFAVLAB_TK9902	0x2120
 
@@ -1357,6 +1365,7 @@
 struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
 struct pci_dev *pci_find_class (unsigned int class, struct pci_dev *from);
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
+unsigned long pci_resource_len (struct pci_dev *dev, int n_base);
 
 #define pci_present pcibios_present
 int pci_read_config_byte(struct pci_dev *dev, u8 where, u8 *val);
@@ -1394,6 +1403,9 @@
 
 extern inline void pci_set_master(struct pci_dev *dev)
 { return; }
+
+extern inline unsigned long pci_resource_len (struct pci_dev *dev, int n_base) 
+{ return 0; }
 
 #endif /* !CONFIG_PCI */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/pm.h linux.18p8/include/linux/pm.h
--- linux.vanilla/include/linux/pm.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/pm.h	Mon Sep 11 19:58:51 2000
@@ -0,0 +1,88 @@
+#ifndef __LINUX_PM_H
+#define __LINUX_PM_H
+
+
+typedef int pm_request_t;
+
+struct pm_dev {
+	void *data;
+	struct pm_dev *next;
+	int (*event)(struct pm_dev *, pm_request_t, void *);
+};
+
+#define PM_SUSPEND	1
+#define PM_RESUME	2
+
+#ifdef CONFIG_APM
+
+#include <linux/apm_bios.h>
+
+#define PM_PCI_DEV	0
+#define PM_PCI_ID(a)	a
+
+static struct pm_dev *pm_dev = NULL;
+
+static int handle_apm_event(apm_event_t apm_event)
+{
+	struct pm_dev *list = pm_dev;
+	pm_request_t action;
+
+	switch (apm_event) {
+
+		case APM_SYS_SUSPEND:
+		case APM_CRITICAL_SUSPEND:
+		case APM_USER_SUSPEND:
+			action = PM_SUSPEND;
+			break;
+		case APM_NORMAL_RESUME:
+		case APM_CRITICAL_RESUME:
+		case APM_STANDBY_RESUME:
+			action = PM_RESUME;
+			break;
+		default:
+			return 0;
+	}
+
+	while (list) {
+		list->event(list, action, list->data);
+		list = list->next;
+	}
+
+	return 0;
+}
+
+static struct pm_dev *pm_register(int a, void *b, int (*event)(struct pm_dev *, pm_request_t, void *))
+{
+	struct pm_dev *list;
+	
+	list = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);
+	list->event = event;
+	list->next = pm_dev;
+	pm_dev = list;
+
+	apm_register_callback(handle_apm_event);
+
+	return list;
+}
+
+static void pm_unregister_all(int (*event)(struct pm_dev *, pm_request_t, void *))
+{
+	struct pm_dev *list;
+
+	while (pm_dev) {
+		list = pm_dev;
+		pm_dev = pm_dev->next;
+		kfree(list);
+	}
+
+	apm_unregister_callback(handle_apm_event);
+}
+
+#else
+
+#define pm_register(a,b,c)	0
+#define pm_unregister_all(a)	do {} while (0)
+
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/proc_fs.h linux.18p8/include/linux/proc_fs.h
--- linux.vanilla/include/linux/proc_fs.h	Sun Jun 11 21:44:23 2000
+++ linux.18p8/include/linux/proc_fs.h	Fri Sep 15 14:59:44 2000
@@ -436,6 +436,12 @@
 					 struct proc_dir_entry *parent);
 void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
 
+#define create_proc_info_entry(n, m, b, g) \
+	{ \
+		struct proc_dir_entry *r = create_proc_entry(n, m, b); \
+		if (r) r->get_info = g; \
+	}
+
 /*
  * proc_tty.c
  */
@@ -463,6 +469,13 @@
 	return NULL;
 }
 
+#define create_proc_info_entry(n, m, b, g) \
+	{ \
+		struct proc_dir_entry *r = create_proc_entry(n, m, b); \
+		if (r) r->get_info = g; \
+	}
+
+
 extern inline void remove_proc_entry(const char *name, struct proc_dir_entry *parent) {};
 
 extern inline void proc_tty_register_driver(struct tty_driver *driver) {};
@@ -471,4 +484,7 @@
 extern struct proc_dir_entry proc_root;
 
 #endif /* CONFIG_PROC_FS */
+
+#define proc_mkdir(buf, usbdir)	create_proc_entry(buf, S_IFDIR, usbdir)
+
 #endif /* _LINUX_PROC_FS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sched.h linux.18p8/include/linux/sched.h
--- linux.vanilla/include/linux/sched.h	Sat Sep  9 18:42:51 2000
+++ linux.18p8/include/linux/sched.h	Fri Sep 15 14:59:44 2000
@@ -497,6 +497,13 @@
 #define wake_up(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
 #define wake_up_interruptible(x)	__wake_up((x),TASK_INTERRUPTIBLE)
 
+#define __set_current_state(state_value)	do { current->state = state_value; } while (0)
+#ifdef __SMP__
+#define set_current_state(state_value)		do { mb(); __set_current_state(state_value); } while (0)
+#else
+#define set_current_state(state_value)		__set_current_state(state_value)
+#endif
+
 extern int in_group_p(gid_t grp);
 extern int in_egroup_p(gid_t grp);
 
@@ -687,6 +694,8 @@
 extern void exit_fs(struct task_struct *);
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
+
+extern void daemonize(void);
 
 extern int do_execve(char *, char **, char **, struct pt_regs *);
 extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/slab.h linux.18p8/include/linux/slab.h
--- linux.vanilla/include/linux/slab.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/linux/slab.h	Fri Sep 15 14:59:44 2000
@@ -51,6 +51,7 @@
 extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
 				       void (*)(void *, kmem_cache_t *, unsigned long),
 				       void (*)(void *, kmem_cache_t *, unsigned long));
+extern int kmem_cache_destroy(kmem_cache_t *);
 extern int kmem_cache_shrink(kmem_cache_t *);
 extern void *kmem_cache_alloc(kmem_cache_t *, int);
 extern void kmem_cache_free(kmem_cache_t *, void *);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/smb.h linux.18p8/include/linux/smb.h
--- linux.vanilla/include/linux/smb.h	Fri Apr 21 12:47:01 2000
+++ linux.18p8/include/linux/smb.h	Sat Sep  2 23:59:49 2000
@@ -62,6 +62,12 @@
 
 #ifdef __KERNEL__
 
+#define SMB_NLS_MAXNAMELEN 20
+struct smb_nls_codepage {
+	char local_name[SMB_NLS_MAXNAMELEN];
+	char remote_name[SMB_NLS_MAXNAMELEN];
+};
+
 #define SMB_MAXNAMELEN 255
 #define SMB_MAXPATHLEN 1024
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/smb_fs.h linux.18p8/include/linux/smb_fs.h
--- linux.vanilla/include/linux/smb_fs.h	Sun Jun 11 21:44:23 2000
+++ linux.18p8/include/linux/smb_fs.h	Fri Sep 15 15:01:29 2000
@@ -70,14 +70,6 @@
 #define SMB_F_CACHEVALID	0x01	/* directory cache valid */
 #define SMB_F_LOCALWRITE	0x02	/* file modified locally */
 
-/*
- * Bug fix flags
- */
-#define SMB_FIX_WIN95	0x0001	/* Win 95 server */
-#define SMB_FIX_OLDATTR	0x0002	/* Use core getattr (Win 95 speedup) */
-#define SMB_FIX_DIRATTR	0x0004	/* Use find_first for getattr */
-
-
 /* NT1 protocol capability bits */
 #define SMB_CAP_RAW_MODE         0x0001
 #define SMB_CAP_MPX_MODE         0x0002
@@ -117,6 +109,7 @@
 extern int init_smb_fs(void);
 
 /* linux/fs/smbfs/proc.c */
+int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp);
 __u32 smb_len(unsigned char *);
 __u8 *smb_encode_smb_length(__u8 *, __u32);
 __u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/smb_fs_sb.h linux.18p8/include/linux/smb_fs_sb.h
--- linux.vanilla/include/linux/smb_fs_sb.h	Fri Apr 21 12:47:01 2000
+++ linux.18p8/include/linux/smb_fs_sb.h	Sat Sep  2 23:59:49 2000
@@ -23,7 +23,7 @@
         enum smb_conn_state state;
 	struct file * sock_file;
 
-        struct smb_mount_data *mnt;
+        struct smb_mount_data_kernel *mnt;
         unsigned char *temp_buf;
 
 	/* Connections are counted. Each time a new socket arrives,
@@ -41,8 +41,20 @@
         unsigned short     rcls; /* The error codes we received */
         unsigned short     err;
 
-        /* We use our on data_ready callback, but need the original one */
+        /* We use our own data_ready callback, but need the original one */
         void *data_ready;
+
+	/* nls pointers for codepage conversions */
+	struct nls_table *remote_nls;
+	struct nls_table *local_nls;
+
+	/* utf8 can make strings longer so we can't do in-place conversion.
+	   This is a buffer for temporary stuff. We only need one so no need
+	   to put it on the stack. This points to temp_buf space. */
+	char *name_buf;
+
+	int (*convert)(char *, int, const char *, int,
+		       struct nls_table *, struct nls_table *);
 };
 
 #endif /* __KERNEL__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/smb_mount.h linux.18p8/include/linux/smb_mount.h
--- linux.vanilla/include/linux/smb_mount.h	Fri Apr 21 12:47:01 2000
+++ linux.18p8/include/linux/smb_mount.h	Sun Sep  3 00:28:07 2000
@@ -11,7 +11,7 @@
 
 #include <linux/types.h>
 
-#define SMB_MOUNT_VERSION 6
+#define SMB_MOUNT_VERSION	6
 
 struct smb_mount_data {
 	int version;
@@ -21,5 +21,29 @@
 	__kernel_mode_t file_mode;
 	__kernel_mode_t dir_mode;
 };
+
+
+#ifdef __KERNEL__
+
+/* flags */
+#define SMB_MOUNT_WIN95		0x0001  /* Win 95 server */
+#define SMB_MOUNT_OLDATTR	0x0002  /* Use core getattr (Win 95 speedup) */
+#define SMB_MOUNT_DIRATTR	0x0004  /* Use find_first for getattr */
+#define SMB_MOUNT_CASE		0x0008  /* Be case sensitive */
+
+struct smb_mount_data_kernel {
+	int _version;
+	__kernel_uid_t mounted_uid; /* Who may umount() this filesystem? */
+	__kernel_uid_t uid;
+	__kernel_gid_t gid;
+	__kernel_mode_t file_mode;
+	__kernel_mode_t dir_mode;
+
+	u32 flags;
+
+	struct smb_nls_codepage codepage;
+};
+
+#endif
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/smp.h linux.18p8/include/linux/smp.h
--- linux.vanilla/include/linux/smp.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/linux/smp.h	Fri Sep 15 14:59:44 2000
@@ -80,7 +80,8 @@
 #define smp_threads_ready			1
 #define kernel_lock()
 #define cpu_logical_map(cpu)			0
-#define smp_call_function(func,info,retry,wait)
+#define smp_call_function(func,info,retry,wait)	({0;})
+#define cpu_online_map 1
 
 #endif
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/spinlock.h linux.18p8/include/linux/spinlock.h
--- linux.vanilla/include/linux/spinlock.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/spinlock.h	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,4 @@
+#ifndef __LINUX_SPINLOCK_H
+#define __LINUX_SPINLOCK_H
+#include <asm/spinlock.h>
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/tasks.h linux.18p8/include/linux/tasks.h
--- linux.vanilla/include/linux/tasks.h	Fri Apr 21 12:47:01 2000
+++ linux.18p8/include/linux/tasks.h	Fri Sep 15 12:50:44 2000
@@ -11,7 +11,7 @@
 #define NR_CPUS 1
 #endif
 
-#define NR_TASKS	512	/* On x86 Max 4092, or 4090 w/APM configured. */
+#define NR_TASKS	512	/* On x86 Max about 4000 */
 
 #define MAX_TASKS_PER_USER (NR_TASKS/2)
 #define MIN_TASKS_LEFT_FOR_ROOT 4
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/usb.h linux.18p8/include/linux/usb.h
--- linux.vanilla/include/linux/usb.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/usb.h	Fri Sep 15 15:06:15 2000
@@ -0,0 +1,789 @@
+#ifndef __LINUX_USB_H
+#define __LINUX_USB_H
+
+/* USB constants */
+
+/*
+ * Device and/or Interface Class codes
+ */
+#define USB_CLASS_PER_INTERFACE		0	/* for DeviceClass */
+#define USB_CLASS_AUDIO			1
+#define USB_CLASS_COMM			2
+#define USB_CLASS_HID			3
+#define USB_CLASS_PHYSICAL		5
+#define USB_CLASS_PRINTER		7
+#define USB_CLASS_MASS_STORAGE		8
+#define USB_CLASS_HUB			9
+#define USB_CLASS_DATA			10
+#define USB_CLASS_APP_SPEC		0xfe
+#define USB_CLASS_VENDOR_SPEC		0xff
+
+/*
+ * USB types
+ */
+#define USB_TYPE_STANDARD		(0x00 << 5)
+#define USB_TYPE_CLASS			(0x01 << 5)
+#define USB_TYPE_VENDOR			(0x02 << 5)
+#define USB_TYPE_RESERVED		(0x03 << 5)
+
+/*
+ * USB recipients
+ */
+#define USB_RECIP_DEVICE		0x00
+#define USB_RECIP_INTERFACE		0x01
+#define USB_RECIP_ENDPOINT		0x02
+#define USB_RECIP_OTHER			0x03
+
+/*
+ * USB directions
+ */
+#define USB_DIR_OUT			0
+#define USB_DIR_IN			0x80
+
+/*
+ * Descriptor types
+ */
+#define USB_DT_DEVICE			0x01
+#define USB_DT_CONFIG			0x02
+#define USB_DT_STRING			0x03
+#define USB_DT_INTERFACE		0x04
+#define USB_DT_ENDPOINT			0x05
+
+#define USB_DT_HID			(USB_TYPE_CLASS | 0x01)
+#define USB_DT_REPORT			(USB_TYPE_CLASS | 0x02)
+#define USB_DT_PHYSICAL			(USB_TYPE_CLASS | 0x03)
+#define USB_DT_HUB			(USB_TYPE_CLASS | 0x09)
+
+/*
+ * Descriptor sizes per descriptor type
+ */
+#define USB_DT_DEVICE_SIZE		18
+#define USB_DT_CONFIG_SIZE		9
+#define USB_DT_INTERFACE_SIZE		9
+#define USB_DT_ENDPOINT_SIZE		7
+#define USB_DT_ENDPOINT_AUDIO_SIZE	9	/* Audio extension */
+#define USB_DT_HUB_NONVAR_SIZE		7
+#define USB_DT_HID_SIZE			9
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_NUMBER_MASK	0x0f	/* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK		0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK	0x03	/* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL	0
+#define USB_ENDPOINT_XFER_ISOC		1
+#define USB_ENDPOINT_XFER_BULK		2
+#define USB_ENDPOINT_XFER_INT		3
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+#define USB_PID_UNDEF_0                        0xf0
+#define USB_PID_OUT                            0xe1
+#define USB_PID_ACK                            0xd2
+#define USB_PID_DATA0                          0xc3
+#define USB_PID_PING                           0xb4	/* USB 2.0 */
+#define USB_PID_SOF                            0xa5
+#define USB_PID_NYET                           0x96	/* USB 2.0 */
+#define USB_PID_DATA2                          0x87	/* USB 2.0 */
+#define USB_PID_SPLIT                          0x78	/* USB 2.0 */
+#define USB_PID_IN                             0x69
+#define USB_PID_NAK                            0x5a
+#define USB_PID_DATA1                          0x4b
+#define USB_PID_PREAMBLE                       0x3c	/* Token mode */
+#define USB_PID_ERR                            0x3c	/* USB 2.0: handshake mode */
+#define USB_PID_SETUP                          0x2d
+#define USB_PID_STALL                          0x1e
+#define USB_PID_MDATA                          0x0f	/* USB 2.0 */
+
+/*
+ * Standard requests
+ */
+#define USB_REQ_GET_STATUS		0x00
+#define USB_REQ_CLEAR_FEATURE		0x01
+#define USB_REQ_SET_FEATURE		0x03
+#define USB_REQ_SET_ADDRESS		0x05
+#define USB_REQ_GET_DESCRIPTOR		0x06
+#define USB_REQ_SET_DESCRIPTOR		0x07
+#define USB_REQ_GET_CONFIGURATION	0x08
+#define USB_REQ_SET_CONFIGURATION	0x09
+#define USB_REQ_GET_INTERFACE		0x0A
+#define USB_REQ_SET_INTERFACE		0x0B
+#define USB_REQ_SYNCH_FRAME		0x0C
+
+/*
+ * HID requests
+ */
+#define USB_REQ_GET_REPORT		0x01
+#define USB_REQ_GET_IDLE		0x02
+#define USB_REQ_GET_PROTOCOL		0x03
+#define USB_REQ_SET_REPORT		0x09
+#define USB_REQ_SET_IDLE		0x0A
+#define USB_REQ_SET_PROTOCOL		0x0B
+
+
+#ifdef __KERNEL__
+
+#include <linux/kcomp.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>	/* for in_interrupt() */
+#include <linux/config.h>
+#include <linux/list.h>
+
+#define USB_MAJOR 180
+
+static __inline__ void wait_ms(unsigned int ms)
+{
+	if(!in_interrupt()) {
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(1 + ms * HZ / 1000);
+	}
+	else
+		mdelay(ms);
+}
+
+typedef struct {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+} devrequest __attribute__ ((packed));
+
+/*
+ * USB-status codes:
+ * USB_ST* maps to -E* and should go away in the future
+ */
+
+#define USB_ST_NOERROR		0
+#define USB_ST_CRC		(-EILSEQ)
+#define USB_ST_BITSTUFF		(-EPROTO)
+#define USB_ST_NORESPONSE	(-ETIMEDOUT)			/* device not responding/handshaking */
+#define USB_ST_DATAOVERRUN	(-EOVERFLOW)
+#define USB_ST_DATAUNDERRUN	(-EREMOTEIO)
+#define USB_ST_BUFFEROVERRUN	(-ECOMM)
+#define USB_ST_BUFFERUNDERRUN	(-ENOSR)
+#define USB_ST_INTERNALERROR	(-EPROTO) 			/* unknown error */
+#define USB_ST_SHORT_PACKET    	(-EREMOTEIO)
+#define USB_ST_PARTIAL_ERROR  	(-EXDEV)			/* ISO transfer only partially completed */
+#define USB_ST_URB_KILLED     	(-ENOENT)			/* URB canceled by user */
+#define USB_ST_URB_PENDING       (-EINPROGRESS)
+#define USB_ST_REMOVED		(-ENODEV) 			/* device not existing or removed */
+#define USB_ST_TIMEOUT		(-ETIMEDOUT)			/* communication timed out, also in urb->status**/
+#define USB_ST_NOTSUPPORTED	(-ENOSYS)			
+#define USB_ST_BANDWIDTH_ERROR	(-ENOSPC)			/* too much bandwidth used */
+#define USB_ST_URB_INVALID_ERROR  (-EINVAL)			/* invalid value/transfer type */
+#define USB_ST_URB_REQUEST_ERROR  (-ENXIO)			/* invalid endpoint */
+#define USB_ST_STALL		(-EPIPE) 			/* pipe stalled, also in urb->status*/
+
+/*
+ * USB device number allocation bitmap. There's one bitmap
+ * per USB tree.
+ */
+struct usb_devmap {
+	unsigned long devicemap[128 / (8*sizeof(unsigned long))];
+};
+
+#define USB_MAXBUS		64
+
+struct usb_busmap {
+	unsigned long busmap[USB_MAXBUS / (8*sizeof(unsigned long))];
+};
+
+/*
+ * This is a USB device descriptor.
+ *
+ * USB device information
+ */
+
+/* Everything but the endpoint maximums are aribtrary */
+#define USB_MAXCONFIG		8
+#define USB_ALTSETTINGALLOC     4
+#define USB_MAXALTSETTING	128  /* Hard limit */
+#define USB_MAXINTERFACES	32
+#define USB_MAXENDPOINTS	32
+
+/* All standard descriptors have these 2 fields in common */
+struct usb_descriptor_header {
+	__u8  bLength;
+	__u8  bDescriptorType;
+} __attribute__ ((packed));
+
+/* Device descriptor */
+struct usb_device_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u16 bcdUSB;
+	__u8  bDeviceClass;
+	__u8  bDeviceSubClass;
+	__u8  bDeviceProtocol;
+	__u8  bMaxPacketSize0;
+	__u16 idVendor;
+	__u16 idProduct;
+	__u16 bcdDevice;
+	__u8  iManufacturer;
+	__u8  iProduct;
+	__u8  iSerialNumber;
+	__u8  bNumConfigurations;
+} __attribute__ ((packed));
+
+/* Endpoint descriptor */
+struct usb_endpoint_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bEndpointAddress;
+	__u8  bmAttributes;
+	__u16 wMaxPacketSize;
+	__u8  bInterval;
+	__u8  bRefresh;
+	__u8  bSynchAddress;
+
+   	unsigned char *extra;   /* Extra descriptors */
+	int extralen;
+} __attribute__ ((packed));
+
+/* Interface descriptor */
+struct usb_interface_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bInterfaceNumber;
+	__u8  bAlternateSetting;
+	__u8  bNumEndpoints;
+	__u8  bInterfaceClass;
+	__u8  bInterfaceSubClass;
+	__u8  bInterfaceProtocol;
+	__u8  iInterface;
+
+  	struct usb_endpoint_descriptor *endpoint;
+
+	unsigned char *extra;
+	int extralen;
+} __attribute__ ((packed));
+
+struct usb_interface {
+	struct usb_interface_descriptor *altsetting;
+
+	int act_altsetting;		/* active alternate setting */
+	int num_altsetting;		/* number of alternate settings */
+	int max_altsetting;             /* total memory allocated */
+ 
+	struct usb_driver *driver;	/* driver */
+	void *private_data;
+};
+
+/* Configuration descriptor information.. */
+struct usb_config_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u16 wTotalLength;
+	__u8  bNumInterfaces;
+	__u8  bConfigurationValue;
+	__u8  iConfiguration;
+	__u8  bmAttributes;
+	__u8  MaxPower;
+
+	struct usb_interface *interface;
+} __attribute__ ((packed));
+
+/* String descriptor */
+struct usb_string_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u16 wData[1];
+} __attribute__ ((packed));
+
+struct usb_device;
+
+struct usb_driver {
+	const char *name;
+
+	void * (*probe)(struct usb_device *, unsigned int);
+	void (*disconnect)(struct usb_device *, void *);
+
+	struct list_head driver_list;
+
+	struct file_operations *fops;
+	int minor;
+
+	struct semaphore serialize;
+
+	int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
+};
+
+/*
+ * Pointer to a device endpoint interrupt function -greg
+ *   Parameters:
+ *     int status - This needs to be defined.  Right now each HCD
+ *         passes different transfer status bits back.  Don't use it
+ *         until we come up with a common meaning.
+ *     void *buffer - This is a pointer to the data used in this
+ *         USB transfer.
+ *     int length - This is the number of bytes transferred in or out
+ *         of the buffer by this transfer.  (-1 = unknown/unsupported)
+ *     void *dev_id - This is a user defined pointer set when the IRQ
+ *         is requested that is passed back.
+ *
+ *   Special Cases:
+ *     if (status == USB_ST_REMOVED), don't trust buffer or len.
+ */
+typedef int (*usb_device_irq)(int, void *, int, void *);
+
+/*----------------------------------------------------------------------------* 
+ * New USB Structures                                                         *
+ *----------------------------------------------------------------------------*/
+
+/*
+ * urb->transfer_flags:
+ */
+#define USB_DISABLE_SPD         0x0001
+#define USB_ISO_ASAP            0x0002
+#define USB_URB_EARLY_COMPLETE  0x0004
+#define USB_ASYNC_UNLINK        0x0008
+#define USB_QUEUE_BULK          0x0010
+#define USB_TIMEOUT_KILLED	0x1000	// only set by HCD!
+
+typedef struct
+{
+	unsigned int offset;
+	unsigned int length;		// expected length
+	unsigned int actual_length;
+	unsigned int status;
+} iso_packet_descriptor_t, *piso_packet_descriptor_t;
+
+struct urb;
+typedef void (*usb_complete_t)(struct urb *);
+
+typedef struct urb
+{
+	spinlock_t lock;		// lock for the URB
+	void *hcpriv;			// private data for host controller
+	struct list_head urb_list;	// list pointer to all active urbs 
+	struct urb *next;		// pointer to next URB	
+	struct usb_device *dev;		// pointer to associated USB device
+	unsigned int pipe;		// pipe information
+	int status;			// returned status
+	unsigned int transfer_flags;	// USB_DISABLE_SPD | USB_ISO_ASAP | USB_URB_EARLY_COMPLETE
+	void *transfer_buffer;		// associated data buffer
+	int transfer_buffer_length;	// data buffer length
+	int actual_length;              // actual data buffer length	
+	int bandwidth;			// bandwidth for this transfer request (INT or ISO)
+	unsigned char *setup_packet;	// setup packet (control only)
+	//
+	int start_frame;		// start frame (iso/irq only)
+	int number_of_packets;		// number of packets in this request (iso)
+	int interval;                   // polling interval (irq only)
+	int error_count;		// number of errors in this transfer (iso only)
+	int timeout;			// timeout (in jiffies)
+	//
+	void *context;			// context for completion routine
+	usb_complete_t complete;	// pointer to completion routine
+	//
+	iso_packet_descriptor_t	 iso_frame_desc[0];
+} urb_t, *purb_t;
+
+#define FILL_CONTROL_URB(a,aa,b,c,d,e,f,g) \
+    do {\
+	spin_lock_init(&(a)->lock);\
+	(a)->dev=aa;\
+	(a)->pipe=b;\
+	(a)->setup_packet=c;\
+	(a)->transfer_buffer=d;\
+	(a)->transfer_buffer_length=e;\
+	(a)->complete=f;\
+	(a)->context=g;\
+    } while (0)
+
+#define FILL_BULK_URB(a,aa,b,c,d,e,f) \
+    do {\
+	spin_lock_init(&(a)->lock);\
+	(a)->dev=aa;\
+	(a)->pipe=b;\
+	(a)->transfer_buffer=c;\
+	(a)->transfer_buffer_length=d;\
+	(a)->complete=e;\
+	(a)->context=f;\
+    } while (0)
+    
+#define FILL_INT_URB(a,aa,b,c,d,e,f,g) \
+    do {\
+	spin_lock_init(&(a)->lock);\
+	(a)->dev=aa;\
+	(a)->pipe=b;\
+	(a)->transfer_buffer=c;\
+	(a)->transfer_buffer_length=d;\
+	(a)->complete=e;\
+	(a)->context=f;\
+	(a)->interval=g;\
+	(a)->start_frame=-1;\
+    } while (0)
+
+#define FILL_CONTROL_URB_TO(a,aa,b,c,d,e,f,g,h) \
+    do {\
+	spin_lock_init(&(a)->lock);\
+	(a)->dev=aa;\
+	(a)->pipe=b;\
+	(a)->setup_packet=c;\
+	(a)->transfer_buffer=d;\
+	(a)->transfer_buffer_length=e;\
+	(a)->complete=f;\
+	(a)->context=g;\
+	(a)->timeout=h;\
+    } while (0)
+
+#define FILL_BULK_URB_TO(a,aa,b,c,d,e,f,g) \
+    do {\
+	spin_lock_init(&(a)->lock);\
+	(a)->dev=aa;\
+	(a)->pipe=b;\
+	(a)->transfer_buffer=c;\
+	(a)->transfer_buffer_length=d;\
+	(a)->complete=e;\
+	(a)->context=f;\
+	(a)->timeout=g;\
+    } while (0)
+    
+purb_t usb_alloc_urb(int iso_packets);
+void usb_free_urb (purb_t purb);
+int usb_submit_urb(purb_t purb);
+int usb_unlink_urb(purb_t purb);
+int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd,  void *data, int len, int timeout);
+int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout);
+
+/*-------------------------------------------------------------------*
+ *                         COMPATIBILITY STUFF                       *
+ *-------------------------------------------------------------------*/
+typedef struct
+{
+  wait_queue_head_t *wakeup;
+
+  usb_device_irq handler;
+  void* stuff;
+  /* more to follow */
+} api_wrapper_data;
+
+struct irq_wrapper_data {
+	void *context;
+	usb_device_irq handler;
+};
+
+/* -------------------------------------------------------------------------- */
+
+struct usb_operations {
+	int (*allocate)(struct usb_device *);
+	int (*deallocate)(struct usb_device *);
+	int (*get_frame_number) (struct usb_device *usb_dev);
+	int (*submit_urb) (struct urb* purb);
+	int (*unlink_urb) (struct urb* purb);
+};
+
+/*
+ * Allocated per bus we have
+ */
+struct usb_bus {
+	int busnum;			/* Bus number (in order of reg) */
+
+	struct usb_devmap devmap;       /* Device map */
+	struct usb_operations *op;      /* Operations (specific to the HC) */
+	struct usb_device *root_hub;    /* Root hub */
+	struct list_head bus_list;
+	void *hcpriv;                   /* Host Controller private data */
+
+	int bandwidth_allocated;	/* on this Host Controller; */
+					  /* applies to Int. and Isoc. pipes; */
+					  /* measured in microseconds/frame; */
+					  /* range is 0..900, where 900 = */
+					  /* 90% of a 1-millisecond frame */
+	int bandwidth_int_reqs;		/* number of Interrupt requesters */
+	int bandwidth_isoc_reqs;	/* number of Isoc. requesters */
+
+	/* usbdevfs inode list */
+	struct list_head inodes;
+};
+
+#define USB_MAXCHILDREN (8)	/* This is arbitrary */
+
+struct usb_device {
+	int devnum;			/* Device number on USB bus */
+	int slow;			/* Slow device? */
+
+	atomic_t refcnt;		/* Reference count */
+
+	unsigned int toggle[2];		/* one bit for each endpoint ([0] = IN, [1] = OUT) */
+	unsigned int halted[2];		/* endpoint halts; one bit per endpoint # & direction; */
+					/* [0] = IN, [1] = OUT */
+	int epmaxpacketin[16];		/* INput endpoint specific maximums */
+	int epmaxpacketout[16];		/* OUTput endpoint specific maximums */
+
+	struct usb_device *parent;
+	struct usb_bus *bus;		/* Bus we're part of */
+
+	struct usb_device_descriptor descriptor;/* Descriptor */
+	struct usb_config_descriptor *config;	/* All of the configs */
+	struct usb_config_descriptor *actconfig;/* the active configuration */
+
+	char **rawdescriptors;		/* Raw descriptors for each config */
+
+	int have_langid;		/* whether string_langid is valid yet */
+	int string_langid;		/* language ID for strings */
+  
+	void *hcpriv;			/* Host Controller private data */
+	
+        /* usbdevfs inode list */
+	struct list_head inodes;
+	struct list_head filelist;
+
+	/*
+	 * Child devices - these can be either new devices
+	 * (if this is a hub device), or different instances
+	 * of this same device.
+	 *
+	 * Each instance needs its own set of data structures.
+	 */
+
+	int maxchild;			/* Number of ports if hub */
+	struct usb_device *children[USB_MAXCHILDREN];
+};
+
+extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
+
+extern int usb_register(struct usb_driver *);
+extern void usb_deregister(struct usb_driver *);
+extern void usb_scan_devices(void);
+
+/* used these for multi-interface device registration */
+extern void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv);
+extern int usb_interface_claimed(struct usb_interface *iface);
+extern void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface);
+
+extern struct usb_bus *usb_alloc_bus(struct usb_operations *);
+extern void usb_free_bus(struct usb_bus *);
+extern void usb_register_bus(struct usb_bus *);
+extern void usb_deregister_bus(struct usb_bus *);
+
+extern struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *);
+extern void usb_free_dev(struct usb_device *);
+extern void usb_inc_dev_use(struct usb_device *);
+#define usb_dec_dev_use usb_free_dev
+
+extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
+extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc);
+extern void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc);
+
+extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size, int timeout);
+
+extern void usb_init_root_hub(struct usb_device *dev);
+extern int usb_root_hub_string(int id, int serial, char *type, __u8 *data, int len);
+extern void usb_connect(struct usb_device *dev);
+extern void usb_disconnect(struct usb_device **);
+
+extern void usb_destroy_configuration(struct usb_device *dev);
+
+int usb_get_current_frame_number (struct usb_device *usb_dev);
+
+/*
+ * Calling this entity a "pipe" is glorifying it. A USB pipe
+ * is something embarrassingly simple: it basically consists
+ * of the following information:
+ *  - device number (7 bits)
+ *  - endpoint number (4 bits)
+ *  - current Data0/1 state (1 bit)
+ *  - direction (1 bit)
+ *  - speed (1 bit)
+ *  - max packet size (2 bits: 8, 16, 32 or 64) [Historical; now gone.]
+ *  - pipe type (2 bits: control, interrupt, bulk, isochronous)
+ *
+ * That's 18 bits. Really. Nothing more. And the USB people have
+ * documented these eighteen bits as some kind of glorious
+ * virtual data structure.
+ *
+ * Let's not fall in that trap. We'll just encode it as a simple
+ * unsigned int. The encoding is:
+ *
+ *  - max size:		bits 0-1	(00 = 8, 01 = 16, 10 = 32, 11 = 64) [Historical; now gone.]
+ *  - direction:	bit 7		(0 = Host-to-Device [Out], 1 = Device-to-Host [In])
+ *  - device:		bits 8-14
+ *  - endpoint:		bits 15-18
+ *  - Data0/1:		bit 19
+ *  - speed:		bit 26		(0 = Full, 1 = Low Speed)
+ *  - pipe type:	bits 30-31	(00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk)
+ *
+ * Why? Because it's arbitrary, and whatever encoding we select is really
+ * up to us. This one happens to share a lot of bit positions with the UHCI
+ * specification, so that much of the uhci driver can just mask the bits
+ * appropriately.
+ */
+
+#define PIPE_ISOCHRONOUS		0
+#define PIPE_INTERRUPT			1
+#define PIPE_CONTROL			2
+#define PIPE_BULK			3
+
+#define usb_maxpacket(dev, pipe, out)	(out \
+				? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \
+				: (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] )
+#define usb_packetid(pipe)	(((pipe) & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT)
+
+#define usb_pipeout(pipe)	((((pipe) >> 7) & 1) ^ 1)
+#define usb_pipein(pipe)	(((pipe) >> 7) & 1)
+#define usb_pipedevice(pipe)	(((pipe) >> 8) & 0x7f)
+#define usb_pipe_endpdev(pipe)	(((pipe) >> 8) & 0x7ff)
+#define usb_pipeendpoint(pipe)	(((pipe) >> 15) & 0xf)
+#define usb_pipedata(pipe)	(((pipe) >> 19) & 1)
+#define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
+#define usb_pipetype(pipe)	(((pipe) >> 30) & 3)
+#define usb_pipeisoc(pipe)	(usb_pipetype((pipe)) == PIPE_ISOCHRONOUS)
+#define usb_pipeint(pipe)	(usb_pipetype((pipe)) == PIPE_INTERRUPT)
+#define usb_pipecontrol(pipe)	(usb_pipetype((pipe)) == PIPE_CONTROL)
+#define usb_pipebulk(pipe)	(usb_pipetype((pipe)) == PIPE_BULK)
+
+#define PIPE_DEVEP_MASK		0x0007ff00
+
+/* The D0/D1 toggle bits */
+#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1)
+#define	usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << ep))
+#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << ep)) | ((bit) << ep))
+
+/* Endpoint halt control/status */
+#define usb_endpoint_out(ep_dir)	(((ep_dir >> 7) & 1) ^ 1)
+#define usb_endpoint_halt(dev, ep, out) ((dev)->halted[out] |= (1 << (ep)))
+#define usb_endpoint_running(dev, ep, out) ((dev)->halted[out] &= ~(1 << (ep)))
+#define usb_endpoint_halted(dev, ep, out) ((dev)->halted[out] & (1 << (ep)))
+
+static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
+{
+	return (dev->devnum << 8) | (endpoint << 15) | (dev->slow << 26);
+}
+
+static inline unsigned int __default_pipe(struct usb_device *dev)
+{
+	return (dev->slow << 26);
+}
+
+/* Create various pipes... */
+#define usb_sndctrlpipe(dev,endpoint)	((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvctrlpipe(dev,endpoint)	((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndisocpipe(dev,endpoint)	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvisocpipe(dev,endpoint)	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndbulkpipe(dev,endpoint)	((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvbulkpipe(dev,endpoint)	((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndintpipe(dev,endpoint)	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvintpipe(dev,endpoint)	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_snddefctrl(dev)		((PIPE_CONTROL << 30) | __default_pipe(dev))
+#define usb_rcvdefctrl(dev)		((PIPE_CONTROL << 30) | __default_pipe(dev) | USB_DIR_IN)
+
+/*
+ * Send and receive control messages..
+ */
+int usb_new_device(struct usb_device *dev);
+int usb_reset_device(struct usb_device *dev);
+int usb_set_address(struct usb_device *dev);
+int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
+	unsigned char descindex, void *buf, int size);
+int usb_get_class_descriptor(struct usb_device *dev, int ifnum, unsigned char desctype,
+	unsigned char descindex, void *buf, int size);
+int usb_get_device_descriptor(struct usb_device *dev);
+int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr);
+int usb_get_status(struct usb_device *dev, int type, int target, void *data);
+int usb_get_configuration(struct usb_device *dev);
+int usb_get_protocol(struct usb_device *dev, int ifnum);
+int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol);
+int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
+int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id);
+int usb_set_configuration(struct usb_device *dev, int configuration);
+int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type,
+	unsigned char id, void *buf, int size);
+int usb_set_report(struct usb_device *dev, int ifnum, unsigned char type,
+	unsigned char id, void *buf, int size);
+int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
+int usb_clear_halt(struct usb_device *dev, int pipe);
+void usb_set_maxpacket(struct usb_device *dev);
+
+#define usb_get_extra_descriptor(ifpoint,type,ptr)\
+	__usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,type,(void**)ptr)
+
+/*
+ * Some USB bandwidth allocation constants.
+ */
+#define BW_HOST_DELAY	1000L		/* nanoseconds */
+#define BW_HUB_LS_SETUP	333L		/* nanoseconds */
+                        /* 4 full-speed bit times (est.) */
+
+#define FRAME_TIME_BITS         12000L		/* frame = 1 millisecond */
+#define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
+#define FRAME_TIME_USECS	1000L
+#define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
+
+#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */
+		/* Trying not to use worst-case bit-stuffing
+                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */
+		/* bytecount = data payload byte count */
+
+#define NS_TO_US(ns)	((ns + 500L) / 1000L)
+			/* convert & round nanoseconds to microseconds */
+
+/*
+ * Debugging helpers..
+ */
+void usb_show_device_descriptor(struct usb_device_descriptor *);
+void usb_show_config_descriptor(struct usb_config_descriptor *);
+void usb_show_interface_descriptor(struct usb_interface_descriptor *);
+void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *);
+void usb_show_device(struct usb_device *);
+void usb_show_string(struct usb_device *dev, char *id, int index);
+
+#ifdef DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
+
+
+/*
+ * bus and driver list
+ */
+
+extern struct list_head usb_driver_list;
+extern struct list_head usb_bus_list;
+
+/*
+ * USB device fs stuff
+ */
+
+#ifdef CONFIG_USB_DEVICEFS
+
+/*
+ * these are expected to be called from the USB core/hub thread
+ * with the kernel lock held
+ */
+extern void usbdevfs_add_bus(struct usb_bus *bus);
+extern void usbdevfs_remove_bus(struct usb_bus *bus);
+extern void usbdevfs_add_device(struct usb_device *dev);
+extern void usbdevfs_remove_device(struct usb_device *dev);
+
+extern int usbdevfs_init(void);
+extern void usbdevfs_cleanup(void);
+
+#else /* CONFIG_USB_DEVICEFS */
+
+extern inline void usbdevfs_add_bus(struct usb_bus *bus) {}
+extern inline void usbdevfs_remove_bus(struct usb_bus *bus) {}
+extern inline void usbdevfs_add_device(struct usb_device *dev) {}
+extern inline void usbdevfs_remove_device(struct usb_device *dev) {}
+
+extern inline int usbdevfs_init(void) { return 0; }
+extern inline void usbdevfs_cleanup(void) { }
+
+#endif /* CONFIG_USB_DEVICEFS */
+
+#endif  /* __KERNEL__ */
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/usbdev_fs_i.h linux.18p8/include/linux/usbdev_fs_i.h
--- linux.vanilla/include/linux/usbdev_fs_i.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/usbdev_fs_i.h	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,11 @@
+struct usb_device;
+struct usb_bus;
+
+struct usbdev_inode_info {
+	struct list_head dlist;
+	struct list_head slist;
+	union {
+		struct usb_device *dev;
+		struct usb_bus *bus;
+	} p;
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/usbdev_fs_sb.h linux.18p8/include/linux/usbdev_fs_sb.h
--- linux.vanilla/include/linux/usbdev_fs_sb.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/usbdev_fs_sb.h	Fri Sep  1 13:51:30 2000
@@ -0,0 +1,10 @@
+struct usbdev_sb_info {
+	struct list_head slist;
+	struct list_head ilist;
+	uid_t devuid;
+	gid_t devgid;
+	umode_t devmode;
+	uid_t busuid;
+	gid_t busgid;
+	umode_t busmode;
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/usbdevice_fs.h linux.18p8/include/linux/usbdevice_fs.h
--- linux.vanilla/include/linux/usbdevice_fs.h	Thu Jan  1 01:00:00 1970
+++ linux.18p8/include/linux/usbdevice_fs.h	Thu Sep 14 15:35:56 2000
@@ -0,0 +1,204 @@
+/*****************************************************************************/
+
+/*
+ *	usbdevice_fs.h  --  USB device file system.
+ *
+ *	Copyright (C) 2000
+ *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  History:
+ *   0.1  04.01.2000  Created
+ *
+ *  $Id: usbdevice_fs.h,v 1.1 2000/01/06 18:40:41 tom Exp $
+ */
+
+/*****************************************************************************/
+
+#ifndef _LINUX_USBDEVICE_FS_H
+#define _LINUX_USBDEVICE_FS_H
+
+#include <linux/types.h>
+
+/* --------------------------------------------------------------------- */
+
+#define USBDEVICE_SUPER_MAGIC 0x9fa2
+
+/* usbdevfs ioctl codes */
+
+struct usbdevfs_ctrltransfer {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+	__u32 timeout;  /* in milliseconds */
+ 	void *data;
+};
+
+struct usbdevfs_bulktransfer {
+	unsigned int ep;
+	unsigned int len;
+	unsigned int timeout; /* in milliseconds */
+	void *data;
+};
+
+struct usbdevfs_setinterface {
+	unsigned int interface;
+	unsigned int altsetting;
+};
+
+struct usbdevfs_disconnectsignal {
+	unsigned int signr;
+	void *context;
+};
+
+#define USBDEVFS_MAXDRIVERNAME 255
+
+struct usbdevfs_getdriver {
+	unsigned int interface;
+	char driver[USBDEVFS_MAXDRIVERNAME + 1];
+};
+
+struct usbdevfs_connectinfo {
+	unsigned int devnum;
+	unsigned char slow;
+};
+
+#define USBDEVFS_URB_DISABLE_SPD           1
+#define USBDEVFS_URB_ISO_ASAP              2
+
+#define USBDEVFS_URB_TYPE_ISO		   0
+#define USBDEVFS_URB_TYPE_INTERRUPT	   1
+#define USBDEVFS_URB_TYPE_CONTROL	   2
+#define USBDEVFS_URB_TYPE_BULK		   3
+
+struct usbdevfs_iso_packet_desc {
+	unsigned int length;
+	unsigned int actual_length;
+	unsigned int status;
+};
+
+struct usbdevfs_urb {
+	unsigned char type;
+	unsigned char endpoint;
+	int status;
+	unsigned int flags;
+	void *buffer;
+	int buffer_length;
+	int actual_length;
+	int start_frame;
+	int number_of_packets;
+	int error_count;
+	unsigned int signr;  /* signal to be sent on error, -1 if none should be sent */
+	void *usercontext;
+	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+
+/* ioctls for talking to drivers in the usbcore module: */
+struct usbdevfs_ioctl {
+	int	ifno;		/* interface 0..N ; negative numbers reserved */
+	int	ioctl_code;	/* MUST encode size + direction of data so the
+				 * macros in <asm/ioctl.h> give correct values */
+	void	*data;		/* param buffer (in, or out) */
+};
+
+/* You can do most things with hubs just through control messages,
+ * except find out what device connects to what port. */
+struct usbdevfs_hub_portinfo {
+	char nports;		/* number of downstream ports in this hub */
+	char port [127];	/* e.g. port 3 connects to device 27 */
+};
+
+#define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
+#define USBDEVFS_BULK              _IOWR('U', 2, struct usbdevfs_bulktransfer)
+#define USBDEVFS_RESETEP           _IOR('U', 3, unsigned int)
+#define USBDEVFS_SETINTERFACE      _IOR('U', 4, struct usbdevfs_setinterface)
+#define USBDEVFS_SETCONFIGURATION  _IOR('U', 5, unsigned int)
+#define USBDEVFS_GETDRIVER         _IOW('U', 8, struct usbdevfs_getdriver)
+#define USBDEVFS_SUBMITURB         _IOR('U', 10, struct usbdevfs_urb)
+#define USBDEVFS_DISCARDURB        _IO('U', 11)
+#define USBDEVFS_REAPURB           _IOW('U', 12, void *)
+#define USBDEVFS_REAPURBNDELAY     _IOW('U', 13, void *)
+#define USBDEVFS_DISCSIGNAL        _IOR('U', 14, struct usbdevfs_disconnectsignal)
+#define USBDEVFS_CLAIMINTERFACE    _IOR('U', 15, unsigned int)
+#define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
+#define USBDEVFS_CONNECTINFO       _IOW('U', 17, struct usbdevfs_connectinfo)
+#define USBDEVFS_IOCTL             _IOWR('U', 18, struct usbdevfs_ioctl)
+#define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
+#define USBDEVFS_RESET             _IO('U', 20)
+#define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)
+
+/* --------------------------------------------------------------------- */
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+#include <asm/semaphore.h>
+
+/*
+ * inode number macros
+ */
+#define ITYPE(x)   ((x)&(0xf<<28))
+#define ISPECIAL   (0<<28)
+#define IBUS       (1<<28)
+#define IDEVICE    (2<<28)
+#define IBUSNR(x)  (((x)>>8)&0xff)
+#define IDEVNR(x)  ((x)&0xff)
+
+#define IROOT      1
+
+/*
+ * sigh. rwsemaphores do not (yet) work from modules
+ */
+
+#define rw_semaphore semaphore
+#define init_rwsem init_MUTEX
+#define down_read down
+#define down_write down
+#define up_read up
+#define up_write up
+
+
+struct dev_state {
+	struct list_head list;      /* state list */
+	struct rw_semaphore devsem; /* protects modifications to dev (dev == NULL indicating disconnect) */ 
+	struct usb_device *dev;
+	struct file *file;
+	spinlock_t lock;            /* protects the async urb lists */
+	struct list_head async_pending;
+	struct list_head async_completed;
+	wait_queue_head_t wait;     /* wake up if a request completed */
+	unsigned int discsignr;
+	struct task_struct *disctask;
+	void *disccontext;
+	unsigned long ifclaimed;
+};
+
+/* internal methods & data */
+extern struct usb_driver usbdevfs_driver;
+extern struct file_operations usbdevfs_drivers_fops;
+extern struct file_operations usbdevfs_devices_fops;
+extern struct file_operations usbdevfs_device_file_operations;
+extern struct inode_operations usbdevfs_device_inode_operations;
+extern struct inode_operations usbdevfs_bus_inode_operations;
+extern struct file_operations usbdevfs_bus_file_operations;
+extern void usbdevfs_conn_disc_event(void);
+
+#endif /* __KERNEL__ */
+
+/* --------------------------------------------------------------------- */
+#endif /* _LINUX_USBDEVICE_FS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/videodev.h linux.18p8/include/linux/videodev.h
--- linux.vanilla/include/linux/videodev.h	Wed May  3 22:25:25 2000
+++ linux.18p8/include/linux/videodev.h	Fri Sep 15 15:05:10 2000
@@ -279,6 +279,8 @@
 #define VID_HARDWARE_VINO	20	/* Reserved for SGI Indy Vino */
 #define VID_HARDWARE_CADET	21	/* Cadet radio */
 #define VID_HARDWARE_TRUST	22	/* Trust FM Radio */
+#define VID_HARDWARE_CPIA	24
+#define VID_HARDWARE_OV511	27
 
 /*
  *	Initialiser list
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/vmalloc.h linux.18p8/include/linux/vmalloc.h
--- linux.vanilla/include/linux/vmalloc.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/linux/vmalloc.h	Fri Sep 15 14:59:45 2000
@@ -19,6 +19,9 @@
 long vread(char *buf, char *addr, unsigned long count);
 void vmfree_area_pages(unsigned long address, unsigned long size);
 int vmalloc_area_pages(unsigned long address, unsigned long size);
-
+extern inline void * vmalloc_32(unsigned long size)
+{
+	return vmalloc(size);
+}
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/wait.h linux.18p8/include/linux/wait.h
--- linux.vanilla/include/linux/wait.h	Fri Apr 21 23:10:16 2000
+++ linux.18p8/include/linux/wait.h	Sun Sep  3 00:06:13 2000
@@ -15,7 +15,14 @@
 	struct wait_queue * next;
 };
 
+typedef struct wait_queue wait_queue_t;
+typedef struct wait_queue *wait_queue_head_t;
+
 #define WAIT_QUEUE_HEAD(x) ((struct wait_queue *)((x)-1))
+#define DECLARE_WAITQUEUE(wait, current)	struct wait_queue wait = { current, NULL }
+#define DECLARE_WAIT_QUEUE_HEAD(wait)		wait_queue_head_t wait
+#define init_waitqueue_head(x)			*(x)=NULL
+#define init_waitqueue_entry(q,p)		((q)->task)=(p)
 
 static inline void init_waitqueue(struct wait_queue **q)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/ip.h linux.18p8/include/net/ip.h
--- linux.vanilla/include/net/ip.h	Fri Apr 21 23:11:52 2000
+++ linux.18p8/include/net/ip.h	Fri Sep 15 15:01:36 2000
@@ -171,10 +171,8 @@
 int ip_decrease_ttl(struct iphdr *iph)
 {
 	u16 check = iph->check;
-	check = ntohs(check) + 0x0100;
-	if ((check & 0xFF00) == 0)
-		check++;		/* carry overflow */
-	iph->check = htons(check);
+	check += __constant_htons(0x0100);
+	iph->check = check + (check>=0xFFFF);
 	return --iph->ttl;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/ipconfig.h linux.18p8/include/net/ipconfig.h
--- linux.vanilla/include/net/ipconfig.h	Sun Jun 11 21:44:23 2000
+++ linux.18p8/include/net/ipconfig.h	Fri Sep  8 16:53:11 2000
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.h,v 1.3 1999/01/04 20:13:29 davem Exp $
+ *  $Id: ipconfig.h,v 1.3.2.1 2000/06/09 02:27:24 davem Exp $
  *
  *  Copyright (C) 1997 Martin Mares
  *
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/init/main.c linux.18p8/init/main.c
--- linux.vanilla/init/main.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/init/main.c	Wed Sep 13 16:08:20 2000
@@ -22,6 +22,7 @@
 #include <linux/smp_lock.h>
 #include <linux/blk.h>
 #include <linux/hdreg.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -42,10 +43,6 @@
 #  include <asm/mtrr.h>
 #endif
 
-#ifdef CONFIG_APM
-#include <linux/apm_bios.h>
-#endif
-
 #ifdef CONFIG_DASD
 #include <asm/dasd.h>
 #endif
@@ -107,6 +104,9 @@
 extern void ioapic_pirq_setup(char *str, int *ints);
 extern void ioapic_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_MICROCODE
+extern int microcode_init(void);
+#endif
 extern void no_scroll(char *str, int *ints);
 extern void kbd_reset_setup(char *str, int *ints);
 extern void panic_setup(char *str, int *ints);
@@ -224,6 +224,7 @@
 extern void aha1542_setup(char *str, int *ints);
 extern void gdth_setup(char *str, int *ints);
 extern void aic7xxx_setup(char *str, int *ints);
+extern void ips_setup(char *str, int *ints);
 extern void AM53C974_setup(char *str, int *ints);
 extern void BusLogic_Setup(char *str, int *ints);
 extern void ncr53c8xx_setup(char *str, int *ints);
@@ -399,6 +400,10 @@
 extern void md_setup(char *str,int *ints) __init;
 #endif
 
+#ifdef CONFIG_AGP
+extern int agp_init (void);
+#endif
+
 /*
  * Boot command-line arguments
  */
@@ -862,6 +867,9 @@
 #ifdef CONFIG_SCSI_AIC7XXX
 	{ "aic7xxx=", aic7xxx_setup},
 #endif
+#ifdef CONFIG_SCSI_IPS
+	{ "ips=", ips_setup},
+#endif
 #ifdef CONFIG_SCSI_BUSLOGIC
 	{ "BusLogic=", BusLogic_Setup},
 #endif
@@ -1080,9 +1088,6 @@
 #ifdef CONFIG_PARIDE_PG
         { "pg.", pg_setup },
 #endif
-#ifdef CONFIG_APM
-	{ "apm=", apm_setup },
-#endif
 #ifdef CONFIG_N2
 	{ "n2=", n2_setup },
 #endif
@@ -1108,6 +1113,7 @@
 	{ 0, 0 }
 };
 
+
 #ifdef CONFIG_BLK_DEV_RAM
 static void __init ramdisk_start_setup(char *str, int *ints)
 {
@@ -1136,6 +1142,7 @@
 
 static int __init checksetup(char *line)
 {
+	struct new_kernel_param *p;
 	int i, ints[11];
 
 #ifdef CONFIG_BLK_DEV_IDE
@@ -1159,6 +1166,17 @@
 			return 1;
 		}
 	}
+
+	/* Now handle new-style __setup parameters */
+	p = &__setup_start;
+	while (p < &__setup_end) {
+		int n = strlen(p->str);
+		if (!strncmp(line,p->str,n)) {
+			if (p->setup_func(line+n))
+				return 1;
+		}
+		p++;
+	}
 	return 0;
 }
 
@@ -1457,6 +1475,21 @@
 
 struct task_struct *child_reaper = &init_task;
 
+
+static void __init do_initcalls(void)
+{
+	initcall_t *call;
+
+	call = &__initcall_start;
+	
+	while (call < &__initcall_end)
+	{
+		(*call)();
+		call++;
+	} 
+}
+
+
 /*
  * Ok, the machine is now initialized. None of the devices
  * have been touched yet, but the CPU subsystem is up and
@@ -1521,6 +1554,9 @@
 #ifdef CONFIG_MAC
 	nubus_init();
 #endif
+#ifdef CONFIG_AGP
+	agp_init();
+#endif
 
 	/* Networking initialization needs a process context */ 
 	sock_init();
@@ -1555,11 +1591,19 @@
 	/* .. executable formats .. */
 	binfmt_setup();
 
+	/* the functions marked initcall  */
+	
+	do_initcalls();
+
 	/* .. filesystems .. */
 	filesystem_setup();
 
 #ifdef CONFIG_IRDA
 	irda_device_init(); /* Must be done after protocol initialization */
+#endif
+
+#ifdef CONFIG_MICROCODE
+	microcode_init();
 #endif
 
 	/* Mount the root filesystem.. */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/ksyms.c linux.18p8/kernel/ksyms.c
--- linux.vanilla/kernel/ksyms.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/kernel/ksyms.c	Tue Sep 12 12:55:12 2000
@@ -23,8 +23,6 @@
 #include <linux/serial.h>
 #include <linux/locks.h>
 #include <linux/delay.h>
-#include <linux/minix_fs.h>
-#include <linux/ext2_fs.h>
 #include <linux/random.h>
 #include <linux/reboot.h>
 #include <linux/pagemap.h>
@@ -90,6 +88,7 @@
 EXPORT_SYMBOL(exit_files);
 EXPORT_SYMBOL(exit_fs);
 EXPORT_SYMBOL(exit_sighand);
+EXPORT_SYMBOL(daemonize);
 
 /* internal kernel memory management */
 EXPORT_SYMBOL(__get_free_pages);
@@ -98,6 +97,7 @@
 EXPORT_SYMBOL(kmem_find_general_cachep);
 EXPORT_SYMBOL(kmem_cache_create);
 EXPORT_SYMBOL(kmem_cache_shrink);
+EXPORT_SYMBOL(kmem_cache_destroy);
 EXPORT_SYMBOL(kmem_cache_alloc);
 EXPORT_SYMBOL(kmem_cache_free);
 EXPORT_SYMBOL(kmalloc);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/sched.c linux.18p8/kernel/sched.c
--- linux.vanilla/kernel/sched.c	Sun Jun 11 21:44:23 2000
+++ linux.18p8/kernel/sched.c	Fri Sep  1 13:51:30 2000
@@ -696,6 +696,7 @@
 	struct task_struct *prev, *next, *p;
 	int this_cpu, c;
 
+	sti();
 	if (tq_scheduler)
 		goto handle_tq_scheduler;
 tq_scheduler_back:
@@ -2044,6 +2045,34 @@
 	for_each_task(p)
 		show_task((p->tarray_ptr - &task[0]),p);
 	read_unlock(&tasklist_lock);
+}
+
+/*
+ *      Put all the gunge required to become a kernel thread without
+ *      attached user resources in one place where it belongs.
+ */
+
+void daemonize(void)
+{
+	struct fs_struct *fs;
+
+	/*
+	 * If we were started as result of loading a module, close all of the
+	 * user space pages.  We don't need them, and if we didn't close them
+	 * they would be locked into memory.
+	 */
+	exit_mm(current);
+
+	current->session = 1;
+	current->pgrp = 1;
+
+	/* Become as one with the init task */
+
+	exit_fs(current);	/* current->fs->count--; */
+	fs = init_task.fs;
+	current->fs = fs;
+	atomic_inc(&fs->count);
+
 }
 
 void __init init_idle(void)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/filemap.c linux.18p8/mm/filemap.c
--- linux.vanilla/mm/filemap.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/mm/filemap.c	Wed Sep 13 16:48:19 2000
@@ -708,6 +708,13 @@
 	{
 		unsigned long offset, nr;
 
+		/* If users can be writing to this page using arbitrary
+		 * virtual addresses, take care about potential aliasing
+		 * before reading the page on the kernel side.
+		 */
+		if (inode->i_mmap_shared != NULL)
+			flush_dcache_page(page_address(page));
+
 		offset = pos & ~PAGE_CACHE_MASK;
 		nr = PAGE_CACHE_SIZE - offset;
 		if (nr > inode->i_size - pos)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/memory.c linux.18p8/mm/memory.c
--- linux.vanilla/mm/memory.c	Fri Apr 21 12:47:02 2000
+++ linux.18p8/mm/memory.c	Wed Sep 13 16:48:19 2000
@@ -722,22 +722,8 @@
 	flush_page_to_ram(pte_page(pte));
 }
 
-/*
- * Handle all mappings that got truncated by a "truncate()"
- * system call.
- *
- * NOTE! We have to be ready to update the memory sharing
- * between the file and the memory map for a potential last
- * incomplete page.  Ugly, but necessary.
- */
-void vmtruncate(struct inode * inode, unsigned long offset)
+static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long offset)
 {
-	struct vm_area_struct * mpnt;
-
-	truncate_inode_pages(inode, offset);
-	if (!inode->i_mmap)
-		return;
-	mpnt = inode->i_mmap;
 	do {
 		struct mm_struct *mm = mpnt->vm_mm;
 		unsigned long start = mpnt->vm_start;
@@ -767,6 +753,23 @@
 		zap_page_range(mm, start, len);
 		flush_tlb_range(mm, start, end);
 	} while ((mpnt = mpnt->vm_next_share) != NULL);
+}
+
+/*
+ * Handle all mappings that got truncated by a "truncate()"
+ * system call.
+ *
+ * NOTE! We have to be ready to update the memory sharing
+ * between the file and the memory map for a potential last
+ * incomplete page.  Ugly, but necessary.
+ */
+void vmtruncate(struct inode * inode, unsigned long offset)
+{
+	truncate_inode_pages(inode, offset);
+	if (inode->i_mmap)
+		vmtruncate_list(inode->i_mmap, offset);
+	if (inode->i_mmap_shared)
+		vmtruncate_list(inode->i_mmap_shared, offset);
 }
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/mmap.c linux.18p8/mm/mmap.c
--- linux.vanilla/mm/mmap.c	Sun Jun 11 21:44:23 2000
+++ linux.18p8/mm/mmap.c	Wed Sep 13 16:48:19 2000
@@ -70,7 +70,7 @@
 	return free > pages;
 }
 
-/* Remove one vm structure from the inode's i_mmap ring. */
+/* Remove one vm structure from the inode's i_mmap{,_shared} ring. */
 static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
 {
 	struct file * file = vma->vm_file;
@@ -755,7 +755,7 @@
 }
 
 /* Insert vm structure into process list sorted by address
- * and into the inode's i_mmap ring.
+ * and into the inode's i_mmap{,_shared} ring.
  */
 void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
 {
@@ -783,14 +783,20 @@
 	file = vmp->vm_file;
 	if (file) {
 		struct inode * inode = file->f_dentry->d_inode;
+		struct vm_area_struct **head;
+
 		if (vmp->vm_flags & VM_DENYWRITE)
 			inode->i_writecount--;
       
+		head = &inode->i_mmap;
+		if (vmp->vm_flags & VM_SHARED)
+			head = &inode->i_mmap_shared;
+
 		/* insert vmp into inode's share list */
-		if((vmp->vm_next_share = inode->i_mmap) != NULL)
-			inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
-		inode->i_mmap = vmp;
-		vmp->vm_pprev_share = &inode->i_mmap;
+		if((vmp->vm_next_share = *head) != NULL)
+			(*head)->vm_pprev_share = &vmp->vm_next_share;
+		*head = vmp;
+		vmp->vm_pprev_share = head;
 	}
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/slab.c linux.18p8/mm/slab.c
--- linux.vanilla/mm/slab.c	Fri Apr 21 12:47:02 2000
+++ linux.18p8/mm/slab.c	Sat Sep  2 11:11:21 2000
@@ -987,8 +987,8 @@
  * is available.  To help debugging, a zero exit status indicates all slabs
  * were released.
  */
-int
-kmem_cache_shrink(kmem_cache_t *cachep)
+
+static int __kmem_cache_shrink(kmem_cache_t *cachep, int validated)
 {
 	kmem_cache_t	*searchp;
 	kmem_slab_t	*slabp;
@@ -1003,26 +1003,29 @@
 		return 2;
 	}
 
-	/* Find the cache in the chain of caches. */
-	down(&cache_chain_sem);		/* Semaphore is needed. */
-	searchp = &cache_cache;
-	for (;searchp->c_nextp != &cache_cache; searchp = searchp->c_nextp) {
-		if (searchp->c_nextp != cachep)
-			continue;
+	if(validated==0)
+	{
+		/* Find the cache in the chain of caches. */
+		down(&cache_chain_sem);		/* Semaphore is needed. */
+		searchp = &cache_cache;
+		for (;searchp->c_nextp != &cache_cache; searchp = searchp->c_nextp) {
+			if (searchp->c_nextp != cachep)
+				continue;
 
-		/* Accessing clock_searchp is safe - we hold the mutex. */
-		if (cachep == clock_searchp)
-			clock_searchp = cachep->c_nextp;
-		goto found;
-	}
-	up(&cache_chain_sem);
-	printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n", cachep);
-	return 2;
+			/* Accessing clock_searchp is safe - we hold the mutex. */
+			if (cachep == clock_searchp)
+				clock_searchp = cachep->c_nextp;
+			goto found;
+		}
+		up(&cache_chain_sem);
+		printk(KERN_ERR "kmem_shrink: Invalid cache addr %p\n", cachep);
+		return 2;
 found:
-	/* Release the semaphore before getting the cache-lock.  This could
-	 * mean multiple engines are shrinking the cache, but so what.
-	 */
-	up(&cache_chain_sem);
+		/* Release the semaphore before getting the cache-lock.  This could
+		 * mean multiple engines are shrinking the cache, but so what.
+		 */
+		up(&cache_chain_sem);
+	}
 	spin_lock_irq(&cachep->c_spinlock);
 
 	/* If the cache is growing, stop shrinking. */
@@ -1040,6 +1043,71 @@
 		ret--;		/* Cache is empty. */
 	spin_unlock_irq(&cachep->c_spinlock);
 	return ret;
+}
+
+int kmem_cache_shrink(kmem_cache_t *cachep)
+{
+	return __kmem_cache_shrink(cachep,0);
+}
+
+/*
+ * Remove a kmem_cache_t object from the slab cache. When returns 0 it
+ * completed succesfully. -arca
+ */
+int kmem_cache_destroy(kmem_cache_t * cachep)
+{
+	kmem_cache_t * prev;
+	int ret;
+
+	if (!cachep) {
+		printk(KERN_ERR "kmem_destroy: NULL ptr\n");
+		return 1;
+	}
+	if (in_interrupt()) {
+		printk(KERN_ERR "kmem_destroy: Called during int - %s\n",
+		       cachep->c_name);
+		return 1;
+	}
+
+	ret = 0;
+	/* Find the cache in the chain of caches. */
+	down(&cache_chain_sem);
+	for (prev = &cache_cache; prev->c_nextp != &cache_cache;
+	     prev = prev->c_nextp) {
+		if (prev->c_nextp != cachep)
+			continue;
+
+		/* Accessing clock_searchp is safe - we hold the mutex. */
+		if (cachep == clock_searchp)
+			clock_searchp = cachep->c_nextp;
+
+		/* remove the cachep from the cache_cache list. -arca */
+		prev->c_nextp = cachep->c_nextp;
+
+		ret = 1;
+		break;
+	}
+	up(&cache_chain_sem);
+
+	if (!ret) {
+		printk(KERN_ERR "kmem_destroy: Invalid cache addr %p\n",
+		       cachep);
+		return 1;
+	}
+
+	if (__kmem_cache_shrink(cachep, 1)) {
+		printk(KERN_ERR "kmem_destroy: Can't free all objects %p\n",
+		       cachep);
+		down(&cache_chain_sem);
+		cachep->c_nextp = cache_cache.c_nextp;
+		cache_cache.c_nextp = cachep;
+		up(&cache_chain_sem);
+		return 1;
+	}
+
+	kmem_cache_free(&cache_cache, cachep);
+
+	return 0;
 }
 
 /* Get the memory for a slab management obj. */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ax25/af_ax25.c linux.18p8/net/ax25/af_ax25.c
--- linux.vanilla/net/ax25/af_ax25.c	Fri Apr 21 12:47:10 2000
+++ linux.18p8/net/ax25/af_ax25.c	Thu Aug 31 15:29:34 2000
@@ -1140,12 +1140,19 @@
 	 */
 	if (sk->zapped) {
 		if ((err = ax25_rt_autobind(sk->protinfo.ax25, &fsa->fsa_ax25.sax25_call)) < 0)
+		{
+			if(digi)
+				kfree(digi);
 			return err;
+		}
 		ax25_fillin_cb(sk->protinfo.ax25, sk->protinfo.ax25->ax25_dev);
 		ax25_insert_socket(sk->protinfo.ax25);
 	} else {
 		if (sk->protinfo.ax25->ax25_dev == NULL)
+		{
+			if (digi != NULL) kfree(digi);
 			return -EHOSTUNREACH;
+		}
 	}
 
 	if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, sk->protinfo.ax25->ax25_dev->dev) != NULL) {
@@ -1191,7 +1198,9 @@
 
 	/* Now the loop */
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
+	{
 		return -EINPROGRESS;
+	}
 
 	cli();	/* To avoid races on the sleep */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/dev.c linux.18p8/net/core/dev.c
--- linux.vanilla/net/core/dev.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/net/core/dev.c	Fri Sep  8 16:53:11 2000
@@ -900,6 +900,12 @@
 		 */
 		skb = skb_dequeue(&backlog);
 
+		/* This can happen if dev_clear_backlog is running
+		 * at the same time and it empties the queue.
+		 */
+		if (skb == NULL)
+			break;
+
 #ifdef CONFIG_CPU_IS_SLOW
 		if (ave_busy > 128*16) {
 			kfree_skb(skb);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/sock.c linux.18p8/net/core/sock.c
--- linux.vanilla/net/core/sock.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/net/core/sock.c	Fri Sep  8 16:53:11 2000
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.80 1999/05/08 03:04:34 davem Exp $
+ * Version:	$Id: sock.c,v 1.80.2.3 2000/08/10 00:37:05 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/Config.in linux.18p8/net/ipv4/Config.in
--- linux.vanilla/net/ipv4/Config.in	Sun Jun 11 21:44:23 2000
+++ linux.18p8/net/ipv4/Config.in	Sat Sep  2 23:47:24 2000
@@ -15,7 +15,7 @@
     bool 'IP: fast network address translation' CONFIG_IP_ROUTE_NAT
   fi
 fi
-bool 'IP: kernel level autoconfiguration' CONFIG_IP_PNP
+bool 'IP: kernel-level configuration support' CONFIG_IP_PNP
 if [ "$CONFIG_IP_PNP" = "y" ]; then
   bool '      DHCP support' CONFIG_IP_PNP_DHCP
   bool '      BOOTP support' CONFIG_IP_PNP_BOOTP
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/af_inet.c linux.18p8/net/ipv4/af_inet.c
--- linux.vanilla/net/ipv4/af_inet.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/net/ipv4/af_inet.c	Thu Sep 14 15:34:28 2000
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.87.2.6 2000/01/13 04:28:16 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.87.2.9 2000/09/14 10:44:31 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -536,7 +536,8 @@
 	snum = ntohs(addr->sin_port);
 #ifdef CONFIG_IP_MASQUERADE
 	/* The kernel masquerader needs some ports. */
-	if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END))
+	if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END) && 
+	   chk_addr_ret != RTN_MULTICAST)
 		return -EADDRINUSE;
 #endif		 
 	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/icmp.c linux.18p8/net/ipv4/icmp.c
--- linux.vanilla/net/ipv4/icmp.c	Sun Jun 11 21:44:23 2000
+++ linux.18p8/net/ipv4/icmp.c	Fri Sep  8 16:53:11 2000
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.52.2.5 2000/04/08 02:45:56 davem Exp $
+ *	Version: $Id: icmp.c,v 1.52.2.6 2000/08/31 23:49:16 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -522,6 +522,7 @@
 	struct icmp_bxm icmp_param;
 	struct rtable *rt = (struct rtable*)skb_in->dst;
 	struct ipcm_cookie ipc;
+	unsigned int offset;
 	u32 saddr;
 	u8  tos;
 	
@@ -651,7 +652,12 @@
 	room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
 	room -= sizeof(struct icmphdr);
 
-	icmp_param.data_len=(iph->ihl<<2)+skb_in->len;
+	if (skb_in->data > skb_in->nh.raw) 
+		offset = (skb_in->data - skb_in->nh.raw);
+	else 
+		offset = 0;
+	icmp_param.data_len = (skb_in->len + offset);
+
 	if (icmp_param.data_len > room)
 		icmp_param.data_len = room;
 	
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_masq_irc.c linux.18p8/net/ipv4/ip_masq_irc.c
--- linux.vanilla/net/ipv4/ip_masq_irc.c	Fri Apr 21 12:47:14 2000
+++ linux.18p8/net/ipv4/ip_masq_irc.c	Thu Aug 31 15:59:26 2000
@@ -20,9 +20,8 @@
  *	Juan Jose Ciarlante	:  put new ms entry to listen()
  *	Scottie Shore		:  added support for clients that add extra args
  *	  <sshore@escape.ca>
- *
- * FIXME:
- *	- detect also previous "PRIVMSG" string ?.
+ *	Scottie Shore		:  added support for mIRC DCC resume negotiation
+ *	  <sshore@escape.ca>
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -91,9 +90,10 @@
  { "CHAT ", 5 },
  { "MOVE ", 5 },
  { "TSEND ", 6 },
- { "SCHAT ", 6 }
+ { "SCHAT ", 6 },
+ { "ACCEPT ", 7 },
 };
-#define MAXMATCHLEN 6
+#define MAXMATCHLEN 7
 
 static int
 masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
@@ -137,6 +137,7 @@
 	 *	strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26
 	 *	strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26
 	 *	strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27
+	 *	strlen("\1DCC ACCEPT F AAAAAAAA P S\1\n")=28
 	 *		AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
 	 *		P:         bound port (min 1 d )
 	 *		F:         filename   (min 1 d )
@@ -197,17 +198,26 @@
 				s_port = simple_strtoul(data,&data,10);
 				addr_end_p = data;
 
+				/*	Do we already have a port open for this client?
+				 *	If so, use it (for DCC ACCEPT)
+				 */
+
+				n_ms = ip_masq_out_get(IPPROTO_TCP,
+						htonl(s_addr),htons(s_port),
+						0, 0);
+
 				/*
-				 *	Now create an masquerade entry for it
-				 * 	must set NO_DPORT and NO_DADDR because
+				 *	If we didn't already have a port, we need to make one.
+				 * 	We must set NO_DPORT and NO_DADDR because
 				 *	connection is requested by another client.
 				 */
 
-				n_ms = ip_masq_new(IPPROTO_TCP,
-						maddr, 0,
-						htonl(s_addr),htons(s_port),
-						0, 0,
-						IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
+				if (n_ms==NULL)
+					n_ms = ip_masq_new(IPPROTO_TCP,
+							maddr, 0,
+							htonl(s_addr),htons(s_port),
+							0, 0,
+							IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
 				if (n_ms==NULL)
 					return 0;
 
@@ -252,6 +262,125 @@
 
 }
 
+int
+masq_irc_in (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
+{
+        struct sk_buff *skb;
+	struct iphdr *iph;
+	struct tcphdr *th;
+	char *data, *data_limit;
+	__u32 s_addr;
+	__u16 s_port;
+	struct ip_masq *n_ms;
+	char buf[20];		/* "m_addr m_port" (dec base)*/
+        unsigned buf_len;
+	int diff;
+        char *dcc_p, *addr_beg_p, *addr_end_p;
+
+        skb = *skb_p;
+	iph = skb->nh.iph;
+        th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
+        data = (char *)&th[1];
+
+        /*
+	 *	Hunt irc DCC RESUME string:
+	 *
+	 *	strlen("\1DCC RESUME chat AAAAAAAA P\1\n")=29
+	 *		AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
+	 *		P:         bound port (min 1 d )
+	 *		F:         filename   (min 1 d )
+	 *		S:         size       (min 1 d ) 
+	 *		0x01, \n:  terminators
+         */
+
+        data_limit = skb->h.raw + skb->len;
+        
+	while (data < (data_limit - 29 ) )
+	{
+		if (memcmp(data,"\1DCC RESUME ",12))  {
+			data ++;
+			continue;
+		}
+
+		dcc_p = data;
+		data += 12;
+
+		while( *data++ != ' ')
+			/*
+			 *	must still parse, at least, "AAAAAAAA P\1\n",
+			 *      12 bytes left.
+			 */
+			if (data > (data_limit-12)) return 0;
+
+
+		addr_beg_p = data;
+
+		/*
+		 *	masq bound address in dec base
+		 */
+
+		s_addr = simple_strtoul(data,&data,10);
+		if (*data++ !=' ')
+		continue;
+
+		/*
+		 *	masq bound port in dec base
+		 */
+
+		s_port = simple_strtoul(data,&data,10);
+		addr_end_p = data;
+
+		/*
+		 *	Find the masq entry associated with this connection.
+		 *	The entry should have no dest addr/port yet.
+		 *	If there is no entry, return 0.
+		 */
+
+		n_ms = ip_masq_in_get(IPPROTO_TCP,
+			0, 0,
+			htonl(s_addr), htons(s_port));
+					
+		if (n_ms==NULL)
+			return 0;
+
+		/*
+		 * Replace the outside address with the inside address
+		 */
+
+		buf_len = sprintf(buf,"%lu %u",
+			ntohl(n_ms->saddr),ntohs(n_ms->sport));
+
+		/*
+		 * Calculate required delta-offset to keep TCP happy
+		 */
+
+		diff = buf_len - (addr_end_p-addr_beg_p);
+
+		*addr_beg_p = '\0';
+		IP_MASQ_DEBUG(1-debug, "masq_irc_in(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
+
+		/*
+		 *	No shift.
+		 */
+
+		if (diff==0) {
+			/*
+			 * simple case, just copy.
+			 */
+			memcpy(addr_beg_p,buf,buf_len);
+		} else {
+			*skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
+				addr_beg_p, addr_end_p-addr_beg_p,
+				buf, buf_len);
+		}
+
+		return diff;
+
+	}
+	return 0;
+
+}
+
 /*
  *	Main irc object
  *     	You need 1 object per port in case you need
@@ -263,12 +392,12 @@
 struct ip_masq_app ip_masq_irc = {
         NULL,			/* next */
 	"irc",			/* name */
-        0,                      /* type */
-        0,                      /* n_attach */
-        masq_irc_init_1,        /* init_1 */
-        masq_irc_done_1,        /* done_1 */
-        masq_irc_out,           /* pkt_out */
-        NULL                    /* pkt_in */
+        0,			/* type */
+        0,			/* n_attach */
+        masq_irc_init_1,	/* init_1 */
+        masq_irc_done_1,	/* done_1 */
+        masq_irc_out,		/* pkt_out */
+        masq_irc_in		/* pkt_in */
 };
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ipconfig.c linux.18p8/net/ipv4/ipconfig.c
--- linux.vanilla/net/ipv4/ipconfig.c	Sun Jun 11 21:44:23 2000
+++ linux.18p8/net/ipv4/ipconfig.c	Sat Sep  2 23:47:24 2000
@@ -74,8 +74,9 @@
 #define CONF_POST_OPEN		(1*HZ)	/* After opening: 1 second */
 
 /* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */
-#define CONF_OPEN_RETRIES 	3	/* (Re)open devices three times */
-#define CONF_SEND_RETRIES 	3	/* Send requests three times */
+#define CONF_OPEN_RETRIES 	2	/* (Re)open devices twice */
+#define CONF_SEND_RETRIES 	6	/* Send six requests per open */
+#define CONF_INTER_TIMEOUT	(HZ/2)	/* Inter-device timeout: 1/2 second */
 #define CONF_BASE_TIMEOUT	(HZ*2)	/* Initial timeout: 2 seconds */
 #define CONF_TIMEOUT_RANDOM	(HZ)	/* Maximum amount of randomization */
 #define CONF_TIMEOUT_MULT	*7/4	/* Rate of timeout growth */
@@ -86,7 +87,7 @@
  * Public IP configuration
  */
 
-int ic_enable __initdata = 1;			/* Automatic IP cfg enabled? */
+int ic_enable __initdata = 0;			/* IP config enabled? */
 
 /* Protocol choice */
 static int ic_proto_enabled __initdata = 0
@@ -129,10 +130,11 @@
 static int ic_proto_have_if __initdata = 0;
 
 #ifdef IPCONFIG_DYNAMIC
-static volatile int ic_got_reply = 0;	    /* Protocol(s) we got reply from */
+static spinlock_t ic_recv_lock = SPIN_LOCK_UNLOCKED;
+static volatile int ic_got_reply __initdata = 0;    /* Proto(s) that replied */
 #endif
 #ifdef IPCONFIG_DHCP
-static int ic_dhcp_msgtype __initdata = 0;	/* Last incoming msg type */
+static int ic_dhcp_msgtype __initdata = 0;	/* DHCP msg type received */
 #endif
 
 
@@ -144,11 +146,12 @@
 	struct ic_device *next;
 	struct device *dev;
 	unsigned short flags;
-	int able;
+	short able;
+	u32 xid;
 };
 
-static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
-static struct device *ic_dev __initdata = NULL;		/* Selected device */
+static struct ic_device *ic_first_dev __initdata = NULL; /* Open devices */
+static struct device *ic_dev __initdata = NULL;		 /* Selected device */
 
 static int __init ic_open_devs(void)
 {
@@ -185,8 +188,13 @@
 			last = &d->next;
 			d->flags = oflags;
 			d->able = able;
+			if (able & IC_BOOTP)
+				get_random_bytes(&d->xid, sizeof(u32));
+			else
+				d->xid = 0;
 			ic_proto_have_if |= able;
-			DBG((SELF "%s UP (able=%d)\n", dev->name, able));
+			DBG((SELF "%s UP (able=%d, xid=%08x)\n",
+			     dev->name, able, d->xid));
 		}
 	*last = NULL;
 
@@ -386,11 +394,22 @@
 	unsigned char *rarp_ptr = (unsigned char *) (rarp + 1);
 	unsigned long sip, tip;
 	unsigned char *sha, *tha;		/* s for "source", t for "target" */
+	struct ic_device *d;
+
+	/* One reply at a time, please. */
+	spin_lock(&ic_recv_lock);
 
 	/* If we already have a reply, just drop the packet */
 	if (ic_got_reply)
 		goto drop;
 
+	/* Find the ic_device that the packet arrived on */
+	d = ic_first_dev;
+	while (d && d->dev != dev)
+		d = d->next;
+	if (!d)
+		goto drop;	/* should never happen */
+
 	/* If this test doesn't pass, it's not IP, or we should ignore it anyway */
 	if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd))
 		goto drop;
@@ -420,7 +439,7 @@
 	if (ic_servaddr != INADDR_NONE && ic_servaddr != sip)
 		goto drop;
 
-	/* Victory! The packet is what we were looking for! */
+	/* We have a winner! */
 	ic_dev = dev;
 	if (ic_myaddr == INADDR_NONE)
 		ic_myaddr = tip;
@@ -428,8 +447,12 @@
 	ic_got_reply = IC_RARP;
 
 drop:
-	/* and throw the packet out */
+	/* Show's over.  Nothing to see here.  */
+	spin_unlock(&ic_recv_lock);
+
+	/* Throw the packet out. */
 	kfree_skb(skb);
+
 	return 0;
 }
 
@@ -437,16 +460,23 @@
 /*
  *  Send RARP request packet over all devices which allow RARP.
  */
+static void __init ic_rarp_send_if(struct ic_device *d)
+{
+	struct device *dev = d->dev;
+	arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
+		 dev->dev_addr, dev->dev_addr);
+}
+
+/*
+ *  Send RARP request package over a single interface.
+ */
 static void __init ic_rarp_send(void)
 {
 	struct ic_device *d;
 
 	for (d=ic_first_dev; d; d=d->next)
-		if (d->able & IC_RARP) {
-			struct device *dev = d->dev;
-			arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
-				 dev->dev_addr, dev->dev_addr);
-		}
+		if (d->able & IC_RARP)
+			ic_rarp_send_if(d);
 }
 
 #endif
@@ -491,8 +521,6 @@
 #define DHCPRELEASE	7
 #define DHCPINFORM	8
 
-static u32 ic_bootp_xid;
-
 static int ic_bootp_recv(struct sk_buff *skb, struct device *dev,
 			 struct packet_type *pt);
 
@@ -516,12 +544,12 @@
 static void __init
 ic_dhcp_init_options(u8 *options)
 {
-	u8 msgtype = ((ic_dhcp_msgtype == DHCPOFFER)
-		      ? DHCPREQUEST : DHCPDISCOVER);
+	u8 mt = ((ic_servaddr == INADDR_NONE)
+		 ? DHCPDISCOVER : DHCPREQUEST);
 	u8 *e = options;
 
 #ifdef IPCONFIG_DEBUG
-	printk("DHCP: Sending message type %d\n", msgtype);
+	printk("DHCP: Sending message type %d\n", mt);
 #endif
 
 	memcpy(e, ic_bootp_cookie, 4);	/* RFC1048 Magic Cookie */
@@ -529,9 +557,14 @@
 
 	*e++ = 53;		/* DHCP message type */
 	*e++ = 1;
-	*e++ = msgtype;
+	*e++ = mt;
+
+	if (mt == DHCPREQUEST) {
+		*e++ = 54;	/* Server ID (IP address) */
+		*e++ = 4;
+		memcpy(e, &ic_servaddr, 4);
+		e += 4;
 
-	if (msgtype == DHCPREQUEST) {
 		*e++ = 50;	/* Requested IP address */
 		*e++ = 4;
 		memcpy(e, &ic_myaddr, 4);
@@ -595,8 +628,6 @@
 static inline void
 ic_bootp_init(void)
 {
-	get_random_bytes(&ic_bootp_xid, sizeof(u32));
-	DBG(("DHCP/BOOTP: XID=%08x\n", ic_bootp_xid));
 	dev_add_pack(&bootp_packet_type);
 }
 
@@ -656,7 +687,7 @@
 	b->server_ip = INADDR_NONE;
 	memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
 	b->secs = htons(jiffies / HZ);
-	b->xid = ic_bootp_xid;
+	b->xid = d->xid;
 
 	/* add DHCP options or BOOTP extensions */
 #ifdef IPCONFIG_DHCP
@@ -756,12 +787,23 @@
 {
 	struct bootp_pkt *b = (struct bootp_pkt *) skb->nh.iph;
 	struct iphdr *h = &b->iph;
+	struct ic_device *d;
 	int len;
 
+	/* One reply at a time, please. */
+	spin_lock(&ic_recv_lock);
+
 	/* If we already have a reply, just drop the packet */
 	if (ic_got_reply)
 		goto drop;
 
+	/* Find the ic_device that the packet arrived on */
+	d = ic_first_dev;
+	while (d && d->dev != dev)
+		d = d->next;
+	if (!d)
+		goto drop;  /* should never happen */
+
 	/* Check whether it's a BOOTP packet */
 	if (skb->pkt_type == PACKET_OTHERHOST ||
 	    skb->len < sizeof(struct udphdr) + sizeof(struct iphdr) ||
@@ -783,9 +825,9 @@
 
 	/* Is it a reply to our BOOTP request? */
 	len = ntohs(b->udph.len) - sizeof(struct udphdr);
-	if (len < 300 ||				    /* See RFC 951:2.1 */
+	if (len < 300 ||		/* See RFC 951:2.1 */
 	    b->op != BOOTP_REPLY ||
-	    b->xid != ic_bootp_xid) {
+	    b->xid != d->xid) {
 		printk("?");
 		goto drop;
 	}
@@ -798,7 +840,7 @@
 #ifdef IPCONFIG_DHCP
 
 		u32 server_id = INADDR_NONE;
-		ic_dhcp_msgtype = 0;
+		int mt = 0;
 
 		ext = &b->exten[4];
 		while (ext < end && *ext != 0xff) {
@@ -811,7 +853,7 @@
 			switch (*opt) {
 			    case 53:	/* Message type */
 				if (opt[1])
-					ic_dhcp_msgtype = opt[2];
+					mt = opt[2];
 				break;
 			    case 54:	/* Server ID (IP address) */
 				if (opt[1] >= 4)
@@ -821,11 +863,15 @@
 		}
 
 #ifdef IPCONFIG_DEBUG
-		printk("DHCP: Got message type %d\n", ic_dhcp_msgtype);
+		printk("DHCP: Got message type %d\n", mt);
 #endif
 
-		switch (ic_dhcp_msgtype) {
+		switch (mt) {
 		    case DHCPOFFER:
+			/* While in the process of accepting one offer,
+			   ignore all others. */
+			if (ic_myaddr != INADDR_NONE)
+				goto drop;
 			/* Let's accept that offer. */
 			ic_myaddr = b->your_ip;
 			ic_servaddr = server_id;
@@ -833,7 +879,7 @@
 			printk("DHCP: Offered address %s", in_ntoa(ic_myaddr));
 			printk(" by server %s\n", in_ntoa(ic_servaddr));
 #endif
-			goto drop;
+			break;
 
 		    case DHCPACK:
 			/* Yeah! */
@@ -846,6 +892,8 @@
 			goto drop;
 		}
 
+		ic_dhcp_msgtype = mt;
+
 #endif /* IPCONFIG_DHCP */
 
 		ext = &b->exten[4];
@@ -859,6 +907,7 @@
 		}
 	}
 
+	/* We have a winner! */
 	ic_dev = dev;
 	ic_myaddr = b->your_ip;
 	ic_servaddr = b->server_ip;
@@ -869,8 +918,12 @@
 	ic_got_reply = IC_BOOTP;
 
 drop:
-	/* and throw the packet out */
+	/* Show's over.  Nothing to see here.  */
+	spin_unlock(&ic_recv_lock);
+
+	/* Throw the packet out. */
 	kfree_skb(skb);
+
 	return 0;
 }	
 
@@ -887,8 +940,8 @@
 static int __init ic_dynamic(void)
 {
 	int retries;
-	unsigned long timeout, jiff;
-	unsigned long start_jiffies;
+	struct ic_device *d;
+	unsigned long start_jiffies, timeout, jiff;
 	int do_bootp = ic_proto_have_if & IC_BOOTP;
 	int do_rarp = ic_proto_have_if & IC_RARP;
 
@@ -936,36 +989,39 @@
 	 * [Actually we could now, but the nothing else running note still 
 	 *  applies.. - AC]
 	 */
-	printk(KERN_NOTICE "Sending %s%s%s requests ",
+	printk(KERN_NOTICE "Sending %s%s%s requests .",
 	       do_bootp
 		? ((ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP") : "",
 	       (do_bootp && do_rarp) ? " and " : "",
 	       do_rarp ? "RARP" : "");
+
 	start_jiffies = jiffies;
+	d = ic_first_dev;
 	retries = CONF_SEND_RETRIES;
 	get_random_bytes(&timeout, sizeof(timeout));
 	timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
 	for(;;) {
 #ifdef IPCONFIG_BOOTP
-		if (do_bootp)
-			ic_bootp_send(jiffies - start_jiffies);
+		if (do_bootp && (d->able & IC_BOOTP))
+			ic_bootp_send_if(d, jiffies - start_jiffies);
 #endif
 #ifdef IPCONFIG_RARP
-		if (do_rarp)
-			ic_rarp_send();
+		if (do_rarp && (d->able & IC_RARP))
+			ic_rarp_send_if(d);
 #endif
-		printk(".");
 
-		jiff = jiffies + timeout;
+		jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout);
 		while (jiffies < jiff && !ic_got_reply)
 			;
+
 #ifdef IPCONFIG_DHCP
+		/* DHCP isn't done until we get a DHCPACK. */
 		if ((ic_got_reply & IC_BOOTP)
 		    && (ic_proto_enabled & IC_USE_DHCP)
 		    && ic_dhcp_msgtype != DHCPACK)
 		{
-			printk(",");
 			ic_got_reply = 0;
+			printk(",");
 			continue;
 		}
 #endif /* IPCONFIG_DHCP */
@@ -975,14 +1031,21 @@
 			break;
 		}
 
+		if ((d = d->next))
+			continue;
+
 		if (! --retries) {
 			printk(" timed out!\n");
 			break;
 		}
 
+		d = ic_first_dev;
+
 		timeout = timeout CONF_TIMEOUT_MULT;
 		if (timeout > CONF_TIMEOUT_MAX)
 			timeout = CONF_TIMEOUT_MAX;
+
+		printk(".");
 	}
 
 #ifdef IPCONFIG_BOOTP
@@ -997,7 +1060,8 @@
 	if (!ic_got_reply)
 		return -1;
 
-	printk(SELF "Got %s answer from %s\n",
+	printk(SELF "%s: Got %s answer from %s\n",
+	       ic_dev->name, 
 	       ((ic_got_reply & IC_RARP) ? "RARP"
 		: (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"),
 	       in_ntoa(ic_servaddr));
@@ -1167,7 +1231,7 @@
 	 * Clue in the operator.
 	 */
 	printk(SELF "Complete:");
-	printk("\n      device=%s", ic_dev->name);
+	printk( "\n     if=%s", ic_dev->name);
 	printk(", addr=%s", in_ntoa(ic_myaddr));
 	printk(", mask=%s", in_ntoa(ic_netmask));
 	printk(", gw=%s", in_ntoa(ic_gateway));
@@ -1199,14 +1263,14 @@
  *			  by BOOTP
  *	<device>	- use all available devices
  *	<PROTO>:
- *	   dhcp|bootp|rarp  - use given protocol
- *	   both or empty    - use both BOOTP and RARP (not DHCP)
- *	   off or none	    - don't do autoconfig at all
+ *	   off|none	    - don't do autoconfig at all (DEFAULT)
+ *	   on|any           - use any configured protocol
+ *	   dhcp|bootp|rarp  - use only the specified protocol
+ *	   both             - use both BOOTP and RARP (not DHCP)
  */
 static int __init ic_proto_name(char *name)
 {
-	if (!strcmp(name, "off") || !strcmp(name, "none")) {
-		ic_proto_enabled = 0;
+	if (!strcmp(name, "on") || !strcmp(name, "any")) {
 		return 1;
 	}
 #ifdef CONFIG_IP_PNP_DHCP
@@ -1241,10 +1305,10 @@
 	char *cp, *ip, *dp;
 	int num = 0;
 
-	if (!strcmp(addrs, "off") || !strcmp(addrs, "none")) {
-		ic_enable = 0;
+	ic_enable = (*addrs && strcmp(addrs, "off") && strcmp(addrs, "none"));
+	if (!ic_enable)
 		return;
-	}
+
 	if (ic_proto_name(addrs))
 		return;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/route.c linux.18p8/net/ipv4/route.c
--- linux.vanilla/net/ipv4/route.c	Fri Apr 21 12:47:15 2000
+++ linux.18p8/net/ipv4/route.c	Fri Sep  8 16:53:11 2000
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.67.2.4 1999/11/16 02:28:43 davem Exp $
+ * Version:	$Id: route.c,v 1.67.2.5 2000/09/01 23:19:46 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -222,8 +222,8 @@
 				(unsigned long)r->rt_dst,
 				(unsigned long)r->rt_gateway,
 				r->rt_flags,
-				atomic_read(&r->u.dst.use),
 				atomic_read(&r->u.dst.refcnt),
+				atomic_read(&r->u.dst.use),
 				0,
 				(unsigned long)r->rt_src, (int)r->u.dst.pmtu,
 				r->u.dst.window,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp.c linux.18p8/net/ipv4/tcp.c
--- linux.vanilla/net/ipv4/tcp.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/net/ipv4/tcp.c	Fri Sep  8 16:53:11 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.140.2.11 2000/04/17 05:57:01 davem Exp $
+ * Version:	$Id: tcp.c,v 1.140.2.14 2000/08/10 00:37:05 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_input.c linux.18p8/net/ipv4/tcp_input.c
--- linux.vanilla/net/ipv4/tcp_input.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/net/ipv4/tcp_input.c	Fri Sep  8 16:53:11 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.164.2.15 2000/05/27 04:01:49 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.164.2.16 2000/06/28 04:54:16 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_ipv4.c linux.18p8/net/ipv4/tcp_ipv4.c
--- linux.vanilla/net/ipv4/tcp_ipv4.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/net/ipv4/tcp_ipv4.c	Fri Sep  8 16:53:11 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.175.2.13 1999/11/16 06:33:53 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.175.2.16 2000/06/28 04:54:17 davem Exp $
  *
  *		IPv4 specific functions
  *
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_output.c linux.18p8/net/ipv4/tcp_output.c
--- linux.vanilla/net/ipv4/tcp_output.c	Sat Sep  9 18:42:51 2000
+++ linux.18p8/net/ipv4/tcp_output.c	Fri Sep  8 16:53:11 2000
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.108.2.6 2000/02/07 20:20:11 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.108.2.9 2000/09/02 01:27:51 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -811,7 +811,6 @@
  */
 void tcp_send_active_reset(struct sock *sk)
 {
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	struct sk_buff *skb;
 
 	/* NOTE: No TCP options attached and we never retransmit this. */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/ip6_input.c linux.18p8/net/ipv6/ip6_input.c
--- linux.vanilla/net/ipv6/ip6_input.c	Fri Apr 21 12:47:16 2000
+++ linux.18p8/net/ipv6/ip6_input.c	Tue Sep  5 21:48:39 2000
@@ -99,7 +99,7 @@
 	struct raw6_opt *opt;
 
 	opt = &sk->tp_pinfo.tp_raw;
-	icmph = (struct icmp6hdr *) (skb->nh.ipv6h + 1);
+	icmph = (struct icmp6hdr *) skb->h.raw;
 	return test_bit(icmph->icmp6_type, &opt->filter);
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/ip6_output.c linux.18p8/net/ipv6/ip6_output.c
--- linux.vanilla/net/ipv6/ip6_output.c	Fri Apr 21 12:47:16 2000
+++ linux.18p8/net/ipv6/ip6_output.c	Tue Sep  5 21:48:39 2000
@@ -121,7 +121,7 @@
 
 		if (skb_headroom(skb) < head_room) {
 			struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
-			kfree(skb);
+			kfree_skb(skb);
 			skb = skb2;
 			if (skb == NULL)
 				return -ENOBUFS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/reassembly.c linux.18p8/net/ipv6/reassembly.c
--- linux.vanilla/net/ipv6/reassembly.c	Fri Apr 21 12:47:16 2000
+++ linux.18p8/net/ipv6/reassembly.c	Tue Sep  5 21:48:39 2000
@@ -160,6 +160,15 @@
 		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb->h.raw);
 		return NULL;
 	}
+ 
+	if (!(fhdr->frag_off & __constant_htons(0xFFF9))) {
+		/* It is not a fragmented frame */
+		skb->h.raw += sizeof(struct frag_hdr);
+		ipv6_statistics.Ip6ReasmOKs++;
+
+		return &fhdr->nexthdr;
+	}
+
 	if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
 		frag_prune();
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/compressors/Config.in linux.18p8/net/irda/compressors/Config.in
--- linux.vanilla/net/irda/compressors/Config.in	Fri Apr 21 12:47:16 2000
+++ linux.18p8/net/irda/compressors/Config.in	Mon Sep 11 17:14:10 2000
@@ -4,7 +4,7 @@
 if [ "$CONFIG_IRDA_COMPRESSION" != "n" ]; then
    comment '    IrDA compressors'
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      dep_tristate '    Deflate compression (EXPERIMENTAL)' CONFIG_IRDA_DEFLATE $CONFIG_IRDA
+      dep_tristate '    Deflate compression (EXPERIMENTAL)' CONFIG_IRDA_DEFLATE $CONFIG_IRDA m
    fi
 #   tristate '    BZIP2 compression' CONFIG_IRDA_BZIP2
 #   tristate '    BSD compression' CONFIG_IRDA_BSD
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/socket.c linux.18p8/net/socket.c
--- linux.vanilla/net/socket.c	Fri Apr 21 12:47:17 2000
+++ linux.18p8/net/socket.c	Fri Sep  8 16:53:11 2000
@@ -597,7 +597,7 @@
 #endif
 
 	if (net_families[family]==NULL)
-		return -EINVAL;
+		return -EAFNOSUPPORT;
 
 /*
  *	Check that this is a type that we know how to manipulate and
@@ -1165,7 +1165,6 @@
 			/* Note - when this code becomes multithreaded on
 			 * SMP machines you have a race to fix here.
 			 */
-			err = -ENOBUFS;
 			ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
 			if (ctl_buf == NULL) 
 				goto out_freeiov;
